📄 targets.jam
字号:
# Returns the alternative condition for this alternative, if
# the condition is satisfied by 'property-set'.
rule match ( property-set )
{
local condition = [ $(self.requirements).base ] ;
# Weed out conditional properties.
condition = [ MATCH ^([^:]*)\$ : $(condition) ] ;
if $(condition) in [ $(property-set).raw ]
{
return $(condition) ;
}
else
{
return no-match ;
}
}
# Determine and return properties which should be used for
# building when given 'build-request'. This includes refining
# build request with requirements, evaluating conditionals,
# generating depenendecies and running actions for features.
local rule refined-properties ( build-request )
{
local erequirements = [ $(self.requirements).evaluate-conditionals
$(build-request) ] ;
erequirements = [ $(erequirements).expand-composites ] ;
local rproperties = [ $(build-request).refine $(erequirements) ] ;
if $(rproperties[1]) != "@error"
{
# TODO: issue a warning when requirements change properties, but
# link-compatibility is still not broken.
rproperties = [ $(rproperties).run-actions ] ;
}
return $(rproperties) ;
}
# Generate all sources for this target. Returns property-set with
# usage requirements, followed by the list of virtual targets.
local rule generate-sources ( property-set )
{
local usage-requirements = [ property-set.empty ] ;
local source-targets ;
for local s in $(self.sources)
{
# Try treating this source as reference to main target
local more-targets =
[ targets.generate-from-reference $(s) : $(self.project)
: $(property-set) ] ;
check-for-link-compatibility $(more-targets[2-]) : $(property-set) ;
usage-requirements = [ $(usage-requirements).add $(more-targets[1]) ] ;
source-targets += $(more-targets[2-]) ;
}
return $(usage-requirements) $(source-targets) ;
}
#
# Allows the user to tag the name of the target, according to properties.
#
rule tag-name ( name : property-set )
{
local properties = [ $(property-set).raw ] ;
local tagged-name = $(name) ;
if <tag> in $(properties:G)
{
local tags = [ $(property-set).get <tag> ] ;
for local tag in $(tags)
{
tagged-name = $(tagged-name)$(tag) ;
}
}
return $(tagged-name) ;
}
# Determines final build properties, generates sources,
# and calls 'construct'. This method should not be
# overridden.
rule generate ( property-set )
{
if ! $(self.generated.$(property-set))
{
local rproperties = [ refined-properties $(property-set) ] ;
if $(rproperties[1]) != "@error"
{
local usage-requirements = [ property-set.empty ] ;
rproperties =
[ targets.generate-dependencies $(rproperties) : $(self.project)
: $(rproperties) ] ;
usage-requirements = [ $(usage-requirements).add $(rproperties[1]) ] ;
rproperties = $(rproperties[2-]) ;
local deps = [ $(rproperties).dependency ] ;
check-for-link-compatibility $(deps:G=) : $(property-set) ;
local source-targets = [ generate-sources $(rproperties) ] ;
usage-requirements =
[ $(usage-requirements).add $(source-targets[1]) ] ;
source-targets = $(source-targets[2-]) ;
rproperties = [ $(rproperties).add $(usage-requirements) ] ;
local tagged-name = [ tag-name $(self.name) : $(rproperties) ] ;
local original-name = $(self.name) ;
self.name = $(tagged-name) ;
local result =
[ construct $(source-targets) : $(rproperties) ] ;
check-for-unused-sources
$(result) : $(source-targets) ;
local s = [ create-subvariant $(result) : $(property-set) : $(source-targets)
: $(rproperties) : $(usage-requirements) ] ;
local ur = [ compute-usage-requirements $(s) ] ;
$(s).set-usage-requirements $(ur) ;
self.generated.$(property-set) = $(ur) $(result) ;
self.name = $(original-name) ;
}
else
{
self.generated.$(property-set) = $(rproperties) ;
}
}
return $(self.generated.$(property-set)) ;
}
# Given the set of generated targets, and refined build
# properties, determines and sets appripriate usage requirements
# on those targets.
rule compute-usage-requirements ( subvariant )
{
local rproperties = [ $(subvariant).build-properties ] ;
xusage-requirements = [ $(self.usage-requirements).evaluate-conditionals
$(rproperties) ] ;
local xusage-requirements =
[ targets.generate-dependencies
$(xusage-requirements)
: $(self.project) : $(rproperties) ] ;
local recursive-usage-requirements = $(xusage-requirements[1]) ;
local result = [ $(recursive-usage-requirements).add $(xusage-requirements[2-]) ] ;
return $(result) ;
}
# Creates a new subvariant-dg instances for 'targets'
local rule create-subvariant ( targets * : build-request : sources * :
rproperties
: usage-requirements )
{
for local e in $(targets)
{
$(e).root true ;
}
# Process all vtargets that will be created if this main target
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(targets) ] ;
local s = [ new subvariant $(__name__) : $(build-request) : $(sources)
: $(rproperties) : $(usage-requirements) : $(all-targets) ] ;
for local v in $(all-targets)
{
if ! [ $(v).creating-subvariant ]
{
$(v).creating-subvariant $(s) ;
}
}
return $(s) ;
}
# Check that each source virtual target is either directly present in the
# result, or is in dependency graph of some returned virtual target.
# If this is not the case, issues a warning.
# Note that 'result' *can* be empty. For
# example, in this use case:
# alias platform-sources ;
# alias platform-sources : a.cpp : <os>NT ;
# result will be empty in the first case.
local rule check-for-unused-sources ( result * : sources * )
{
local used-sources ;
for local r in $(result)
{
used-sources += [ virtual-target.traverse $(r) : include-roots : 1 ] ;
}
local unused = [ set.difference $(sources) : $(used-sources) ] ;
if $(unused)
{
for local u in $(unused)
{
errors.warning "Unused source" [ $(u).str ] "in main target" [ full-name ] ;
}
}
}
# Checks if 'targets' are link-compatible with 'build-request' and
# issues a warning if that's not the case.
local rule check-for-link-compatibility ( targets * : build-request )
{
local checked ;
for local t in $(targets)
{
local a = [ $(t).action ] ;
if $(a)
{
local p = [ $(a).properties ] ;
if ! $(p) in $(cheched)
{
if [ $(p).link-incompatible-with $(build-request) ]
{
local s = [ $(t).creating-subvariant ] ;
local other-mt = [ $(s).main-target ] ;
ECHO "warning: targets produced from" [ $(other-mt).name ]
"are link incompatible" ;
ECHO "warning: with main target" [ name ] ;
}
}
checked += $(p) ;
}
}
}
# Constructs the virtual targets for this abstract targets and
# the dependecy graph. Returns the list of virtual targets.
# Should be overrided in derived classes.
rule construct ( source-targets * : properties * )
{
errors.error "method should be defined in derived classes" ;
}
}
class typed-target : basic-target
{
import generators ;
rule __init__ ( name : project : type
: sources * : requirements * : default-build * : usage-requirements * )
{
basic-target.__init__ $(name) : $(project)
: $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ;
self.type = $(type) ;
}
rule type ( )
{
return $(self.type) ;
}
rule construct ( source-targets * : property-set )
{
local r = [ generators.construct $(self.project) $(self.name) : $(self.type)
: [ property-set.create [ $(property-set).raw ] # [ feature.expand
<main-target-type>$(self.type) ]
# ]
: $(source-targets) ] ;
if ! $(r)
{
errors.error "unable to construct" [ full-name ] ;
}
return $(r) ;
}
}
# Return the list of sources to use, if main target rule is invoked
# with 'sources'. If there are any objects in 'sources', they are treated
# as main target instances, and WRITEME.
rule main-target-sources ( sources * : main-target-name )
{
local result ;
for local t in $(sources)
{
if [ class.is-instance $(t) ]
{
local name = [ $(t).name ] ;
# NOTE: on windows, this won't work if 'main-target-name'
# if single letter. But other alternatives are even worse.
local new-name = $(main-target-name)..$(name) ;
$(t).rename $(new-name) ;
#local p = [ $(t).project ] ;
#local pt = [ project.target $(p) ] ;
#$(pt).rename-main-target $(name) : $(new-name) ;
result += $(new-name) ;
}
else
{
result += $(t) ;
}
}
return $(result) ;
}
# Returns the requirement to use when declaring a main target,
# which are obtained by
# - translating all specified property paths, and
# - refining project requirements with the one specified for the target
rule main-target-requirements (
specification * # Properties explicitly specified for a main target
: project # Project where the main target is to be declared
)
{
local loc = [ project.attribute $(project) location ] ;
local requirements = [ property.translate-paths $(specification) : $(loc) ] ;
local requirements = [ property-set.create $(requirements) ] ;
local project-requirements = [ project.attribute $(project) requirements ] ;
requirements = [ $(project-requirements).refine $(requirements) ] ;
if $(requirements[1]) = "@error"
{
errors.error "Conflicting requirements for target:" $(requirements) ;
}
return $(requirements) ;
}
# Returns the use requirement to use when declaraing a main target,
# which are obtained by
# - translating all specified property paths, and
# - adding project's usage requirements
rule main-target-usage-requirements (
specification * # Use-properties explicitly specified for a main target
: project # Project where the main target is to be declared
)
{
local loc = [ project.attribute $(project) location ] ;
local project-usage-requirements = [ project.attribute $(project) usage-requirements ] ;
local usage-requirements = [ property-set.create
[ property.translate-paths $(specification) : $(loc) ] ] ;
return [ $(project-usage-requirements).add $(usage-requirements) ] ;
}
# Return the default build value to use when declaring a main target,
# which is obtained by using specified value if not empty and parent's
# default build attribute otherwise.
rule main-target-default-build (
specification * # Default build explicitly specified for a main target
: project # Project where the main target is to be declared
)
{
local result ;
if $(specification)
{
result = $(specification) ;
}
else
{
result = [ project.attribute $(project) default-build ] ;
}
return [ property-set.create-with-validation $(result) ] ;
}
# Registers the specified target as a main target alternatives.
# Returns 'target'.
rule main-target-alternative ( target )
{
local ptarget = [ project.target [ $(target).project ] ] ;
$(ptarget).add-alternative $(target) ;
return $(target) ;
}
# Creates a typed-target with the specified properties.
# The 'name', 'sources', 'requirements', 'default-build' and
# 'usage-requirements' are assumed to be in the form specified
# by the user in Jamfile corresponding to 'project'.
rule create-typed-target ( type : project :
name : sources * : requirements * : default-build *
: usage-requirements * )
{
return [
targets.main-target-alternative
[ new typed-target $(name) : $(project) : $(type)
: [ targets.main-target-sources $(sources) : $(name) ]
: [ targets.main-target-requirements $(requirements) : $(project) ]
: [ targets.main-target-default-build $(default-build) : $(project) ]
: [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ]
] ] ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -