From 7b2749353b3f8ea4182c43b34bbf06ef64a70751 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Thu, 2 Jun 2005 06:43:56 +0000 Subject: [PATCH] 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] --- v2/build/generators.jam | 111 +++++++----------------------- v2/test/generators-test/extra.jam | 41 +++++++++++ v2/test/searched_lib.py | 18 ----- v2/tools/builtin.jam | 35 +++++++--- v2/tools/qt.jam | 12 ++-- v2/tools/unix.jam | 14 ++-- 6 files changed, 104 insertions(+), 127 deletions(-) diff --git a/v2/build/generators.jam b/v2/build/generators.jam index a3f04c7fe..77802458d 100644 --- a/v2/build/generators.jam +++ b/v2/build/generators.jam @@ -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 ; diff --git a/v2/test/generators-test/extra.jam b/v2/test/generators-test/extra.jam index 638a9b764..ef639e1ef 100644 --- a/v2/test/generators-test/extra.jam +++ b/v2/test/generators-test/extra.jam @@ -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 * ) { } diff --git a/v2/test/searched_lib.py b/v2/test/searched_lib.py index 2ad628850..4a411ccef 100644 --- a/v2/test/searched_lib.py +++ b/v2/test/searched_lib.py @@ -140,22 +140,4 @@ lib l : : 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 : : 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() diff --git a/v2/tools/builtin.jam b/v2/tools/builtin.jam index 3780765b3..b81c08b41 100644 --- a/v2/tools/builtin.jam +++ b/v2/tools/builtin.jam @@ -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 ] ; 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 ] ; @@ -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 ] ; extra += $(values:G=) ; - + 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 ] ; 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 ] = static + { + for local t in $(sources) + { + if [ type.is-derived [ $(t).type ] LIB ] + { + result += $(t) ; + } + } + } return $(result) ; } diff --git a/v2/tools/qt.jam b/v2/tools/qt.jam index d1645da24..8b4ba32c8 100644 --- a/v2/tools/qt.jam +++ b/v2/tools/qt.jam @@ -64,7 +64,7 @@ rule init ( prefix ? ) generator.__init__ qt.uic-cpp : UI UIC_H : CPP : qt ; } - rule run ( project name ? : properties * : sources + : multiple ? ) + rule run ( project name ? : properties * : sources + ) { # Consider this: # obj test : test_a.cpp : 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-]) ; } } diff --git a/v2/tools/unix.jam b/v2/tools/unix.jam index 2126bcc20..b85ef5809 100644 --- a/v2/tools/unix.jam +++ b/v2/tools/unix.jam @@ -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 ] ; unix.set-library-order-aux $(f) : $(sources) ;