📄 generators.jam
字号:
# 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)
{
# Determine the name of the produced target from the
# names of the sources. The simple case if when a name
# of source has single dot. Then, we take the part before
# dot. Several dots can be caused by:
# - Using source file like a.host.cpp
# - A type which suffix has a dot. Say, we can
# type 'host_cpp' with extension 'host.cpp'.
# In the first case, we want to take the part till the last
# dot. In the second case -- no sure, but for now take
# the part till the last dot too.
name = [ utility.basename [ $(sources[1]).name ] ] ;
for local s in $(sources[2])
{
local n2 = [ utility.basename [ $(s).name ] ] ;
if $(n2) != $(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=) ;
}
# Assign an action for each target
local action = [ action-class ] ;
local a = [ class.new $(action) $(sources) : $(self.id) :
$(property-set) ] ;
# 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) : $(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 +
: 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) : $(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.
# NOTE: ignoring usage requirements
for local t in $(transformed[2-])
{
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 )
{
# 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]) : true : _c _b ;
if ! $(_c)
{
generators.dout [ indent ] " failed to convert " $(sources[1]) ;
# 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 ] ;
# If there are no source types, we can consume anything
local source-types = $(self.source-types) ;
source-types ?= $(real-source-type) ;
for local st in $(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
# TODO: should we check that generator with this id
# is not already registered. For example, the fop.jam
# module intentionally declared two generators with the
# same id, so such check will break it.
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)) ;
}
rule override ( overrider-id : overridee-id )
{
.override.$(overrider-id) += $(overridee-id) ;
}
# 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 = ;
# Returns a list of source type which can possibly be converted
# to 'target-type' by some chain of generator invocation.
#
# More formally, takes all generators for 'target-type' and
# returns union of source types for those generators and result
# of calling itself recusrively on source types.
local rule viable-source-types-real ( target-type )
{
local generators ;
local t = [ type.all-bases $(target-type) ] ;
local result ;
# 't' is the list of types which are not yet processed
while $(t)
{
# Find all generators for current type.
# Unlike 'find-viable-generators' we don't care about property-set.
local generators = $(.generators.$(t[1])) ;
t = $(t[2-]) ;
while $(generators)
{
local g = $(generators[1]) ;
generators = $(generators[2-]) ;
if ! [ $(g).source-types ]
{
# Empty source types -- everything can be accepted
result = * ;
# This will terminate this loop.
generators = ;
# This will terminate outer loop.
t = ;
}
for local source-type in [ $(g).source-types ]
{
if ! $(source-type) in $(result)
{
# If generator accepts 'source-type' it
# will happily accept any type derived from it
local all = [ type.all-derived $(source-type) ] ;
for local n in $(all)
{
if ! $(n) in $(result)
{
t += $(n) ;
result += $(n) ;
}
}
}
}
}
}
result = [ sequence.unique $(result) ] ;
return $(result) ;
}
# Helper rule, caches the result of 'viable-source-types-real'.
rule viable-source-types ( target-type )
{
local key = .vst.$(target-type) ;
if ! $($(key))
{
local v = [ viable-source-types-real $(target-type) ] ;
if ! $(v)
{
v = none ;
}
$(key) = $(v) ;
}
if $($(key)) != none
{
return $($(key)) ;
}
}
# Returns the list of source types, which, when passed to 'run'
# method of 'generator', has some change of being eventually used
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -