mirror of
https://github.com/boostorg/build.git
synced 2026-02-14 12:42:11 +00:00
More generators docs and minor refactoring.
[SVN r17117]
This commit is contained in:
@@ -6,6 +6,39 @@
|
||||
# Manages 'generators' --- objects which can do transformation between different
|
||||
# target types and contain algorithm for finding transformation from sources
|
||||
# to targets.
|
||||
#
|
||||
# The main entry point to this module is generators.construct rule. It is given
|
||||
# a list of source targets, desired target type and a set of properties.
|
||||
# It starts by selecting 'viable generators', which have any chances of producing
|
||||
# the desired target type with the required properties. Generators are ranked and
|
||||
# a set of most specific ones is selected.
|
||||
#
|
||||
# The most specific generators have their 'run' methods called, with the properties
|
||||
# and list of sources. Each one selects target which can be directly consumed, and
|
||||
# tries to convert the remaining ones to the types it can consume. This is done
|
||||
# by recursively calling 'construct' with all consumable types.
|
||||
#
|
||||
# If the generator has collected all the targets it needs, it creates targets
|
||||
# corresponding to result, and returns it. When all generators have been run,
|
||||
# results of one of them are selected and returned as result.
|
||||
#
|
||||
# It's quite possible that 'construct' returns more targets that it was asked for.
|
||||
# For example, it was asked to target type EXE, but the only found generators produces
|
||||
# both EXE and TDS (file with debug) information. The extra target will be returned.
|
||||
#
|
||||
# Likewise, when generator tries to convert sources to consumable types, it can get
|
||||
# more targets that it was asked for. The question is what to do with extra targets.
|
||||
# Boost.Build attempts to convert them to requested types, and attempts as early as
|
||||
# possible. Specifically, this is done after invoking each generator. (Later I'll
|
||||
# document the rationale for trying extra target conversion at that point).
|
||||
#
|
||||
# That early conversion is not always desirable. Suppose a generator got a source of
|
||||
# type Y and must consume one target of type X_1 and one target of type X_2.
|
||||
# When converting Y to X_1 extra target of type Y_2 is created. We should not try to
|
||||
# convert it to type X_1, because if we do so, the generator will get two targets
|
||||
# of type X_1, and will be at loss as to which one to use. Because of that, the
|
||||
# 'construct' rule has a parameter, telling if multiple targets can be returned. If
|
||||
# the parameter is false, conversion of extra targets is not performed.
|
||||
|
||||
import class : class new is-a ;
|
||||
import container : vector ;
|
||||
@@ -129,6 +162,36 @@ rule generator (
|
||||
return $(self.optional-properties) ;
|
||||
}
|
||||
|
||||
# Returns a number telling how good generator's properties match
|
||||
# the passed properties, or empty list if generator can't be run
|
||||
# at all.
|
||||
rule match-rank ( properties * )
|
||||
{
|
||||
# See if generator's requirements are satisfied by 'properties'.
|
||||
# Treat feature name in requirements (i.e. grist-only element),
|
||||
# as matching any value of feature.
|
||||
local raw = [ requirements ] ;
|
||||
local requirements ;
|
||||
local features ;
|
||||
for local r in $(raw)
|
||||
{
|
||||
if $(r:G=)
|
||||
{
|
||||
requirements += $(r) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
features += $(r) ;
|
||||
}
|
||||
}
|
||||
|
||||
if $(requirements) in $(properties) && $(features) in $(properties:G)
|
||||
{
|
||||
return [ sequence.length [ set.intersection
|
||||
[ optional-properties ] : $(properties) ] ] ;
|
||||
}
|
||||
}
|
||||
|
||||
# Returns another generator which differers from $(self) in
|
||||
# - id
|
||||
# - value to <toolset> feature in properties
|
||||
@@ -667,31 +730,13 @@ local rule find-viable-generators ( target-type : properties * : allow-composing
|
||||
if ! $(g) in $(.active-generators)
|
||||
&& ! ( [ is-a $(g) : composing-generator ] && ! $(allow-composing) )
|
||||
{
|
||||
# See if generator's requirements are satisfied by 'properties'.
|
||||
# Treat feature name in requirements (i.e. grist-only element),
|
||||
# as matching any value of feature.
|
||||
local raw = [ $(g).requirements ] ;
|
||||
local requirements ;
|
||||
local features ;
|
||||
for local r in $(raw)
|
||||
{
|
||||
if $(r:G=)
|
||||
{
|
||||
requirements += $(r) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
features += $(r) ;
|
||||
}
|
||||
}
|
||||
|
||||
if $(requirements) in $(properties) && $(features) in $(properties:G)
|
||||
local m = [ $(g).match-rank $(properties) ] ;
|
||||
if $(m)
|
||||
{
|
||||
viable-generators += $(g) ;
|
||||
generator-rank += [ sequence.length [ set.intersection
|
||||
[ $(g).optional-properties ] : $(properties) ] ] ;
|
||||
generator-rank += $(m) ;
|
||||
t = ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t = $(t[2-]) ;
|
||||
@@ -699,53 +744,6 @@ local rule find-viable-generators ( target-type : properties * : allow-composing
|
||||
|
||||
return [ sequence.select-highest-ranked $(viable-generators) : $(generator-rank) ] ;
|
||||
}
|
||||
|
||||
# currently unused. Sorry for the cruft. Delete at will
|
||||
local rule find-viable-generators.new ( target-type : properties * : disallow-composing ? )
|
||||
{
|
||||
# Select generators that can create the required target type.
|
||||
local viable-generators = ;
|
||||
local generator-rank = ;
|
||||
|
||||
import type ;
|
||||
local t = [ type.all-bases $(target-type) ] ;
|
||||
|
||||
while $(t[1])
|
||||
{
|
||||
generators.dout [ indent ] " ...checking type" [ $(t[1]) ] ;
|
||||
|
||||
for local g in $(.generators.$(t[1]))
|
||||
{
|
||||
generators.dout [ indent ] " ...checking" [ $(g).id ] ;
|
||||
# Avoid trying the same generator twice on different levels.
|
||||
if ! $(g) in $(.active-generators)
|
||||
&& ! ( [ is-a $(g) : composing-generator ] && $(.disallow-composing) )
|
||||
{
|
||||
local requirements = [ $(g).requirements ] ;
|
||||
generators.dout [ indent ] " ...requirements:" $(requirements) ;
|
||||
|
||||
if $(requirements) in $(properties)
|
||||
{
|
||||
local optional = [ $(g).optional-properties ] ;
|
||||
local match = $(requirements) [ set.intersection $(optional) : $(properties) ] ;
|
||||
|
||||
if $(match)
|
||||
{
|
||||
viable-generators += $(g) ;
|
||||
generator-rank += [ sequence.length $(match) ] ;
|
||||
generators.dout [ indent ] " ...matched" [ $(g).id ]
|
||||
"with rank $(generator-rank[-1]) :" $(match) ;
|
||||
t = ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
t = $(t[2-]) ;
|
||||
}
|
||||
|
||||
|
||||
return [ sequence.select-highest-ranked $(viable-generators) : $(generator-rank) ] ;
|
||||
}
|
||||
|
||||
# Given a vector of vectors, of of them represents results of running some
|
||||
# generator, returns the 'best' result, it it exists. Otherwise, exit with
|
||||
|
||||
Reference in New Issue
Block a user