📄 targets.jam
字号:
}
}
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
# to use here.
[ feature.compress-subproperties $(raw) ]
$(defaults-to-apply)
] ;
if $(properties)
{
for local p in $(properties)
{
result += [ property-set.create [ feature.split $(p) ] ] ;
}
}
else
{
result = [ property-set.empty ] ;
}
}
else
{
result = $(property-set) ;
}
return $(result) ;
}
# Select an alternative for this main target, by finding all alternatives
# which requirements are satisfied by 'properties' and picking the one with
# longest requirements set.
# Returns the result of calling 'generate' on that alternative.
rule generate ( property-set )
{
start-building $(__name__) ;
local all-property-sets = [ apply-default-build $(property-set) ] ;
local usage-requirements = [ property-set.empty ] ;
local result ;
for local p in $(all-property-sets)
{
p = [ $(p).expand-composites ] ;
p = [ $(p).add-defaults ] ;
local r = [ generate-really $(p) ] ;
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
result += $(r[2-]) ;
}
end-building $(__name__) ;
return $(usage-requirements) [ sequence.unique $(result) ] ;
}
# Generates the main target with the given property set
# and returns a list which first element is property-set object
# containing usage-requirements of generated target and with
# generated virtual target in other elements. It's possible
# that no targets are generated.
local rule generate-really ( property-set )
{
local best-alternatives = [ select-alternatives $(property-set) ] ;
if ! $(best-alternatives)
{
errors.error
"failed to build" [ full-name ]
"with properties" [ $(property-set).raw ]
"because no best-matching alternative could be found"
;
return [ property-set.empty ] ;
}
else
{
local result = [ $(best-alternatives).generate $(property-set) ] ;
# Now return virtual targets for the only alternative
return $(result) ;
}
}
rule rename ( new-name )
{
abstract-target.rename $(new-name) ;
for local a in $(self.alternatives)
{
$(a).rename $(new-name) ;
}
}
}
# Abstract target which refers to a source file.
# This is artificial creature; it's usefull so that sources to
# a target can be represented as list of abstract target instances.
class file-reference : abstract-target
{
import virtual-target ;
import property-set ;
import path ;
rule __init__ ( file : project )
{
abstract-target.__init__ $(file) : $(project) ;
}
rule generate ( properties )
{
return [ property-set.empty ]
[ virtual-target.from-file $(self.name) : $(self.project) ] ;
}
# Returns true if the referred file really exists;
rule exists ( )
{
local location = [ path.root $(self.name)
[ project.attribute $(self.project) source-location ] ] ;
return [ path.exists $(location) ] ;
}
}
# Helper for 'find', below.
local rule remove-trailing-slash ( string )
{
local stripped = [ MATCH (.*)/$ : $(string) ] ;
stripped ?= $(string) ;
return $(stripped) ;
}
if "--quiet" in [ modules.peek : ARGV ]
{
.quiet = true ;
}
rule find ( id : project )
{
local current-location = [ project.attribute $(project) location ] ;
local target ;
local split = [ MATCH (.*)//(.*) : $(id) ] ;
local project-part = $(split[1]) ;
local target-part = $(split[2]) ;
if ! $(split)
{
target-part = $(id) ;
}
# Make a more convenient name
local have-project-reference = $(split) ;
# The project used for finding main targets and for providing base directory
# for file paths.
local base-project ;
if $(project-part)
{
base-project = [ project.find $(project-part) : $(current-location) ] ;
}
else
{
# No project part in id. Resolve references relatively to the referring
# project.
base-project = $(project) ;
}
# Interpret target-part as project-id
if ! $(have-project-reference)
{
local project-module = [ project.find $(target-part) : $(current-location) ] ;
if $(project-module)
{
target = [ project.target $(project-module) ] ;
}
}
# Interpret target-name as name of main target
if ! $(target) && $(base-project)
{
local project-target = [ project.target $(base-project) ] ;
if [ $(project-target).has-main-target $(target-part) ]
{
target = [ $(project-target).main-target $(target-part) ] ;
}
}
if ! $(target) && ! $(have-project-reference)
{
target = [ new file-reference $(target-part) : $(project) ] ;
if ! [ $(target).exists ]
{
# File actually does not exist.
# Reset 'target' so that an error is issued.
target = ;
}
}
if ! $(target)
{
errors.error "Unable to resolve target-id $(id)" :
"Reference was made from project at '$(current-location)'" ;
}
return $(target) ;
}
# 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 =
[ find $(id) : $(project) ] ;
# Do a sanity check
if $(sproperties) && [ class.is-a $(target) : file-reference ]
{
errors.error
"error: target reference '$(target-reference)' contains properties," :
"error: but refers to a file" ;
}
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) ] ;
}
# Returns two property sets.
# The second one inclues all properties from
# 'property-set', except that all dependency properties are
# generated with 'generation-ps', and the obtained virtual targets
# are added as the values of original features.
# For example, <library>a/b might become <library>object(virtual-target)@1
#
# The first one include all usage requirements propagated from generated
# targets
rule generate-dependencies ( property-set : project : generation-ps )
{
local usage-requirements = [ property-set.empty ] ;
local xproperties ;
for local p in [ $(property-set).dependency ]
{
local g = [ targets.generate-from-reference $(p:TG=) : $(project) : $(generation-ps) ] ;
usage-requirements = [ $(usage-requirements).add $(g[1]) ] ;
xproperties += $(p:G)$(g[2-]) ;
}
local r = [ property-set.create
[ $(property-set).base ]
[ $(property-set).free ]
$(xproperties)
[ $(property-set).incidental ] ] ;
return $(usage-requirements) $(r) ;
}
# 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 virtual-target targets ;
import property-set ;
import set sequence errors ;
import "class" : new ;
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.error "gristed element in sources for" [ full-name ] ;
}
}
# Returns the list of abstract-targets which are used as sources.
# The extra properties specified for sources are not represented.
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) ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -