2
0
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:
Vladimir Prus
2003-01-31 14:20:25 +00:00
parent 601764adff
commit 0d2ae4c6c1

View File

@@ -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