📄 targets.jam
字号:
rule __init__ ( file : project ) { abstract-target.__init__ $(file) : $(project) ; } rule generate ( properties ) { return [ property-set.empty ] [ virtual-target.from-file $(self.name) : [ location ] : $(self.project) ] ; } # Returns true if the referred file really exists. rule exists ( ) { location ; return $(self.file-path) ; } # Returns the location of target. Needed by 'testing.jam'. rule location ( ) { if ! $(self.file-location) { local source-location = [ $(self.project).get source-location ] ; for local src-dir in $(source-location) { if ! $(self.file-location) { local location = [ path.root $(self.name) $(src-dir) ] ; if [ CHECK_IF_FILE [ path.native $(location) ] ] { self.file-location = $(src-dir) ; self.file-path = $(location) ; } } } } return $(self.file-location) ; }}# Given a target-reference, made in context of 'project', returns the# abstract-target instance that is referred to, as well as properties explicitly# specified for this reference.#rule resolve-reference ( target-reference : project ){ # Separate target name from properties override. local split = [ MATCH "^([^<]*)(/(<.*))?$" : $(target-reference) ] ; local id = $(split[1]) ; local sproperties = ; if $(split[3]) { sproperties = [ property.make [ feature.split $(split[3]) ] ] ; sproperties = [ feature.expand-composites $(sproperties) ] ; } # Find the target. local target = [ $(project).find $(id) ] ; return $(target) [ property-set.create $(sproperties) ] ;}# Attempts to generate the target given by target reference, which can refer# both to a main target or to a file. Returns a list consisting of# - usage requirements# - generated virtual targets, if any#rule generate-from-reference ( target-reference # Target reference. : project # Project where the reference is made. : property-set # Properties of the main target that makes the reference.){ local r = [ resolve-reference $(target-reference) : $(project) ] ; local target = $(r[1]) ; local sproperties = $(r[2]) ; # Take properties which should be propagated and refine them with # source-specific requirements. local propagated = [ $(property-set).propagated ] ; local rproperties = [ $(propagated).refine $(sproperties) ] ; if $(rproperties[1]) = "@error" { errors.error "When building" [ full-name ] " with properties " $(properties) : "Invalid properties specified for " $(source) ":" $(rproperties[2-]) ; } return [ $(target).generate $(rproperties) ] ;}# Given a build request and requirements, return properties common to dependency# build request and target requirements.## TODO: Document exactly what 'common properties' are, whether they should# include default property values, whether they should contain any conditional# properties or should those be already processed, etc. See whether there are# any differences between use cases with empty and non-empty build-request as# well as with requirements containing and those not containing any non-free# features.#rule common-properties ( build-request requirements ){ # For optimization, we add free requirements directly, without using a # complex algorithm. This gives the complex algorithm a better chance of # caching results. local free = [ $(requirements).free ] ; local non-free = [ property-set.create [ $(requirements).base ] [ $(requirements).incidental ] ] ; local key = .rp.$(build-request)-$(non-free) ; if ! $($(key)) { $(key) = [ common-properties2 $(build-request) $(non-free) ] ; } result = [ $($(key)).add-raw $(free) ] ;}# Given a 'context' -- a set of already present properties, and 'requirements',# decide which extra properties should be applied to 'context'. For conditional# requirements, this means evaluating the condition. For indirect conditional# requirements, this means calling a rule. Ordinary requirements are always# applied.## Handles the situation where evaluating one conditional requirement affects# conditions of another conditional requirements, such as:# <toolset>gcc:<variant>release <variant>release:<define>RELEASE## If 'what' is 'refined' returns context refined with new requirements. If# 'what' is 'added' returns just the requirements to be applied.#rule evaluate-requirements ( requirements : context : what ){ # Apply non-conditional requirements. It is possible that further # conditional requirement change a value set by non-conditional # requirements. For example: # # exe a : a.cpp : <threading>single <toolset>foo:<threading>multi ; # # I am not sure if this should be an error, or not, especially given that # # <threading>single # # might come from project's requirements. local unconditional = [ feature.expand [ $(requirements).non-conditional ] ] ; local raw = [ $(context).raw ] ; raw = [ property.refine $(raw) : $(unconditional) ] ; # We have collected properties that surely must be present in common # properties. We now try to figure out what other properties should be added # in order to satisfy rules (4)-(6) from the docs. local conditionals = [ $(requirements).conditional ] ; # The 'count' variable has one element for each conditional feature and for # each occurrence of '<indirect-conditional>' feature. It is used as a loop # counter: for each iteration of the loop before we remove one element and # the property set should stabilize before we are done. It is assumed that # #conditionals iterations should be enough for properties to propagate # along conditions in any direction. local count = $(conditionals) [ $(requirements).get <conditional> ] and-once-more ; local added-requirements ; local current = $(raw) ; # It is assumed that ordinary conditional requirements can not add # <conditional> properties (a.k.a. indirect conditional properties), and # that rules referred to by <conditional> properties can not add new # <conditional> properties. So the list of indirect conditionals does not # change. local indirect = [ $(requirements).get <conditional> ] ; indirect = [ MATCH @(.*) : $(indirect) ] ; local ok ; while $(count) { # Evaluate conditionals in context of current properties. local e = [ property.evaluate-conditionals-in-context $(conditionals) : $(current) ] ; # Evaluate indirect conditionals. for local i in $(indirect) { e += [ indirect.call $(i) $(current) ] ; } if $(e) = $(added-requirements) { # If we got the same result, we have found the final properties. count = ; ok = true ; } else { # Oops, conditional evaluation results have changed. Also 'current' # contains leftovers from a previous evaluation. Recompute 'current' # using initial properties and conditional requirements. added-requirements = $(e) ; current = [ property.refine $(raw) : [ feature.expand $(e) ] ] ; } count = $(count[2-]) ; } if ! $(ok) { errors.error "Can not evaluate conditional properties " $(conditionals) ; } if $(what) = added { return [ property-set.create $(unconditional) $(added-requirements) ] ; } else if $(what) = refined { return [ property-set.create $(current) ] ; } else { errors.error "Invalid value of the 'what' parameter." ; }}rule common-properties2 ( build-request requirements ){ # This guarantees that default properties are present in the result, unless # they are overriden by some requirement. FIXME: There is possibility that # we have added <foo>bar, which is composite and expands to <foo2>bar2, but # default value of <foo2> is not bar2, in which case it is not clear what to # do. # build-request = [ $(build-request).add-defaults ] ; # Features added by 'add-default' can be composite and expand to features # without default values -- so they are not added yet. It could be clearer/ # /faster to expand only newly added properties but that is not critical. build-request = [ $(build-request).expand ] ; return [ evaluate-requirements $(requirements) : $(build-request) : refined ] ;}# Implements the most standard way of constructing main target alternative from# sources. Allows sources to be either file or other main target and handles# generation of those dependency targets.#class basic-target : abstract-target{ import build-request ; import build-system ; import "class" : new ; import errors ; import feature ; import property ; import property-set ; import sequence ; import set ; import targets ; import virtual-target ; rule __init__ ( name : project : sources * : requirements * : default-build * : usage-requirements * ) { abstract-target.__init__ $(name) : $(project) ; self.sources = $(sources) ; if ! $(requirements) { requirements = [ property-set.empty ] ; } self.requirements = $(requirements) ; if ! $(default-build) { default-build = [ property-set.empty ] ; } self.default-build = $(default-build) ; if ! $(usage-requirements) { usage-requirements = [ property-set.empty ] ; } self.usage-requirements = $(usage-requirements) ; if $(sources:G) { errors.user-error properties found in the 'sources' parameter for [ full-name ] ; } } # Returns the list of abstract-targets which are used as sources. The extra # properties specified for sources are not represented. The only user for # this rule at the moment is the "--dump-tests" feature of the test system. # rule sources ( ) { if ! $(self.source-targets) { for local s in $(self.sources) { self.source-targets += [ targets.resolve-reference $(s) : $(self.project) ] ; } } return $(self.source-targets) ; } rule requirements ( ) { return $(self.requirements) ; } rule default-build ( ) { return $(self.default-build) ; } # Returns the alternative condition for this alternative, if the condition # is satisfied by 'property-set'. # rule match ( property-set debug ? ) { # The condition is composed of all base non-conditional properties. It # is not clear if we should expand 'self.requirements' or not. For one # thing, it would be nice to be able to put # <toolset>msvc-6.0 # in requirements. On the other hand, if we have <variant>release as a # condition it does not make sense to require <optimization>full to be # in the build request just to select this variant. local bcondition = [ $(self.requirements).base ] ; local ccondition = [ $(self.requirements).conditional ] ; local condition = [ set.difference $(bcondition) : $(ccondition) ] ; if $(debug) { ECHO " next alternative: required properties:" $(condition:E=(empty)) ; } if $(condition) in [ $(property-set).raw ] { if $(debug) { ECHO " matched" ; } return $(condition) ; } else { if $(debug) { ECHO " not matched" ; } return no-match ; } } # Takes a target reference, which might be either target id or a dependency # property, and generates that target using 'property-set' as build request. # # The results are added to the variable called 'result-var'. Usage # requirements are added to the variable called 'usage-requirements-var'. # rule generate-dependencies ( dependencies * : property-set : result-var usage-requirements-var ) { for local dependency in $(dependencies) { local grist = $(dependency:G) ; local id = $(dependency:G=) ; local result = [ targets.generate-from-reference $(id) : $(self.project) : $(property-set) ] ; $(result-var) += $(result[2-]:G=$(grist)) ; $(usage-requirements-var) += [ $(result[1]).raw ] ; } } # Determines final build properties, generates sources, and calls # 'construct'. This method should not be overridden. # rule generate ( property-set ) { if [ modules.peek : .debug-building ] { ECHO ; local fn = [ full-name ] ; ECHO [ targets.indent ] "Building target '$(fn)'" ; targets.increase-indent ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -