diff --git a/v2/build/targets.jam b/v2/build/targets.jam index 7f01356ca..0118c4e3a 100644 --- a/v2/build/targets.jam +++ b/v2/build/targets.jam @@ -917,7 +917,7 @@ class basic-target : abstract-target check-for-unused-sources $(result) : $(source-target-groups) ; - local s = [ create-subvariant $(result) : $(property-set) + local s = [ create-subvariant $(result) : $(property-set) : $(source-targets) : $(rproperties) : $(usage-requirements) ] ; self.generated.$(property-set) = @@ -954,7 +954,8 @@ class basic-target : abstract-target } # Creates a new subvariant-dg instances for 'targets' - local rule create-subvariant ( targets * : build-request : rproperties + local rule create-subvariant ( targets * : build-request : sources * : + rproperties : usage-requirements ) { for local e in $(targets) @@ -966,7 +967,7 @@ class basic-target : abstract-target # is created. local all-targets = [ sequence.transform virtual-target.traverse : $(targets) ] ; - local dg = [ new subvariant $(__name__) : $(build-request) + local dg = [ new subvariant $(__name__) : $(build-request) : $(sources) : $(rproperties) : $(usage-requirements) : $(all-targets) ] ; for local v in $(all-targets) { diff --git a/v2/build/type.jam b/v2/build/type.jam index f24cf12db..4ccc20438 100644 --- a/v2/build/type.jam +++ b/v2/build/type.jam @@ -183,6 +183,21 @@ rule is-derived ( type base ) } } +# Returns true if 'type' is either derived from 'base', +# or 'type' is equal to 'base'. +rule is-subtype ( type base ) +{ + if $(type) = $(base) + { + return true ; + } + else + { + return [ is-derived $(type) $(base) ] ; + } +} + + # Sets a target suffix that should be used when generating target # of 'type' with the specified properties. Can be called with # empty properties if no suffix for 'type' was specified yet. diff --git a/v2/build/virtual-target.jam b/v2/build/virtual-target.jam index 971028864..787e10efd 100644 --- a/v2/build/virtual-target.jam +++ b/v2/build/virtual-target.jam @@ -895,12 +895,14 @@ class subvariant rule __init__ ( main-target # The instance of main-target class : property-set # Properties requested for this target + : sources * : build-properties # Actually used properties : sources-usage-requirements # Properties propagated from sources : created-targets * ) # Top-level created targets { - self.main-target = $(main-target) ; + self.main-target = $(main-target) ; self.properties = $(property-set) ; + self.sources = $(sources) ; self.build-properties = $(build-properties) ; self.sources-usage-requirements = $(sources-usage-requirements) ; self.created-targets = $(created-targets) ; @@ -941,6 +943,33 @@ class subvariant { return $(self.sources-usage-requirements) ; } + + # Returns all targets referenced by this subvariant, + # either directly or indirectly, and + # either as sources, or as dependency properties. + rule all-referenced-targets ( ) + { + # Find directly referenced targets. + local deps = [ $(self.build-properties).dependency ] ; + local all-targets = $(self.sources) $(deps:G=) ; + + # Find other subvariants. + local r ; + for local t in $(all-targets) + { + r += [ $(t).dg ] ; + } + r = [ sequence.unique $(r) ] ; + for local s in $(r) + { + if $(s) != $(__name__) + { + all-targets += [ $(s).all-referenced-targets ] ; + } + } + return $(all-targets) ; + } + # Returns a list of properties which contain implicit includes, # needed to handle dependencies of generated headers. diff --git a/v2/test/stage.py b/v2/test/stage.py index 2eeb937a2..873ecf0d2 100644 --- a/v2/test/stage.py +++ b/v2/test/stage.py @@ -110,4 +110,34 @@ myexe a : a.cpp ; t.run_build_system() t.expect_addition("dist/a.myexe") +# Test 'stage's ability to traverse dependencies. +t.write("a.cpp", """ +int main() { return 0; } + +""") + +t.write("l.cpp", """ +void +#if defined(_WIN32) +__declspec(dllexport) +#endif +foo() { } + +""") + +t.write("Jamfile", """ +lib l : l.cpp ; +exe a : a.cpp l ; +stage dist : a : on EXE LIB ; +""") + +t.write("project-root.jam", "") + +t.rm("dist") +t.run_build_system() +t.expect_addition("dist/a.exe") +t.expect_addition("dist/l.dll") + + t.cleanup() + diff --git a/v2/tools/stage.jam b/v2/tools/stage.jam index 75192b564..79c06877f 100644 --- a/v2/tools/stage.jam +++ b/v2/tools/stage.jam @@ -26,6 +26,26 @@ # # - tells the new name of the staged target. In this case, only # one target can be specified in sources. +# +# The stage rule can also traverse dependencies, for example to install a +# program an all required libraries. Two properties affect this. +# +# - on tells that dependencies should be traversed. +# For each target in 'stage' sources, all sources to that target and all +# dependency properties are traversed. Sources and dependecy properties of +# those target are traversed recursively. +# +# - SOME_TYPE tells that targets of SOME_TYPE or a type derived +# from SOME_TYPE, should be included. +# If no such property is specified, then all found targets will be staged. +# Otherwise, only targets with types mentioned in property +# will be included. +# +# Example usage:: +# +# stage dist : hello_world : +# on EXE SHARED_LIB ; +# import targets ; import "class" : new ; @@ -35,6 +55,10 @@ import type : type ; import type ; import regex ; import generators ; +import feature ; + +feature.feature : off on : incidental ; +feature.feature : : free incidental ; class stage-target-class : basic-target { @@ -54,7 +78,13 @@ class stage-target-class : basic-target { errors.error " property cannot be specified when staging several targets" ; } - + + if [ $(property-set).get ] = "on" + { + source-targets = [ collect-targets $(source-targets) + : [ $(property-set).get ] ] ; + } + local location = [ feature.get-values : [ $(property-set).raw ] ] ; if ! $(location) @@ -115,11 +145,63 @@ class stage-target-class : basic-target return $(result) ; } + rule collect-targets ( targets * : types-to-include * ) + { + # Find subvariants + local s ; + for local t in $(targets) + { + s += [ $(t).dg ] ; + } + s = [ sequence.unique $(s) ] ; + + local result = $(targets) ; + for local i in $(s) + { + result += [ $(i).all-referenced-targets ] ; + } + result = [ sequence.unique $(result) ] ; + + if $(types-to-include) + { + local result2 ; + for local r in $(result) + { + if [ include-type [ $(r).type ] : $(types-to-include) ] + { + result2 += $(r) ; + } + } + return $(result2) ; + } + else + { + return $(result) ; + } + } + # Don't do nothing. rule check-for-unused-sources ( result * : sources * ) { } + # Returns true iff 'type' is subtype of some element of 'types-to-include'. + local rule include-type ( type : types-to-include * ) + { + local found ; + while $(types-to-include) && ! $(found) + { + if [ type.is-subtype $(type) $(types-to-include[1]) ] + { + found = true ; + } + types-to-include = $(types-to-include[2-]) ; + } + + return $(found) ; + } + + } # Declare staged version of the EXE type. Generator for this type will