📄 generators.jam
字号:
generators.dout [ indent ] " FAILURE" ;
}
generators.dout ;
return $(result) ;
}
# Constructs the dependency graph that will be returned by this
# generator
rule construct-result (
consumed + # Already prepared list of consumable targets
# If generator requires several source files will contain
# exactly len $(self.source-types) targets with matching types
# Otherwise, might contain several targets with the type of
# $(self.source-types[1])
: project name ?
: property-set # Properties to be used for all actions create here
)
{
local result ;
# If this is 1->1 transformation, apply it to all consumed targets in order.
if ! $(self.source-types[2]) && ! $(self.composing)
{
generators.dout [ indent ] "alt1" ;
for local r in $(consumed)
{
result += [ generated-targets $(r) : $(property-set) : $(project) $(name) ] ; #(targets) ;
}
}
else
{
generators.dout [ indent ] "alt2 : consumed is" $(consumed) ;
if $(consumed)
{
result += [ generated-targets $(consumed) : $(property-set)
: $(project) $(name) ] ;
}
}
return $(result) ;
}
# Constructs targets that are created after consuming 'sources'.
# The result will be the list of virtual-target, which the same length
# as 'target-types' attribute and with corresponding types.
#
# When 'name' is empty, all source targets must have the same value of
# the 'name' attribute, which will be used instead of the 'name' argument.
#
# The value of 'name' attribute for each generated target will be equal to
# the 'name' parameter if there's no name pattern for this type. Otherwise,
# the '%' symbol in the name pattern will be replaced with the 'name' parameter
# to obtain the 'name' attribute.
#
# For example, if targets types are T1 and T2(with name pattern "%_x"), suffixes
# for T1 and T2 are .t1 and t2, and source if foo.z, then created files would
# be "foo.t1" and "foo_x.t2". The 'name' attribute actually determined the
# basename of a file.
#
# Note that this pattern mechanism has nothing to do with implicit patterns
# in make. It's a way to produce target which name is different for name of
# source.
rule generated-targets ( sources + : property-set : project name ? )
{
if ! $(name)
{
name = [ $(sources[1]).name ] ;
for local s in $(sources[2])
{
if [ $(s).name ] != $(name)
{
error "$(self.id): source targets have different names: cannot determine target name" ;
}
}
# Names of sources might include directory. We should strip it.
name = $(name:D=) ;
}
# Create generated target for each target type.
local targets ;
local pre = $(self.name-prefix) ;
local post = $(self.name-postfix) ;
for local t in $(self.target-types)
{
local generated-name = $(pre[1])$(name)$(post[1]) ;
pre = $(pre[2-]) ;
post = $(post[2-]) ;
targets += [ class.new file-target $(generated-name) : $(t) : $(project) ] ;
}
# Assign an action for each target
local action = [ action-class ] ;
local a = [ class.new $(action) $(targets) : $(sources) : $(self.id) :
$(property-set) ] ;
for local t in $(targets)
{
$(t).action $(a) ;
}
return [ sequence.transform virtual-target.register : $(targets) ] ;
}
# Attempts to convert 'source' to the types that this generator can
# handle. The intention is to produce the set of targets can should be
# used when generator is run.
rule convert-to-consumable-types ( project name ? :
property-set : sources + : multiple ?
: only-one ? # convert 'source' to only one of source types
# if there's more that one possibility, report an
# error
: consumed-var # name of variable which recieves all targets which
# can be consumed.
bypassed-var # name variable which recieves all targets which
# cannot be consumed
)
{
# We're likely to be passed 'consumed' and 'bypassed'
# var names. Use "_" to avoid name conflicts.
local _consumed ;
local _bypassed ;
local missing-types ;
if $(sources[2])
{
# Don't know how to handle several sources yet. Just try
# to pass the request to other generator
missing-types = $(self.source-types) ;
}
else
{
consume-directly $(sources) : _consumed : missing-types ;
}
# No need to search for transformation if
# some source type has consumed source and
# no more source types are needed.
if $(only-one) && $(_consumed)
{
missing-types = ;
}
#TODO: we should check that only one source type
#if create of 'only-one' is true.
# TODO: consider if consuned/bypassed separation should
# be done by 'construct-types'.
if $(missing-types)
{
local transformed = [ generators.construct-types $(project) $(name)
: $(missing-types) : $(multiple) : $(property-set) : $(sources) ] ;
# Add targets of right type to 'consumed'. Add others to
# 'bypassed'. The 'generators.construct' rule has done
# its best to convert everything to the required type.
# There's no need to rerun it on targets of different types.
for local t in $(transformed)
{
if [ $(t).type ] in $(missing-types)
{
_consumed += $(t) ;
}
else
{
_bypassed += $(t) ;
}
}
}
_consumed = [ sequence.unique $(_consumed) ] ;
_bypassed = [ sequence.unique $(_bypassed) ] ;
# remove elements of '_bypassed' that are in '_consumed'
# Suppose the target type of current generator, X is produced from
# X_1 and X_2, which are produced from Y by one generator.
# When creating X_1 from Y, X_2 will be added to 'bypassed'
# Likewise, when creating X_2 from Y, X_1 will be added to 'bypassed'
# But they are also in 'consumed'. We have to remove them from
# bypassed, so that generators up the call stack don't try to convert
# them.
# In this particular case, X_1 instance in 'consumed' and X_1 instance
# in 'bypassed' will be the same: because they have the same source and
# action name, and 'virtual-target.register' won't allow two different
# instances. Therefore, it's OK to use 'set.difference'.
_bypassed = [ set.difference $(_bypassed) : $(_consumed) ] ;
$(consumed-var) += $(_consumed) ;
$(bypassed-var) += $(_bypassed) ;
}
# Converts several files to consumable types.
rule convert-multiple-sources-to-consumable-types
( project : property-set : sources * : consumed-var bypassed-var : multiple ? )
{
multiple ?= * ;
# We process each source one-by-one, trying to convert it to
# a usable type.
local failed ;
while $(sources) && ! $(failed)
{
local _c ;
local _b ;
# TODO: need to check for failure on each source.
convert-to-consumable-types $(project) : $(property-set)
: $(sources[1]) : $(multiple) : true : _c _b ;
if ! $(_c)
{
generators.dout [ indent ] " failed to convert " [ $(sources[1]).str ] ;
# failed = true ;
}
$(consumed-var) += $(_c) ;
$(bypassed-var) += $(_b) ;
sources = $(sources[2-]) ;
}
if $(failed)
{
$(consumed-var) = ;
$(bypassed-var) = ;
}
}
rule consume-directly ( source : consumed-var : missing-types-var )
{
local real-source-type = [ $(source).type ] ;
for local st in $(self.source-types)
{
# The 'source' if of right type already)
if $(real-source-type) = $(st) ||
[ type.is-derived $(real-source-type) $(st) ]
{
$(consumed-var) += $(source) ;
}
else
{
$(missing-types-var) += $(st) ;
}
}
}
# Returns the class to be used to actions. Default implementation
# returns "action".
rule action-class ( )
{
return "action" ;
}
}
import errors : error ;
.generators = ;
# Registers new generator instance 'g'.
rule register ( g )
{
.generators += $(g) ;
for local t in [ $(g).target-types ]
{
.generators.$(t) += $(g) ;
}
# Update the set of generators for toolset
local id = [ $(g).id ] ;
# Some generators have multiple periods in their name, so the
# normal $(id:S=) won't generate the right toolset name.
# e.g. if id = gcc.compile.c++, then
# .generators-for-toolset.$(id:S=) will append to
# .generators-for-toolset.gcc.compile, which is a separate
# value from .generators-for-toolset.gcc. Correcting this
# makes generator inheritance work properly.
# See also inherit-generators in module toolset
local base = $(id) ;
while $(base:S)
{
base = $(base:B) ;
}
.generators-for-toolset.$(base) += $(g) ;
}
# Creates new instance of the 'generator' class and registers it.
# Retursn the creates instance.
# Rationale: the instance is returned so that it's possible to first register
# a generator and then call 'run' method on that generator, bypassing all
# generator selection.
rule register-standard ( id : source-types + : target-types + : requirements * )
{
local g = [ new generator $(id) : $(source-types) : $(target-types)
: $(requirements) ] ;
register $(g) ;
return $(g) ;
}
# Creates new instance of the 'composing-generator' class and
# registers it.
rule register-composing ( id : source-types + : target-types + : requirements * )
{
local g = [ new generator $(id) true : $(source-types)
: $(target-types) : $(requirements) ] ;
register $(g) ;
return $(g) ;
}
# Returns all generators which belong to 'toolset', i.e. which
# ids are $(toolset).<something>
rule generators-for-toolset ( toolset )
{
return $(.generators-for-toolset.$(toolset)) ;
}
# Set if results of the current generators search are going to be cached
# This means no futher attempts to cache generators search should be
# made.
.caching = ;
# For all t in 'targets':
# if [ $(t).type ] in $(target-types), add 't' to result
# if [ $(t).type ] in base type for any of 'target-types', add 't' to result
# otherwise, add 't' to extra.
rule base-to-derived-type-conversion ( targets * : target-types +
: result-var extra-var )
{
for local t in $(targets)
{
if [ $(t).type ] in $(target-types)
{
$(result-var) += $(t) ;
}
else
{
# We might have asked for a type 'D', but found only generator for
# a type 'B', where 'D' is derived from 'B'. In this case, the
# generation succeeds, but we should change type of the generated target.
local at = [ $(t).type ] ;
local found ;
for local tt in $(target-types)
{
if ! $(found) && [ type.is-derived $(tt) $(at) ]
{
$(t).set-type $(tt) ;
$(result-var) += $(t) ;
found = 1 ;
}
}
if ! $(found)
{
$(extra-var) += $(t) ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -