2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-16 01:12:13 +00:00

Refactor generators a bit.

* If a generator was given a source it could not handle, it used to return
  that source together with generated targets. This was nice for some use
  cases, but no very nice for others, and this behaviour could not be turned
  off. One use case where it worked bad was:

      lib plugin : plugin.cpp helper ;
      lib helper : helper.cpp ;

  On windows, 'plugin' would link to the 'import library' and pass the DLL
  target though. So, when installing 'plugin', we'd also install 'helper.dll',
  and it was not possible to do anything about it.

* If we asked generators.construct to produce sources of type CPP,
  and the selected generator produced both targets of type CPP, and of
  some other type, we'd try again to convert those other targets to CPP.
  This simply complicated the logic for no good reason.

* Most generator function had 'multiple' parameter, which function
  was long forgotten by anybody.

As a bit of history, I believe some of the above decisions were due to a
certain use case:

          CPP <------- WHL
                          \
                            WD
                          /
          CPP <------- DLP

Here, a source file is converted to two targets with one command, and each
produced file is converted to CPP. Our generators search would notice that
there are two generators for CPP: the WHL->CPP and DPL->CPP
generators. Neither is better that the other so both are tried, and produce
(CPP, DPL) and (CPP, WHL) pairs of targets. To avoid reporting an ambiguity,
we'd try to convert, DLP to CPP and WHL to CPP, do it successfully, notice
that produced targets are the same and decide that there's no ambiguity.

However, this is rather complex logic for a relatively rare case. It can
be handled by writing another WD->CPP generator that would handle
disambiguation itself.

This commit has one user-visible change. The code:

  exe a : a.cpp b ;
  obj b : b.cpp helper;
  lib helper ;

No longer works -- the 'a' target won't link to 'helper'. However, this is
pretty stange code and worked before almost by accident.


[SVN r29361]
This commit is contained in:
Vladimir Prus
2005-06-02 06:43:56 +00:00
parent 3892b06d72
commit 7b2749353b
6 changed files with 104 additions and 127 deletions

View File

@@ -269,19 +269,8 @@ class generator
# all generated targets. See 'generated-targets' method.
: property-set # Desired properties for generated targets.
: sources + # Source targets.
: multiple ? # Allows the rule to run generator several times and return
# multiple targets of the same type. When this argument is not
# given, 'run' will return the list of targets, which is equal
# in size to the list of target types, and where type of
# each target is the same as the corresponding element of
# target type list. Non-empty value allows to return several
# such target lists, joined together.
)
{
# multiple = true ; # The tests seem to tolerate this; will
# remove the parameter altogether in the
# next revision to see what I learn -- DWA 2003/5/6
)
{
generators.dout [ indent ] " generator" $(self.id) ;
generators.dout [ indent ] " multiple:" $(mutliple) ;
generators.dout [ indent ] " composing:" $(self.composing) ;
@@ -290,12 +279,7 @@ class generator
{
errors.error "Unsupported source/source-type combination" ;
}
if $(self.source-types[2])
{
multiple = ;
}
# We don't run composing generators if no name is specified. The reason
# is that composing generator combines several targets, which can have
# different names, and it cannot decide which name to give for produced
@@ -308,12 +292,12 @@ class generator
# (the OBJ -> STATIC_LIB generator is composing)
if ! $(self.composing) || $(name)
{
run-really $(project) $(name) : $(property-set) : $(sources) : $(multiple) ;
run-really $(project) $(name) : $(property-set) : $(sources) ;
}
}
rule run-really ( project name ? : property-set : sources + : multiple ? )
rule run-really ( project name ? : property-set : sources + )
{
# Targets that this generator will consume directly.
local consumed = ;
@@ -328,7 +312,7 @@ class generator
else
{
convert-to-consumable-types $(project) $(name) :
$(property-set) : $(sources) : $(multiple)
$(property-set) : $(sources)
:
: consumed bypassed ;
}
@@ -338,7 +322,6 @@ class generator
{
result = [ construct-result $(consumed) : $(project) $(name)
: $(property-set) ] ;
result += $(bypassed) ;
}
@@ -467,7 +450,7 @@ class generator
# 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 ?
property-set : sources +
: only-one ? # convert 'source' to only one of source types
# if there's more that one possibility, report an
# error
@@ -510,7 +493,7 @@ class generator
if $(missing-types)
{
local transformed = [ generators.construct-types $(project) $(name)
: $(missing-types) : $(multiple) : $(property-set) : $(sources) ] ;
: $(missing-types) : $(property-set) : $(sources) ] ;
# Add targets of right type to 'consumed'. Add others to
# 'bypassed'. The 'generators.construct' rule has done
@@ -558,9 +541,8 @@ class generator
# Converts several files to consumable types.
rule convert-multiple-sources-to-consumable-types
( project : property-set : sources * : consumed-var bypassed-var : multiple ? )
( project : property-set : sources * : consumed-var bypassed-var )
{
multiple ?= * ;
# We process each source one-by-one, trying to convert it to
# a usable type.
local failed ;
@@ -570,7 +552,7 @@ class generator
local _b ;
# TODO: need to check for failure on each source.
convert-to-consumable-types $(project) : $(property-set)
: $(sources[1]) : $(multiple) : true : _c _b ;
: $(sources[1]) : true : _c _b ;
if ! $(_c)
{
generators.dout [ indent ] " failed to convert " $(sources[1]) ;
@@ -832,22 +814,15 @@ local rule viable-source-types-for-generator ( generator )
# Returns usage requirements + list of created targets
local rule try-one-generator-really ( project name ? : generator multiple ? :
local rule try-one-generator-really ( project name ? : generator :
target-type : property-set : sources * )
{
local targets =
[ $(generator).run $(project) $(name)
: $(property-set)
: $(sources)
: $(multiple)
] ;
# Generated targets that are of required types
local result ;
# Generated target of other types.
local extra ;
local usage-requirements ;
if $(targets) && [ class.is-a $(targets[1]) : property-set ]
{
@@ -859,53 +834,18 @@ local rule try-one-generator-really ( project name ? : generator multiple ? :
usage-requirements = [ property-set.empty ] ;
}
for local t in $(targets)
{
if [ $(t).type ] = $(target-type)
{
result += $(t) ;
}
else
{
extra += $(t) ;
}
}
# Now try to convert extra targets
# 'construct' will to its best to return only requested
# target types, so if we receive any extra from that call,
# we don't try to do anything about them.
local extra2 ;
if $(multiple)
{
for local e in $(extra)
{
local try2 = [ construct-types $(project) $(name)
: $(target-type)
:
: $(property-set)
: $(e) ] ;
usage-requirements = [ $(usage-requirements).add $(try2[1]) ] ;
result += $(try2[2-]) ;
}
}
else
{
extra2 = $(extra) ;
}
generators.dout [ indent ] " generator" [ $(generator).id ] " spawned " ;
generators.dout [ indent ] " " $(result) -- $(extra2) ;
generators.dout [ indent ] " " $(targets) ;
if $(targets)
{
result = $(usage-requirements) $(result) ;
return $(usage-requirements) $(targets) ;
}
return $(result) $(extra2) ;
}
# 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 multiple ? :
local rule try-one-generator ( project name ? : generator :
target-type : property-set : sources * )
{
local source-types ;
@@ -926,14 +866,14 @@ local rule try-one-generator ( project name ? : generator multiple ? :
}
else {
return [ try-one-generator-really $(project) $(name)
: $(generator) $(multiple)
: $(generator)
: $(target-type) : $(property-set) : $(sources) ] ;
}
}
rule construct-types ( project name ? : target-types + : multiple ? :
rule construct-types ( project name ? : target-types + :
property-set : sources + )
{
local result ;
@@ -941,7 +881,7 @@ rule construct-types ( project name ? : target-types + : multiple ? :
local usage-requirements = [ property-set.empty ] ;
for local t in $(target-types)
{
local r = [ construct $(project) $(name) : $(t) $(multiple) : $(property-set) :
local r = [ construct $(project) $(name) : $(t) : $(property-set) :
$(sources) ] ;
if $(r)
{
@@ -1179,7 +1119,7 @@ local rule select-dependency-graph ( options )
# Attempts to construct target by finding viable generators, running them
# and selecting the dependency graph
local rule construct-really (
project name ? : target-type multiple ? : property-set : sources * )
project name ? : target-type : property-set : sources * )
{
viable-generators = [ find-viable-generators $(target-type) : $(property-set) ] ;
@@ -1193,7 +1133,7 @@ local rule construct-really (
# This variable will be restored on exit from this scope.
local .active-generators = $(g) $(.active-generators) ;
local r = [ try-one-generator $(project) $(name) : $(g) $(multiple) : $(target-type) :
local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type) :
$(property-set) : $(sources) ] ;
if $(r)
@@ -1221,7 +1161,7 @@ local rule construct-really (
# 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 multiple ? : property-set * : sources *
rule construct ( project name ? : target-type : property-set * : sources *
: allowed-type * )
{
allowed-type ?= $(target-type) ;
@@ -1254,12 +1194,7 @@ rule construct ( project name ? : target-type multiple ? : property-set * : sour
increase-indent ;
local m ;
if $(multiple)
{
m = "(may return multiple targets)" ;
}
generators.dout [ indent ] "*** construct" $(target-type) $(m) ;
generators.dout [ indent ] "*** construct" $(target-type) ;
for local s in $(sources)
{
@@ -1268,7 +1203,7 @@ rule construct ( project name ? : target-type multiple ? : property-set * : sour
generators.dout [ indent ] " properties:" [ $(property-set).raw ] ;
local result = [ construct-really $(project) $(name)
: $(target-type) $(multiple) : $(property-set) : $(sources) ] ;
: $(target-type) : $(property-set) : $(sources) ] ;
decrease-indent ;

View File

@@ -1,6 +1,7 @@
import type ;
import generators ;
import "class" : new ;
type.register WHL : whl ;
type.register DLP : dlp ;
@@ -11,6 +12,46 @@ generators.register-standard extra.whale : WHL : CPP WHL_LR0 H H(%_symbols) ;
generators.register-standard extra.dolphin : DLP : CPP ;
generators.register-standard extra.wd : WD : WHL(%_parser) DLP(%_lexer) ;
class wd-to-cpp : generator
{
rule __init__ ( * : * : * )
{
generator.__init__ $(1) : $(2) : $(3) ;
}
rule run ( project name ? : property-set : source )
{
local new-sources ;
if ! [ $(source).type ] in WHL DLP
{
local r1 = [ generators.construct $(project) $(name)
: WHL : $(property-set) : $(source) ] ;
local r2 = [ generators.construct $(project) $(name)
: DLP : $(property-set) : $(source) ] ;
new-sources = [ sequence.unique $(r1[2-]) $(r2[2-]) ] ;
}
else
{
new-sources = $(source) ;
}
local result ;
for local i in $(new-sources)
{
local t = [ generators.construct $(project) $(name) : CPP
: $(property-set) : $(i) ] ;
result += $(t[2-]) ;
}
return $(result) ;
}
}
generators.override extra.wd-to-cpp : extra.whale ;
generators.override extra.wd-to-cpp : extra.dolphin ;
generators.register [ new wd-to-cpp extra.wd-to-cpp : : CPP ] ;
rule whale ( targets * : sources * : properties * )
{
}

View File

@@ -140,22 +140,4 @@ lib l : : <name>l_f ;
t.run_build_system("-n")
# A regression test. When a exe target uses obj target and
# obj target uses searched lib, the path to library was not
# added to 'exe's compile options. This is not a common use
# case, but anyway, the less surprises, the better.
t.rm(".")
t.write("Jamroot", """
exe a : a.cpp b ;
obj b : b.cpp s ;
lib s : : <search>foobar ;
""")
t.write("a.cpp", "")
t.write("b.cpp", "")
t.run_build_system("-n -d+2")
t.fail_test(string.find(t.stdout(), "foobar") == -1)
t.cleanup()

View File

@@ -307,7 +307,7 @@ class lib-generator : generator
generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
}
rule run ( project name ? : property-set : sources * : multiple ? )
rule run ( project name ? : property-set : sources * )
{
# The lib generator is composing, and can be only invoked with
# explicit name. This check is present in generator.run (and so in
@@ -408,7 +408,7 @@ class searched-lib-generator : generator
generator.__init__ searched-lib-generator : : SEARCHED_LIB ;
}
rule run ( project name ? : property-set : sources * : multiple ? )
rule run ( project name ? : property-set : sources * )
{
if $(name)
{
@@ -447,7 +447,7 @@ class prebuilt-lib-generator : generator
generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
}
rule run ( project name ? : property-set : sources * : multiple ? )
rule run ( project name ? : property-set : sources * )
{
local f = [ $(property-set).get <file> ] ;
return $(f) $(sources) ;
@@ -532,7 +532,7 @@ class linking-generator : generator
$(requirements) ;
}
rule run ( project name ? : property-set : sources + : multiple ? )
rule run ( project name ? : property-set : sources + )
{
sources += [ $(property-set).get <library> ] ;
@@ -581,9 +581,10 @@ class linking-generator : generator
}
local result = [ generator.run $(project) $(name) : $(property-set)
: $(sources) : $(multiple) ] ;
return [ extra-usage-requirements $(result) : $(property-set) ] $(result) ;
: $(sources) ] ;
return [ extra-usage-requirements $(result) : $(property-set) ]
$(result) ;
}
rule extra-usage-requirements ( created-targets * : property-set )
@@ -617,7 +618,7 @@ class linking-generator : generator
# the user, but then the user's to blaim for using internal feature.
local values = [ $(property-set).get <xdll-path> ] ;
extra += $(values:G=<xdll-path>) ;
if $(extra)
{
result = [ property-set.create $(extra) ] ;
@@ -687,12 +688,26 @@ class archive-generator : generator
$(requirements) ;
}
rule run ( project name ? : property-set : sources + : multiple ? )
rule run ( project name ? : property-set : sources + )
{
sources += [ $(property-set).get <library> ] ;
local result = [ generator.run $(project) $(name) : $(property-set)
: $(sources) : $(multiple) ] ;
: $(sources) ] ;
# For static linking, we can't directly link to libraries.
# So, return all LIB sources together with created targets,
# so that dependents link to them.
if [ $(property-set).get <link> ] = static
{
for local t in $(sources)
{
if [ type.is-derived [ $(t).type ] LIB ]
{
result += $(t) ;
}
}
}
return $(result) ;
}

View File

@@ -64,7 +64,7 @@ rule init ( prefix ? )
generator.__init__ qt.uic-cpp : UI UIC_H : CPP : <allow>qt ;
}
rule run ( project name ? : properties * : sources + : multiple ? )
rule run ( project name ? : properties * : sources + )
{
# Consider this:
# obj test : test_a.cpp : <optimization>off ;
@@ -81,13 +81,17 @@ rule init ( prefix ? )
{
# Construct CPP as usual
result = [ generator.run $(project) $(name)
: $(properties) : $(sources) : $(multiple) ] ;
# If OK, add "UIC_H" target to the returned list
: $(properties) : $(sources) ] ;
# If OK, process UIC_H with moc. It's pretty clear that
# the object generated with UIC will have Q_OBJECT macro.
if $(result)
{
local action = [ $(result[1]).action ] ;
local sources = [ $(action).sources ] ;
result += $(sources[2]) ;
local mocced = [ generators.construct $(project) $(name)
: CPP : $(properties) : $(sources[2]) ] ;
result += $(mocced[2-]) ;
}
}

View File

@@ -35,10 +35,10 @@ class unix-linking-generator : linking-generator
$(requirements) ;
}
rule run ( project name ? : property-set : sources + : multiple ? )
rule run ( project name ? : property-set : sources + )
{
local result = [ linking-generator.run $(project) $(name) : $(property-set)
: $(sources) : $(multiple) ] ;
: $(sources) ] ;
unix.set-library-order $(sources) : $(property-set) : $(result[2-]) ;
@@ -81,10 +81,10 @@ class unix-archive-generator : archive-generator
$(requirements) ;
}
rule run ( project name ? : property-set : sources + : multiple ? )
rule run ( project name ? : property-set : sources + )
{
local result = [ archive-generator.run $(project) $(name) : $(property-set)
: $(sources) : $(multiple) ] ;
: $(sources) ] ;
unix.set-library-order $(sources) : $(property-set) : $(result) ;
@@ -107,10 +107,10 @@ class unix-searched-lib-generator : searched-lib-generator
return $(self.requirements) ;
}
rule run ( project name ? : property-set : sources * : multiple ? )
rule run ( project name ? : property-set : sources * )
{
local result = [ searched-lib-generator.run $(project) $(name)
: $(property-set) : $(sources) : $(multiple) ] ;
: $(property-set) : $(sources) ] ;
unix.set-library-order $(sources) : $(property-set) : $(result) ;
@@ -126,7 +126,7 @@ class unix-prebuilt-lib-generator : generator
generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
}
rule run ( project name ? : property-set : sources * : multiple ? )
rule run ( project name ? : property-set : sources * )
{
local f = [ $(property-set).get <file> ] ;
unix.set-library-order-aux $(f) : $(sources) ;