📄 generators.jam
字号:
# (probably after conversion by other generators)
rule viable-source-types-for-generator-real ( generator )
{
local source-types = [ $(generator).source-types ] ;
if ! $(source-types)
{
# If generator does not specify any source types,
# it might be special generator like builtin.lib-generator
# which just relays to other generators. Return '*' to
# indicate that any source type is possibly OK, since we don't
# know for sure.
return * ;
}
else
{
local result ;
for local s in $(source-types)
{
result += [ type.all-derived $(s) ]
[ generators.viable-source-types $(s) ] ;
}
result = [ sequence.unique $(result) ] ;
if * in $(result)
{
result = * ;
}
return $(result) ;
}
}
# Helper rule, caches the result of 'viable-source-types-for-genrator'.
local rule viable-source-types-for-generator ( generator )
{
local key = .vstg.$(generator) ;
if ! $($(key))
{
local v = [ viable-source-types-for-generator-real $(generator) ] ;
if ! $(v)
{
v = none ;
}
$(key) = $(v) ;
}
if $($(key)) != none
{
return $($(key)) ;
}
}
# Returns usage requirements + list of created targets
local rule try-one-generator-really ( project name ? : generator :
target-type : property-set : sources * )
{
local targets =
[ $(generator).run $(project) $(name)
: $(property-set)
: $(sources)
] ;
local usage-requirements ;
if $(targets) && [ class.is-a $(targets[1]) : property-set ]
{
usage-requirements = $(targets[1]) ;
targets = $(targets[2-]) ;
}
else
{
usage-requirements = [ property-set.empty ] ;
}
generators.dout [ indent ] " generator" [ $(generator).id ] " spawned " ;
generators.dout [ indent ] " " $(targets) ;
if $(targets)
{
return $(usage-requirements) $(targets) ;
}
}
# Checks if generator invocation can be pruned, because it's guaranteed
# to fail. If so, quickly returns empty list. Otherwise, calls
# try-one-generator-really.
local rule try-one-generator ( project name ? : generator :
target-type : property-set : sources * )
{
local source-types ;
for local s in $(sources)
{
source-types += [ $(s).type ] ;
}
local viable-source-types =
[ viable-source-types-for-generator $(generator) ] ;
if $(source-types) && $(viable-source-types) != * &&
! [ set.intersection $(source-types) : $(viable-source-types) ]
{
local id = [ $(generator).id ] ;
generators.dout [ indent ] "generator '$(id)' pruned" ;
#generators.dout [ indent ] "source-types" '$(source-types)' ;
#generators.dout [ indent ] "viable-source-types" '$(viable-source-types)' ;
}
else {
return [ try-one-generator-really $(project) $(name)
: $(generator)
: $(target-type) : $(property-set) : $(sources) ] ;
}
}
rule construct-types ( project name ? : target-types + :
property-set : sources + )
{
local result ;
local matched-types ;
local usage-requirements = [ property-set.empty ] ;
for local t in $(target-types)
{
local r = [ construct $(project) $(name) : $(t) : $(property-set) :
$(sources) ] ;
if $(r)
{
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
result += $(r[2-]) ;
matched-types += $(t) ;
}
}
# TODO: have to introduce parameter controlling if
# several types can be matches and add appropriate
# checks
# TODO: need to review the documentation for
# 'construct' to see if it should return $(source) even
# if nothing can be done with it. Currents docs seem to
# imply that, contrary to the behaviour.
if $(result)
{
return $(usage-requirements) $(result) ;
}
else
{
return $(usage-requirements) $(sources) ;
}
}
# Ensures all 'targets' have types. If this is not so, exists with
# error.
local rule ensure-type ( targets * )
{
for local t in $(targets)
{
if ! [ $(t).type ]
{
errors.error "target" [ $(t).str ] "has no type" ;
}
}
}
# Returns generators which can be used to construct target of specified type
# with specified properties. Uses the following algorithm:
# - iterates over requested target-type and all it's bases (in the order returned bt
# type.all-bases.
# - for each type find all generators that generate that type and which requirements
# are satisfied by properties.
# - if the set of generators is not empty, returns that set.
#
# Note: this algorithm explicitly ignores generators for base classes if there's
# at least one generator for requested target-type.
local rule find-viable-generators-aux ( target-type : property-set )
{
# Select generators that can create the required target type.
local viable-generators = ;
local generator-rank = ;
import type ;
local t = [ type.all-bases $(target-type) ] ;
generators.dout [ indent ] find-viable-generators target-type= $(target-type)
property-set= [ $(property-set).as-path ]
;
# Get the lit of generators for the requested type.
# If no generator is registered, try base type, and so on.
local generators ;
while $(t[1])
{
generators.dout [ indent ] "trying type" $(t[1]) ;
if $(.generators.$(t[1]))
{
generators.dout [ indent ] "there are generators for this type" ;
generators = $(.generators.$(t[1])) ;
if $(t[1]) != $(target-type)
{
# We're here, when no generators for target-type are found,
# but there are some generators for a base type.
# We'll try to use them, but they will produce targets of
# base type, not of 'target-type'. So, we clone the generators
# and modify the list of target types.
local generators2 ;
for local g in $(generators)
{
# generators.register adds generator to the list of generators
# for toolsets, which is a bit strange, but should work.
# That list is only used when inheriting toolset, which
# should have being done before generators are run.
generators2 += [
$(g).clone-and-change-target-type $(t[1]) : $(target-type) ] ;
generators.register $(generators2[-1]) ;
}
generators = $(generators2) ;
}
t = ;
}
t = $(t[2-]) ;
}
for local g in $(generators)
{
generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
local m = [ $(g).match-rank $(property-set) ] ;
if $(m)
{
generators.dout [ indent ] " is viable" ;
viable-generators += $(g) ;
}
}
return $(viable-generators) ;
}
local rule find-viable-generators ( target-type : property-set )
{
local key = $(target-type).$(property-set) ;
local l = $(.fv.$(key)) ;
if ! $(l)
{
l = [ find-viable-generators-aux $(target-type) : $(property-set) ] ;
if ! $(l)
{
l = none ;
}
.fv.$(key) = $(l) ;
}
if $(l) = none
{
l = ;
}
local viable-generators ;
for local g in $(l)
{
# Avoid trying the same generator twice on different levels.
if ! $(g) in $(.active-generators)
{
viable-generators += $(g) ;
}
}
# Generators which override 'all'.
local all-overrides ;
# Generators which are overriden
local overriden-ids ;
for local g in $(viable-generators)
{
local id = [ $(g).id ] ;
local this-overrides = $(.override.$(id)) ;
overriden-ids += $(this-overrides) ;
if all in $(this-overrides)
{
all-overrides += $(g) ;
}
}
if $(all-overrides)
{
viable-generators = $(all-overrides) ;
}
local result ;
for local g in $(viable-generators)
{
if ! [ $(g).id ] in $(overriden-ids)
{
result += $(g) ;
}
}
return $(result) ;
}
.construct-stack = ;
# Attempts to construct target by finding viable generators, running them
# and selecting the dependency graph
local rule construct-really (
project name ? : target-type : property-set : sources * )
{
viable-generators = [ find-viable-generators $(target-type) : $(property-set) ] ;
generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ]
" viable generators" ;
local result ;
for local g in $(viable-generators)
{
# This variable will be restored on exit from this scope.
local .active-generators = $(g) $(.active-generators) ;
local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type) :
$(property-set) : $(sources) ] ;
if $(r)
{
if $(result)
{
error "Ambiguity found when searching for best transformation" ;
}
else
{
result = $(r) ;
}
}
}
return $(result) ;
}
# Attempts to create target of 'target-type' with 'properties'
# from 'sources'. The 'sources' are treated as a collection of
# *possible* ingridients -- i.e. it is not required to consume
# them all. If 'multiple' is true, the rule is allowed to return
# several targets of 'target-type'.
#
#
# Returns a list of target. When this invocation is first instance of
# 'construct' in stack, returns only targets of requested 'target-type',
# otherwise, returns also unused sources and additionally generated
# targets.
#
# Does not return target which are not of 'allowed-type' or of type derived from
# it. If 'allowed-type' is not specified, it's defaulted to 'target-type'.
# See lib-target-class for use case of this.
rule construct ( project name ? : target-type : property-set * : sources *
: allowed-type * )
{
if (.construct-stack)
{
ensure-type $(sources) ;
}
.construct-stack += 1 ;
increase-indent ;
if $(.debug)
{
generators.dout [ indent ] "*** construct" $(target-type) ;
for local s in $(sources)
{
generators.dout [ indent ] " from" $(s) ;
}
generators.dout [ indent ] " properties:" [ $(property-set).raw ] ;
}
local result = [ construct-really $(project) $(name)
: $(target-type) : $(property-set) : $(sources) ] ;
decrease-indent ;
.construct-stack = $(.construct-stack[2-]) ;
return $(result) ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -