📄 targets.jam
字号:
local split = [ MATCH (.*)//(.*) : $(id) ] ;
local project-part = $(split[1]) ;
local target-part = $(split[2]) ;
local extra-error-message ;
if $(project-part)
{
# There's explicit project part in id. Looks up the
# project and pass the request to it.
local pm = [ project.find $(project-part) : $(current-location) ] ;
if $(pm)
{
project-target = [ project.target $(pm) ] ;
result = [ $(project-target).find $(target-part) : no-error ] ;
}
else
{
extra-error-message = "error: could not find project '$(project-part)'" ;
}
}
else
{
# Interpret as filename
result = [ new file-reference [ path.make $(id) ] : $(project) ] ;
if ! [ $(result).exists ]
{
# File actually does not exist.
# Reset 'target' so that an error is issued.
result = ;
}
# Interpret target-name as name of main target
if ! $(result)
{
result = [ main-target $(id) ] ;
}
# Interpret id as project-id
if ! $(result)
{
local project-module = [ project.find $(id) : $(current-location) ] ;
if $(project-module)
{
result = [ project.target $(project-module) ] ;
}
}
}
return $(result) ;
}
rule find ( id : no-error ? )
{
local v = $(.id.$(id)) ;
if ! $(v)
{
v = [ find-really $(id) ] ;
if ! $(v)
{
v = none ;
}
.id.$(id) = $(v) ;
}
if $(v) != none
{
return $(v) ;
}
else
{
if ! $(no-error)
{
local current-location = [ get location ] ;
ECHO "error: Unable to find file or target named" ;
ECHO "error: '$(id)'" ;
ECHO "error: referred from project at" ;
ECHO "error: '$(current-location)'" ;
ECHO $(extra-error-message) ;
EXIT ;
}
}
}
rule build-main-targets ( )
{
self.built-main-targets = true ;
for local a in $(self.alternatives)
{
local name = [ $(a).name ] ;
local target = $(self.main-target.$(name)) ;
if ! $(target)
{
local t = [ new main-target $(name) : $(self.project) ] ;
self.main-target.$(name) = $(t) ;
self.main-targets += $(t) ;
target = $(self.main-target.$(name)) ;
}
$(target).add-alternative $(a) ;
}
}
# Accessor, add a constant.
rule add-constant (
name # Variable name of the constant.
: value + # Value of the constant.
: type ? # Optional type of value.
)
{
switch $(type)
{
case path :
local r ;
for local v in $(value)
{
v = [ path.root [ path.make $(v) ] $(self.location) ] ;
# Now make the value absolute path
v = [ path.root $(v) [ path.pwd ] ] ;
# Constants should be in platform-native form
v = [ path.native $(v) ] ;
r += $(v) ;
}
value = $(r) ;
}
if ! $(name) in $(self.constants)
{
self.constants += $(name) ;
}
self.constant.$(name) = $(value) ;
# Inject the constant in the scope of project-root module
modules.poke $(self.project-module) : $(name) : $(value) ;
}
rule inherit ( parent )
{
for local c in [ modules.peek $(parent) : self.constants ]
{
# No need to pass the type. Path constants were converted to
# absolute paths already by parent.
add-constant $(c)
: [ modules.peek $(parent) : self.constant.$(c) ] ;
}
# Import rules from parent
local this-module = [ project-module ] ;
local parent-module = [ $(parent).project-module ] ;
# Don't import rules which comes from 'project-rules', they
# must be imported localized.
local user-rules = [ set.difference
[ RULENAMES $(parent-module) ] :
[ RULENAMES project-rules ] ] ;
IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules) ;
EXPORT $(this-module) : $(user-rules) ;
}
# Intern the constants from this project into the specified module.
#
rule intern-constants (
target-module # The module to intern into.
)
{
for local c in $(self.constants)
{
modules.poke $(target-module) : $(c) : $(self.constant.$(c)) ;
}
}
}
# Helper rules to detect cycles in main target references
local rule start-building ( main-target-instance )
{
if $(main-target-instance) in $(.targets-being-built)
{
local names ;
for local t in $(.targets-being-built) $(main-target-instance)
{
names += [ $(t).full-name ] ;
}
errors.error "Recursion in main target references"
: "the following target are being built currently:"
: $(names) ;
}
.targets-being-built += $(main-target-instance) ;
}
local rule end-building ( main-target-instance )
{
.targets-being-built = $(.targets-being-built[1--2]) ;
}
# A named top-level target in Jamfile
class main-target : abstract-target
{
import errors : error ;
import assert ;
import sequence ;
import print ;
import build-request feature property-set ;
import targets : start-building end-building ;
import "class" : is-a ;
rule __init__ ( name : project )
{
abstract-target.__init__ $(name) : $(project) ;
}
# Add a new alternative for this target
rule add-alternative ( target )
{
local d = [ $(target).default-build ] ;
if $(self.alternatives) && ( $(self.default-build) != $(d) )
{
errors.error "default build must be identical in all alternatives"
: "main target is" [ full-name ]
: "with" [ $(d).raw ]
: "differing from previous default build" [ $(self.default-build).raw ] ;
}
else
{
self.default-build = $(d) ;
}
self.alternatives += $(target) ;
}
# Returns the best viable alternative for this property-set
# See the documentation for selection rules.
local rule select-alternatives ( property-set )
{
# When selecting alternatives we have to consider defaults,
# for example:
# lib l : l.cpp : <variant>debug ;
# lib l : l_opt.cpp : <variant>release ;
# won't work unless we add default value <variant>debug.
property-set = [ $(p).add-defaults ] ;
# The algorithm: we keep the current best viable alternative.
# When we've got new best viable alternative, we compare it
# with the current one.
local best ;
local best-properties ;
if $(self.alternatives[2-])
{
local bad ;
local worklist = $(self.alternatives) ;
while $(worklist) && ! $(bad)
{
local v = $(worklist[1]) ;
local properties = [ $(v).match $(property-set) ] ;
if $(properties) != no-match
{
if ! $(best)
{
best = $(v) ;
best-properties = $(properties) ;
}
else
{
if $(properties) = $(best-properties)
{
bad = true ;
}
else if $(properties) in $(best-properties)
{
# Do nothing, this alternative is worse
}
else if $(best-properties) in $(properties)
{
best = $(v) ;
best-properties = $(properties) ;
}
else
{
bad = true ;
}
}
}
worklist = $(worklist[2-]) ;
}
if ! $(bad)
{
return $(best) ;
}
}
else
{
return $(self.alternatives) ;
}
}
rule apply-default-build ( property-set )
{
# 1. First, see what properties from default-build
# are already present in property-set.
local raw = [ $(property-set).raw ] ;
local specified-features = $(raw:G) ;
local defaults-to-apply ;
for local d in [ $(self.default-build).raw ]
{
if ! $(d:G) in $(specified-features)
{
defaults-to-apply += $(d) ;
}
}
# 2. If there's any defaults to be applied, form the new
# build request. Pass it throw 'expand-no-defaults', since
# default-build might contain "release debug", which will
# result in two property-sets.
local result ;
if $(defaults-to-apply)
{
properties = [
build-request.expand-no-defaults
# We have to compress subproperties here to prevent
# property lists like:
#
# <toolset>msvc <toolset-msvc:version>7.1 <threading>multi
#
# from being expanded into:
#
# <toolset-msvc:version>7.1/<threading>multi
# <toolset>msvc/<toolset-msvc:version>7.1/<threading>multi
#
# due to cross-product property combination. That may
# be an indication that
# build-request.expand-no-defaults is the wrong rule
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -