📄 generators.jam
字号:
# 'generator', has some change of being eventually used (probably after# conversion by other generators).## Returns '*' in case any type should be considered a viable source type for the# given generator.#rule viable-source-types-for-generator-real ( generator ){ local source-types = [ $(generator).source-types ] ; if ! $(source-types) { # If generator does not specify any source types, it might be a special # generator like builtin.lib-generator which just relays to other # generators. Return '*' to indicate that any source type is possibly # OK, since we do not know for sure. return * ; } else { local result ; for local s in $(source-types) { local viable-sources = [ generators.viable-source-types $(s) ] ; if $(viable-sources) = * { result = * ; source-types = ; # Terminate the loop. } else { result += [ type.all-derived $(s) ] $(viable-sources) ; } } return [ sequence.unique $(result) ] ; }}# Helper rule, caches the result of 'viable-source-types-for-generator'.#local rule viable-source-types-for-generator ( generator ){ local key = .vstg.$(generator) ; if ! $($(key)) { .vstg-cached-generators += $(generator) ; local v = [ viable-source-types-for-generator-real $(generator) ] ; if ! $(v) { v = none ; } $(key) = $(v) ; } if $($(key)) != none { return $($(key)) ; }}# Returns usage requirements + list of created targets.#local rule try-one-generator-really ( project name ? : generator : target-type : property-set : sources * ){ local targets = [ $(generator).run $(project) $(name) : $(property-set) : $(sources) ] ; local usage-requirements ; local success ; generators.dout [ indent ] returned $(targets) ; if $(targets) { success = true ; if [ class.is-a $(targets[1]) : property-set ] { usage-requirements = $(targets[1]) ; targets = $(targets[2-]) ; } else { usage-requirements = [ property-set.empty ] ; } } generators.dout [ indent ] " generator" [ $(generator).id ] " spawned " ; generators.dout [ indent ] " " $(targets) ; if $(usage-requirements) { generators.dout [ indent ] " with usage requirements:" $(x) ; } if $(success) { return $(usage-requirements) $(targets) ; }}# Checks if generator invocation can be pruned, because it is guaranteed to# fail. If so, quickly returns an empty list. Otherwise, calls# try-one-generator-really.#local rule try-one-generator ( project name ? : generator : target-type : property-set : sources * ){ local source-types ; for local s in $(sources) { source-types += [ $(s).type ] ; } local viable-source-types = [ viable-source-types-for-generator $(generator) ] ; if $(source-types) && $(viable-source-types) != * && ! [ set.intersection $(source-types) : $(viable-source-types) ] { local id = [ $(generator).id ] ; generators.dout [ indent ] " ** generator '$(id)' pruned" ; #generators.dout [ indent ] "source-types" '$(source-types)' ; #generators.dout [ indent ] "viable-source-types" '$(viable-source-types)' ; } else { return [ try-one-generator-really $(project) $(name) : $(generator) : $(target-type) : $(property-set) : $(sources) ] ; }}rule construct-types ( project name ? : target-types + : property-set : sources + ){ local result ; local matched-types ; local usage-requirements = [ property-set.empty ] ; for local t in $(target-types) { local r = [ construct $(project) $(name) : $(t) : $(property-set) : $(sources) ] ; if $(r) { usage-requirements = [ $(usage-requirements).add $(r[1]) ] ; result += $(r[2-]) ; matched-types += $(t) ; } } # TODO: have to introduce parameter controlling if several types can be # matched and add appropriate checks. # TODO: need to review the documentation for 'construct' to see if it should # return $(source) even if nothing can be done with it. Currents docs seem # to imply that, contrary to the behaviour. if $(result) { return $(usage-requirements) $(result) ; } else { return $(usage-requirements) $(sources) ; }}# Ensures all 'targets' have their type. If this is not so, exists with error.#local rule ensure-type ( targets * ){ for local t in $(targets) { if ! [ $(t).type ] { errors.error "target" [ $(t).str ] "has no type" ; } }}# Returns generators which can be used to construct target of specified type# with specified properties. Uses the following algorithm:# - iterates over requested target-type and all its bases (in the order returned# by type.all-bases).# - for each type find all generators that generate that type and whose# requirements are satisfied by properties.# - if the set of generators is not empty, returns that set.## Note: this algorithm explicitly ignores generators for base classes if there# is at least one generator for the requested target-type.#local rule find-viable-generators-aux ( target-type : property-set ){ # Select generators that can create the required target type. local viable-generators = ; local generator-rank = ; import type ; local t = [ type.all-bases $(target-type) ] ; generators.dout [ indent ] find-viable-generators target-type= $(target-type) property-set= [ $(property-set).as-path ] ; # Get the list of generators for the requested type. If no generator is # registered, try base type, and so on. local generators ; while $(t[1]) { generators.dout [ indent ] "trying type" $(t[1]) ; if $(.generators.$(t[1])) { generators.dout [ indent ] "there are generators for this type" ; generators = $(.generators.$(t[1])) ; if $(t[1]) != $(target-type) { # We are here because there were no generators found for # target-type but there are some generators for its base type. # We will try to use them, but they will produce targets of # base type, not of 'target-type'. So, we clone the generators # and modify the list of target types. local generators2 ; for local g in $(generators) { # generators.register adds a generator to the list of # generators for toolsets, which is a bit strange, but # should work. That list is only used when inheriting a # toolset, which should have been done before running # generators. generators2 += [ $(g).clone-and-change-target-type $(t[1]) : $(target-type) ] ; generators.register $(generators2[-1]) ; } generators = $(generators2) ; } t = ; } t = $(t[2-]) ; } for local g in $(generators) { generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ; local m = [ $(g).match-rank $(property-set) ] ; if $(m) { generators.dout [ indent ] " is viable" ; viable-generators += $(g) ; } } return $(viable-generators) ;}rule find-viable-generators ( target-type : property-set ){ local key = $(target-type).$(property-set) ; local l = $(.fv.$(key)) ; if ! $(l) { l = [ find-viable-generators-aux $(target-type) : $(property-set) ] ; if ! $(l) { l = none ; } .fv.$(key) = $(l) ; } if $(l) = none { l = ; } local viable-generators ; for local g in $(l) { # Avoid trying the same generator twice on different levels. if ! $(g) in $(.active-generators) { viable-generators += $(g) ; } } # Generators which override 'all'. local all-overrides ; # Generators which are overriden. local overriden-ids ; for local g in $(viable-generators) { local id = [ $(g).id ] ; local this-overrides = $(.override.$(id)) ; overriden-ids += $(this-overrides) ; if all in $(this-overrides) { all-overrides += $(g) ; } } if $(all-overrides) { viable-generators = $(all-overrides) ; } local result ; for local g in $(viable-generators) { if ! [ $(g).id ] in $(overriden-ids) { result += $(g) ; } } return $(result) ;}.construct-stack = ;# Attempts to construct a target by finding viable generators, running them and# selecting the dependency graph.#local rule construct-really ( project name ? : target-type : property-set : sources * ){ viable-generators = [ find-viable-generators $(target-type) : $(property-set) ] ; generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ] " viable generators" ; local result ; local generators-that-succeeded ; for local g in $(viable-generators) { # This variable will be restored on exit from this scope. local .active-generators = $(g) $(.active-generators) ; local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type) : $(property-set) : $(sources) ] ; if $(r) { generators-that-succeeded += $(g) ; if $(result) { ECHO "Error: ambiguity found when searching for best transformation" ; ECHO "Trying to produce type '$(target-type)' from: " ; for local s in $(sources) { ECHO " - " [ $(s).str ] ; } ECHO "Generators that succeeded:" ; for local g in $(generators-that-succeeded) { ECHO " - " [ $(g).id ] ; } ECHO "First generator produced: " ; for local t in $(result[2-]) { ECHO " - " [ $(t).str ] ; } ECHO "Second generator produced: " ; for local t in $(r[2-]) { ECHO " - " [ $(t).str ] ; } EXIT ; } else { result = $(r) ; } } } return $(result) ;}# Attempts to create a target of 'target-type' with 'properties' from 'sources'.# The 'sources' are treated as a collection of *possible* ingridients, i.e.# there is no obligation to consume them all.## Returns a list of targets. When this invocation is first instance of# 'construct' in stack, returns only targets of requested 'target-type',# otherwise, returns also unused sources and additionally generated targets.#rule construct ( project name ? : target-type : property-set * : sources * ){ if (.construct-stack) { ensure-type $(sources) ; } .construct-stack += 1 ; increase-indent ; if $(.debug) { generators.dout [ indent ] "*** construct" $(target-type) ; for local s in $(sources) { generators.dout [ indent ] " from" $(s) ; } generators.dout [ indent ] " properties:" [ $(property-set).raw ] ; } local result = [ construct-really $(project) $(name) : $(target-type) : $(property-set) : $(sources) ] ; decrease-indent ; .construct-stack = $(.construct-stack[2-]) ; return $(result) ;}# Given 'result', obtained from some generator or generators.construct, adds# 'raw-properties' as usage requirements to it. If result already contains usage# requirements -- that is the first element of result of an instance of the# property-set class, the existing usage requirements and 'raw-properties' are# combined.#rule add-usage-requirements ( result * : raw-properties * ){ if $(result) { if [ class.is-a $(result[1]) : property-set ] { return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ; } else { return [ property-set.create $(raw-properties) ] $(result) ; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -