diff --git a/src/build/alias.jam b/src/build/alias.jam index e85d415ef..4fd1721a0 100644 --- a/src/build/alias.jam +++ b/src/build/alias.jam @@ -30,6 +30,7 @@ import errors : error ; import type : type ; import regex ; import project ; +import property-set ; class alias-target-class : basic-target { @@ -42,7 +43,7 @@ class alias-target-class : basic-target rule construct ( source-targets * : property-set ) { - return $(source-targets) ; + return [ property-set.empty ] $(source-targets) ; } # This check makes no sense for 'alias', so just diff --git a/src/build/generators.jam b/src/build/generators.jam index 14824e73b..0c8a44ba2 100644 --- a/src/build/generators.jam +++ b/src/build/generators.jam @@ -46,6 +46,7 @@ import utility : str equal ; import set sequence ; import assert ; import virtual-target ; +import property-set ; if "--debug-generators" in [ modules.peek : ARGV ] { @@ -84,7 +85,8 @@ local rule decrease-indent ( ) # regardless of their order. rule normalize-target-list ( targets ) { - $(targets).sort ; + local v = [ $(targets).get ] ; + $(targets).set $(v[1]) [ sequence.insertion-sort $(v[2-]) : utility.less ] ; } # Creates a generator @@ -478,7 +480,8 @@ class generator # its best to convert everything to the required type. # There's no need to rerun it on targets of different types. - for local t in $(transformed) + # NOTE: ignoring usage requirements + for local t in $(transformed[2-]) { if [ $(t).type ] in $(missing-types) { @@ -696,7 +699,7 @@ rule base-to-derived-type-conversion ( targets * : target-types + } - +# Returns usage requirements + list of created targets local rule try-one-generator ( project name ? : generator multiple ? : target-type : property-set : sources * ) { @@ -711,7 +714,18 @@ local rule try-one-generator ( project name ? : generator multiple ? : local result ; # Generated target of other types. local extra ; - + + 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 ] ; + } + base-to-derived-type-conversion $(targets) : $(target-type) : result extra ; @@ -729,8 +743,8 @@ local rule try-one-generator ( project name ? : generator multiple ? : : : $(property-set) : $(e) ] ; - - result += $(try2) ; + usage-requirements = [ $(usage-requirements).add $(try2[1]) ] ; + result += $(try2[2-]) ; } } else @@ -739,6 +753,10 @@ local rule try-one-generator ( project name ? : generator multiple ? : } generators.dout [ indent ] " generator" [ $(generator).id ] " spawned " ; generators.dout [ indent ] " " $(result) -- $(extra2) ; + if $(targets) + { + result = $(usage-requirements) $(result) ; + } return $(result) $(extra2) ; } @@ -747,13 +765,15 @@ rule construct-types ( project name ? : target-types + : multiple ? : { local result ; local matched-types ; + local usage-requirements = [ property-set.empty ] ; for local t in $(target-types) { local r = [ construct $(project) $(name) : $(t) $(multiple) : $(property-set) : $(sources) ] ; if $(r) { - result += $(r) ; + usage-requirements = [ $(usage-requirements).add $(r[1]) ] ; + result += $(r[2-]) ; matched-types += $(t) ; } } @@ -767,11 +787,11 @@ rule construct-types ( project name ? : target-types + : multiple ? : # imply that, contrary to the behaviour. if $(result) { - return $(result) ; + return $(usage-requirements) $(result) ; } else { - return $(sources) ; + return $(usage-requirements) $(sources) ; } } @@ -887,7 +907,8 @@ local rule select-dependency-graph ( options ) for local r in [ $(options).get ] { normalize-target-list $(r) ; - generators.dout $(r) ; + local v = [ $(r).get ] ; + generators.dout $(v[2-]) ; } # One note why we can compare object names directly, @@ -897,10 +918,14 @@ local rule select-dependency-graph ( options ) # So, two elements can only be equivalent, if they are just # the same object. local f = [ $(options).at 1 ] ; + f = [ $(f).get ] ; + f = $(f[2-]) ; local mismatch ; - for local r in [ $(results).get ] + for local r in [ $(options).get ] { - if [ $(r).get ] != [ $(f).get ] + local v = [ $(r).get ] ; + v = $(v[2-]) ; + if $(f) != $(v) { mismatch = true ; } @@ -908,7 +933,8 @@ local rule select-dependency-graph ( options ) if ! $(mismatch) { - return [ $(f).get ] ; + local v = [ $(options).at 1 ] ; + return [ $(v).get ] ; } else { @@ -954,8 +980,9 @@ local rule construct-with-caching ( # Substitute the real source name in the transformation template. if $(cresult) { + result += $(cresult[1]) ; generators.dout [ indent ] "*** putting to cache?" ; - for local c in $(cresult) + for local c in $(cresult[2-]) { generators.dout [ indent ] "*** cloning " $(c) ; local cc = [ virtual-target.clone-template $(c) : $(t) : $(project) ] ; @@ -1075,11 +1102,17 @@ rule construct ( project name ? : target-type multiple ? : property-set * : sour result += $(intermediate) ; } + if $(result) + { + assert.true class.is-a $(result[1]) : property-set ; + } + + # For all targets of 'allowed-type', reset the 'intermediate' attribute. if ! $(.construct-stack) && $(allowed-type) != * # This is first invocation in stack { local result2 ; - for local t in $(result) + for local t in $(result[2-]) { local type = [ $(t).type ] ; # Return only targets of the requested type, unless 'return-all' diff --git a/src/build/targets.jam b/src/build/targets.jam index 89f56d25c..890f721db 100644 --- a/src/build/targets.jam +++ b/src/build/targets.jam @@ -1022,11 +1022,15 @@ class basic-target : abstract-target local result = [ construct $(source-targets) : $(rproperties) ] ; + + local gur = $(result[1]) ; + result = $(result[2-]) ; local s = [ create-subvariant $(result) : $(property-set) : $(source-targets) : $(rproperties) : $(usage-requirements) ] ; local ur = [ compute-usage-requirements $(s) ] ; + ur = [ $(ur).add $(gur) ] ; $(s).set-usage-requirements $(ur) ; self.generated.$(property-set) = $(ur) $(result) ; diff --git a/src/tools/borland.jam b/src/tools/borland.jam index bfe162911..d590e14f8 100644 --- a/src/tools/borland.jam +++ b/src/tools/borland.jam @@ -48,7 +48,7 @@ type.register BORLAND.TDS : tds ; generators.register-linker borland.link : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE RSP : borland ; generators.register-linker borland.link.dll : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB RSP : borland ; -generators.register-composing borland.archive : OBJ : STATIC_LIB : borland ; +generators.register-archiver borland.archive : OBJ : STATIC_LIB : borland ; generators.register-c-compiler borland.compile.c++ : CPP : OBJ : borland ; generators.register-c-compiler borland.compile.c : C : OBJ : borland ; diff --git a/src/tools/builtin.jam b/src/tools/builtin.jam index 41af9dea4..0ab98cf31 100644 --- a/src/tools/builtin.jam +++ b/src/tools/builtin.jam @@ -261,8 +261,8 @@ declare-type : SHARED_LIB : so : LIB : main ; declare-type : SEARCHED_LIB : : LIB : main ; -declare-type NT CYGWIN : EXE : exe : : ; -declare-type : EXE : : : ; +declare-type NT CYGWIN : EXE : exe : : main ; +declare-type : EXE : : : main ; declare-type : PYTHON_EXTENSION : : SHARED_LIB : main ; # We can't give "dll" suffix to PYTHON_EXTENSION, because @@ -338,21 +338,18 @@ type.register H : h ; type.register HPP : hpp : H ; type.register C : c ; -class lib-target-class : basic-target +# The generator class for libraries (target type LIB). Depending on properties it will +# request building of the approapriate specific type -- SHARED_LIB, STATIC_LIB or +# SHARED_LIB. +class lib-generator : generator { - import generators : construct : generators.construct ; - import type ; - import path ; - - rule __init__ ( name : project - : sources * : requirements * : default-build * : usage-requirements * ) - { - basic-target.__init__ $(name) : $(project) - : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ; + rule __init__ ( * : * ) + { + generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; } - - rule construct ( source-targets * : property-set ) - { + + rule run ( project name ? : property-set : sources * : multiple ? ) + { local properties = [ $(property-set).raw ] ; # Determine the needed target type local actual-type ; @@ -375,67 +372,17 @@ class lib-target-class : basic-target } property-set = [ $(property-set).add-raw LIB ] ; # Construct the target. - return [ generators.construct $(self.project) $(self.name) : $(actual-type) - : $(property-set) : $(source-targets) : LIB ] ; - } - - rule compute-usage-requirements ( subvariant ) - { - local rproperties = [ $(subvariant).build-properties ] ; - local created-targets = [ $(subvariant).created-targets ] ; - local result = [ basic-target.compute-usage-requirements $(subvariant) ] ; - - # For lib targets with , add the value of as - # usage requirement. - local search = [ $(rproperties).get ] ; - if $(search) - { - result = [ $(result).add [ - property-set.create $(search:G=) ] ] ; - } - - # Add appropricate usage requirements. - local raw = [ $(rproperties).raw ] ; - if shared in $(raw) - { - local paths ; - local pwd = [ path.pwd ] ; - for local t in $(created-targets) - { - if [ type.is-derived [ $(t).type ] SHARED_LIB ] - { - paths += [ path.root [ path.make [ $(t).path ] ] $(pwd) ] ; - } - } - if $(paths) - { - result = [ $(result).add - [ property-set.create $(paths:G=) ] ] ; - } - } - - # Pass features that we've got from sources. - local u = [ $(subvariant).sources-usage-requirements ] ; - local values = [ $(u).get ] ; - result = [ $(result).add-raw $(values:G=) ] ; - - # For libraries that we've failed to consume, we need to - # pass usage requirements, if any. - # We look at all generated target, and if they are created in different - # subvariant, we add usage requirements. - for local t in [ $(subvariant).created-targets ] - { - local s = [ $(t).creating-subvariant ] ; - if $(s) != $(subvariant) - { - result = [ $(result).add [ $(s).usage-requirements ] ] ; - } - } - - return $(result) ; - } + return [ generators.construct $(project) $(name) : $(actual-type) + : $(property-set) : $(sources) : LIB ] ; + } } +generators.register [ new lib-generator builtin.lib-generator : : LIB ] ; + +# The implementation of the 'lib' rule. Beyond standard syntax that rule allows +# simplified: +# lib a b c ; +# so we need to write code to handle that syntax. rule lib ( names + : sources * : requirements * : default-build * : usage-requirements * ) { @@ -452,7 +399,7 @@ rule lib ( names + : sources * : requirements * : default-build * { result += [ targets.main-target-alternative - [ new lib-target-class $(name) : $(project) + [ new typed-target $(name) : $(project) : LIB : : [ targets.main-target-requirements $(requirements) $(name) : $(project) ] @@ -471,7 +418,7 @@ rule lib ( names + : sources * : requirements * : default-build * local name = $(names[1]) ; result = [ targets.main-target-alternative - [ new lib-target-class $(name) : $(project) + [ new typed-target $(name) : $(project) : LIB : [ targets.main-target-sources $(sources) : $(name) ] : [ targets.main-target-requirements $(requirements) : $(project) ] : [ targets.main-target-default-build $(default-build) : $(project) ] @@ -482,73 +429,10 @@ rule lib ( names + : sources * : requirements * : default-build * } IMPORT $(__name__) : lib : : lib ; - -class exe-target-class : typed-target -{ - import type ; - - rule __init__ ( name : project - : sources * : requirements * : default-build * : usage-requirements * ) - { - typed-target.__init__ $(name) : $(project) : EXE - : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ; - } - - rule compute-usage-requirements ( subvariant ) - { - local result = [ typed-target.compute-usage-requirements $(subvariant) ] ; - local p = [ $(subvariant).build-properties ] ; - - local xdll-paths = [ $(p).get ] ; - if $(xdll-paths) - { - result = [ $(result).add-raw $(xdll-paths:G=) ] ; - } - - return $(result) ; - } - - rule check-for-unused-sources ( result * : sources * ) - { - # For exes, we typically don't consume ignore DLL on windows. - # We also handle searched libraries via special properties - # on actions, so should not check for search libraries. - # As the result, we don't check for unused LIB sources - # at all. - - local sources-to-check ; - for local s in $(sources) - { - if ! [ type.is-derived [ $(s).type ] LIB ] - { - sources-to-check += $(s) ; - } - } - basic-target.check-for-unused-sources $(result) : $(sources-to-check) ; - } -} - -rule exe ( name : sources * : requirements * : default-build * - : usage-requirements * ) -{ - local project = [ project.current ] ; - - # This is a circular module dependency, so it must be imported here - import targets ; - targets.main-target-alternative - [ new exe-target-class $(name) : $(project) - : [ targets.main-target-sources $(sources) : $(name) ] - : [ targets.main-target-requirements $(requirements) : $(project) ] - : [ targets.main-target-default-build $(default-build) : $(project) ] - : [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ] - ] ; -} -IMPORT $(__name__) : exe : : exe ; - - - class searched-lib-generator : generator { + import property-set ; + rule __init__ ( ) { # The requirements cause the generators to be tried *only* when we're building @@ -584,9 +468,19 @@ class searched-lib-generator : generator # lib png : z : png ; # the 'z' target should be returned, so that apps linking to # 'png' will link to 'z', too. - return [ virtual-target.register $(t) ] $(sources) ; + return [ extra-usage-requirements $(property-set) ] [ virtual-target.register $(t) ] $(sources) ; } } + + rule extra-usage-requirements ( property-set ) + { + # Add the value of as + # usage requirement. + local search = [ $(property-set).get ] ; + search = $(search:G=) ; + return [ property-set.create $(search) ] ; + } + } generators.register [ new searched-lib-generator ] ; @@ -609,9 +503,6 @@ generators.register [ new prebuilt-lib-generator builtin.prebuilt : : LIB : ] ; - - - class compile-action : action { import sequence ; @@ -620,7 +511,7 @@ class compile-action : action { action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ; } - + # For all virtual targets for the same dependency graph as self, # i.e. which belong to the same main target, add their directories @@ -664,6 +555,7 @@ rule register-c-compiler ( id : source-types + : target-types + : # register all generators as "generator.some-rule", not with "some-module.some-rule".) IMPORT $(__name__) : register-c-compiler : : generators.register-c-compiler ; +# The generator class for handling EXE and SHARED_LIB creation. class linking-generator : generator { import property-set ; @@ -719,9 +611,48 @@ class linking-generator : generator local result = [ generator.run $(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ; - return $(result) ; + return [ extra-usage-requirements $(result) : $(property-set) ] $(result) ; } + rule extra-usage-requirements ( created-targets * : property-set ) + { + local result = [ property-set.empty ] ; + local extra ; + + # Add appropricate usage requirements. + local raw = [ $(property-set).raw ] ; + if shared in $(raw) + { + local paths ; + local pwd = [ path.pwd ] ; + for local t in $(created-targets) + { + if [ type.is-derived [ $(t).type ] SHARED_LIB ] + { + paths += [ path.root [ path.make [ $(t).path ] ] $(pwd) ] ; + } + } + extra += $(paths:G=) ; + } + + # We need to pass features that we've got from sources, + # because if shared library is built, exe which uses it must know paths + # to other shared libraries this one depends on, to be able to find them + # all at runtime. + + # Just pass all features in property-set, it's theorically possible + # that we'll propagate features explicitly specified by + # 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) ] ; + } + return $(result) ; + } + rule generated-targets ( sources + : property-set : project name ? ) { local sources2 ; # sources to pass to inherited rule @@ -772,7 +703,51 @@ rule register-linker ( id composing ? : source-types + : target-types + : generators.register $(g) ; } -IMPORT $(__name__) : register-linker : : generators.register-linker ; +# The generator class for handling STATIC_LIB creation. +class archive-generator : generator +{ + import property-set ; + + rule __init__ ( id composing ? : source-types + : target-types + : + requirements * ) + { + composing ?= true ; + generator.__init__ $(id) $(composing) : $(source-types) : $(target-types) : + $(requirements) ; + } + + rule run ( project name ? : property-set : sources + : multiple ? ) + { + local result = [ generator.run $(project) $(name) : $(property-set) + : $(sources) : $(multiple) ] ; + + # Compute additional usage requirements. + # For static linkinking any source libraries are no linked in but are bypassed. + # We also must pass the usage requirements we've got from those + # sources, so that dependents can find them. + + # Just pass all properties. We might pass + # properties which did not come from dependencies, but + # were specified in requirements, but I don't think that's a problem. + local values = [ $(property-set).get ] ; + local usage-requirements = [ property-set.create $(values:G=) ] ; + + return $(usage-requirements) $(result) ; + + } +} + +rule register-archiver ( id composing ? : source-types + : target-types + : + requirements * ) +{ + local g = [ new archive-generator $(id) $(composing) : $(source-types) + : $(target-types) : $(requirements) ] ; + generators.register $(g) ; +} + + +IMPORT $(__name__) : register-linker register-archiver + : : generators.register-linker generators.register-archiver ; declare-type : RSP : rsp ; diff --git a/src/tools/como-win.jam b/src/tools/como-win.jam index e6ddbeb2a..a3de29517 100644 --- a/src/tools/como-win.jam +++ b/src/tools/como-win.jam @@ -46,7 +46,7 @@ generators.register-linker como-win.link : como win ; # Note that status of shared libraries support is not clear, so we don't # define the link.dll generator. -generators.register-composing como-winc.archive +generators.register-archiver como-winc.archive : OBJ : STATIC_LIB RSP : como win ; diff --git a/src/tools/cw.jam b/src/tools/cw.jam index 35b946b56..b7f6648bd 100644 --- a/src/tools/cw.jam +++ b/src/tools/cw.jam @@ -110,7 +110,7 @@ generators.register-linker cw.link.dll : cw ; -generators.register-composing cw.archive +generators.register-archiver cw.archive : OBJ : STATIC_LIB RSP : cw diff --git a/src/tools/make.jam b/src/tools/make.jam index 9411f7484..249fd69e2 100644 --- a/src/tools/make.jam +++ b/src/tools/make.jam @@ -36,7 +36,7 @@ class make-target-class : basic-target local a = [ new action $(t) : $(source-targets) : $(self.make-rule) : $(property-set) ] ; $(t).action $(a) ; - return [ virtual-target.register $(t) ] ; + return [ property-set.empty ] [ virtual-target.register $(t) ] ; } } diff --git a/src/tools/msvc.jam b/src/tools/msvc.jam index 8672ffe28..bad49cf67 100644 --- a/src/tools/msvc.jam +++ b/src/tools/msvc.jam @@ -224,7 +224,7 @@ rule default-paths ( version ? ) generators.register-linker msvc.link : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE RSP : msvc ; generators.register-linker msvc.link.dll : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB RSP : msvc ; -generators.register-composing msvc.archive : OBJ : STATIC_LIB RSP : msvc ; +generators.register-archiver msvc.archive : OBJ : STATIC_LIB RSP : msvc ; generators.register-c-compiler msvc.compile.c++ : CPP : OBJ : msvc ; generators.register-c-compiler msvc.compile.c : C : OBJ : msvc ; generators.register-standard msvc.compile.rc : RC : OBJ(%_res) : msvc ; diff --git a/src/tools/stage.jam b/src/tools/stage.jam index dc837a761..7c75ab2ad 100644 --- a/src/tools/stage.jam +++ b/src/tools/stage.jam @@ -57,6 +57,7 @@ import regex ; import generators ; import feature ; import project ; +import property-set ; feature.feature : off on : incidental ; feature.feature : : free incidental ; @@ -93,7 +94,7 @@ class stage-target-class : basic-target local targets = [ generators.construct $(self.project) : $(type) : $(property-set) : $(source) : * ] ; - return $(targets) ; + return $(targets[2-]) ; } # Constructs the targets of types for which there is no STAGED_* type. @@ -189,7 +190,7 @@ class stage-target-class : basic-target } } - return $(result) ; + return [ property-set.empty ] $(result) ; } rule select-included ( source-targets * : types-to-include * ) diff --git a/src/tools/symlink.jam b/src/tools/symlink.jam index 41daaee16..35bdecdf2 100644 --- a/src/tools/symlink.jam +++ b/src/tools/symlink.jam @@ -6,7 +6,7 @@ # Defines the "symlink" special target. 'symlink' targets make symbolic links # to the sources. -import targets modules path class os feature project ; +import targets modules path class os feature project property-set ; .count = 0 ; @@ -70,7 +70,7 @@ class symlink-targets : basic-target self.virtual-targets += $(vt) ; i = [ numbers.increment $(i) ] ; } - return $(self.virtual-targets) ; + return [ property-set.empty ] $(self.virtual-targets) ; } } diff --git a/src/tools/unix.jam b/src/tools/unix.jam index aa5d5a58a..3c6e90672 100644 --- a/src/tools/unix.jam +++ b/src/tools/unix.jam @@ -40,7 +40,7 @@ class unix-linking-generator : linking-generator local result = [ linking-generator.run $(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ; - unix.set-library-order $(sources) : $(property-set) : $(result) ; + unix.set-library-order $(sources) : $(property-set) : $(result[2-]) ; return $(result) ; } @@ -69,7 +69,7 @@ class unix-linking-generator : linking-generator } -class unix-archive-generator : generator +class unix-archive-generator : archive-generator { import unix ; @@ -77,16 +77,16 @@ class unix-archive-generator : generator requirements * ) { composing ?= true ; - generator.__init__ $(id) $(composing) : $(source-types) : $(target-types) : + archive-generator.__init__ $(id) $(composing) : $(source-types) : $(target-types) : $(requirements) ; } rule run ( project name ? : property-set : sources + : multiple ? ) { - local result = [ generator.run $(project) $(name) : $(property-set) + local result = [ archive-generator.run $(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ; - unix.set-library-order $(sources) : $(property-set) : $(result) ; + unix.set-library-order $(sources) : $(property-set) : $(result[2-]) ; return $(result) ; @@ -112,7 +112,7 @@ class unix-searched-lib-generator : searched-lib-generator local result = [ searched-lib-generator.run $(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ; - unix.set-library-order $(sources) : $(property-set) : $(result) ; + unix.set-library-order $(sources) : $(property-set) : $(result[2-]) ; return $(result) ; } diff --git a/src/util/container.jam b/src/util/container.jam index a62aad3a4..6ad63d857 100644 --- a/src/util/container.jam +++ b/src/util/container.jam @@ -22,7 +22,7 @@ class node # Set the value of this node, passing nothing will clear it. # - rule set ( value ? ) + rule set ( value * ) { self.value = $(value) ; } @@ -214,6 +214,7 @@ class vector : node # Sorts the vector inplace, calling 'utility.less' for # comparisons. + # NOTE: this rule is unused at the moment. rule sort ( ) { self.value = diff --git a/test/generators-test/project-root.jam b/test/generators-test/project-root.jam index f676c72df..457867fcf 100644 --- a/test/generators-test/project-root.jam +++ b/test/generators-test/project-root.jam @@ -60,7 +60,7 @@ class nm::target::cpp-obj-generator : generator local converted = [ generators.construct $(project) : NM.TARGET.CPP : $(properties) : $(source) ] ; if $(converted[1]) { - local result = [ generators.construct $(project) : OBJ : $(properties) : $(converted[1]) ] ; + local result = [ generators.construct $(project) : OBJ : $(properties) : $(converted[2]) ] ; return $(result) ; } else