diff --git a/new/build-system.jam b/new/build-system.jam index a50243489..514f94ab2 100644 --- a/new/build-system.jam +++ b/new/build-system.jam @@ -32,6 +32,11 @@ virtual-targets = ; if $(expanded) { + for local p in $(expanded) + { + $(root-target).direct-build-request [ feature.split $(p) ] ; + } + for local p in $(expanded) { virtual-targets += [ $(root-target).generate [ feature.split $(p) ] ] ; diff --git a/new/feature.jam b/new/feature.jam index 22577e331..dd7545cab 100644 --- a/new/feature.jam +++ b/new/feature.jam @@ -65,13 +65,15 @@ rule feature ( { error = feature already defined: ; } - else if implicit in $(attributes) + else if implicit in $(attributes) && free in $(attributes) { - if free in $(attributes) - { - error = free features cannot also be implicit ; - } + error = free features cannot also be implicit ; } + else if free in $(attributes) && propagated in $(attributes) + { + error = free features cannot be propagated ; + } + if $(error) { @@ -846,6 +848,12 @@ local rule __test__ ( ) } catch free features cannot also be implicit ; + try ; + { + feature feature3 : : free propagated ; + } + catch free features cannot be propagated ; + try ; { implied-feature lackluster ; diff --git a/new/targets.jam b/new/targets.jam index 2d2afede7..d5419a9e3 100644 --- a/new/targets.jam +++ b/new/targets.jam @@ -56,6 +56,13 @@ rule abstract-target ( name # name of the target in Jamfile return $(location)/$(self.name) ; } + # Adds one more direct build request for this targets. If later generate + # is called with the same non-free non-incidental properties as in one + # of direct build requests, then that build request is used instead. + rule direct-build-request ( properties * ) + { + } + # Takes properties in split form ("foo bar"). # Generates virtual targets for this abstract targets which are matching # 'properties' as closely as possible. It 'properties' are not specified, @@ -78,15 +85,30 @@ rule project-target ( name : project : requirements * : default-build * ) self.requirements = $(requirements) ; self.default-build = $(default-build) ; + rule direct-build-request ( properties * ) + { + for local name in $(self.main-targets) + { + local t = [ main-target $(name) ] ; + result += [ $(t).direct-build-request $(properties) ] ; + } + for local pn in [ project.attribute $(self.project) projects-to-build ] + { + local p = [ project.module-name $(pn) ] ; + local t = [ project.target [ project.attribute $(p) location ] ] ; + result += [ $(t).direct-build-request $(properties) ] ; + } + } + # Generates all possible targets contained in this project. rule generate ( properties * ) { # Project properties are directly imposed on all main targets. # However, we'd need to check if this project can be build at # all. - local properties = + local xproperties = [ property.refine $(properties) : $(self.requirements) ] ; - if $(properties[1]) = "@error" + if $(xproperties[1]) = "@error" { local id = [ project.attribute $(self.project) id ] ; if $(id) @@ -156,12 +178,34 @@ rule main-target ( name : project ) self.alternatives += $(target) ; } + rule direct-build-request ( properties * ) + { + local base = [ property.remove free incidental : $(properties) ] ; + local ep = $(self.direct-request.$(base:J=-)) ; + if $(ep) && $(ep) != $(properties) + { + error "Conflicting direct build requests" $(ep) "and" $(properties) ; + } + else + { + self.direct-request.$(base:J=-) = $(properties) ; + } + } + + # Select an alternative for this main target, by finding all alternatives # which requirements are satisfied by 'properties' and picking the one with # longest requirements set. # Returns the result of calling 'generate' on that alternative. rule generate ( properties * ) { + local base = [ property.remove free incidental : $(properties) ] ; + local ep = $(self.direct-request.$(base:J=-)) ; + if $(ep) + { + properties = $(ep) ; + } + # Try to generate all the alternatives. local alternatives = [ new vector ] ; @@ -228,8 +272,16 @@ rule main-target ( name : project ) } # Add additional subvariant element for the targets which free, - # non-incidental properties are not equal to project's. - + # non-incidental properties are not equal to project's, plus + # those in build request + + # Note that free properties can appear on 'properties' only + # from direct build request, because free properties are not + # allowed to be propagated. + local ref = [ project.attribute $(self.project) requirements ] + $(properties) ; + ref = [ property.take free : [ property.remove incidental : $(ref) ] ] ; + local pr = [ property.take free : [ property.remove incidental : [ project.attribute $(self.project) requirements ] ] ] ; @@ -248,7 +300,7 @@ rule main-target ( name : project ) local properties = [ property.take free : [ property.remove incidental : [ $(action).properties ] ] ] ; - if $(properties) != $(pr) + if $(properties) != $(ref) { $(v).extra-path [ sequence.join main-target- $(self.name) ] ; } @@ -305,7 +357,8 @@ rule basic-target ( name : project return $(result) ; } else { - property-path = [ property.as-path $(properties) ] ; + property-path = [ property.as-path + [ property.remove free incidental : $(properties) ] ] ; if ! $(property-path) { property-path = X ; diff --git a/test/direct-request-test/Jamfile b/test/direct-request-test/Jamfile new file mode 100644 index 000000000..48541ca30 --- /dev/null +++ b/test/direct-request-test/Jamfile @@ -0,0 +1,9 @@ + +# This will link correctly only if symbol MACROS is defined when compiling +# b.cpp. However, this is only possible if that symbol is requested +# on command line and b.cpp is compiled with directly requested +# properties. + +exe a : a.cpp b ; + +lib b : b.cpp ; \ No newline at end of file diff --git a/test/direct-request-test/a.cpp b/test/direct-request-test/a.cpp new file mode 100644 index 000000000..aa4c32f18 --- /dev/null +++ b/test/direct-request-test/a.cpp @@ -0,0 +1,7 @@ + +void foo(); + +int main() +{ + foo(); +} \ No newline at end of file diff --git a/test/direct-request-test/b.cpp b/test/direct-request-test/b.cpp new file mode 100644 index 000000000..93137a0c9 --- /dev/null +++ b/test/direct-request-test/b.cpp @@ -0,0 +1,4 @@ + +#ifdef MACROS +void foo() {} +#endif \ No newline at end of file diff --git a/test/direct-request-test/project-root.jam b/test/direct-request-test/project-root.jam new file mode 100644 index 000000000..487eef980 --- /dev/null +++ b/test/direct-request-test/project-root.jam @@ -0,0 +1,2 @@ + +import gcc ; diff --git a/test/direct_request_test.py b/test/direct_request_test.py new file mode 100644 index 000000000..fd9d33f0d --- /dev/null +++ b/test/direct_request_test.py @@ -0,0 +1,15 @@ +#!/usr/bin/python + +from BoostBuild import Tester, List +import os +from string import strip + +t = Tester() + +# First check some startup +t.set_tree("direct-request-test") +t.run_build_system(extra_args="define=MACROS") + +t.expect_addition("bin/gcc/debug/shared-false/threading-single/" * List("a.o b.o b.a a")) + +t.cleanup() diff --git a/test/test_all.py b/test/test_all.py index 19e34050d..5c4dfdbcc 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -20,3 +20,4 @@ import project_test3 import project_test4 import generators_test import dependency_test +import direct_request_test diff --git a/v2/build/feature.jam b/v2/build/feature.jam index 22577e331..dd7545cab 100644 --- a/v2/build/feature.jam +++ b/v2/build/feature.jam @@ -65,13 +65,15 @@ rule feature ( { error = feature already defined: ; } - else if implicit in $(attributes) + else if implicit in $(attributes) && free in $(attributes) { - if free in $(attributes) - { - error = free features cannot also be implicit ; - } + error = free features cannot also be implicit ; } + else if free in $(attributes) && propagated in $(attributes) + { + error = free features cannot be propagated ; + } + if $(error) { @@ -846,6 +848,12 @@ local rule __test__ ( ) } catch free features cannot also be implicit ; + try ; + { + feature feature3 : : free propagated ; + } + catch free features cannot be propagated ; + try ; { implied-feature lackluster ; diff --git a/v2/build/targets.jam b/v2/build/targets.jam index 2d2afede7..d5419a9e3 100644 --- a/v2/build/targets.jam +++ b/v2/build/targets.jam @@ -56,6 +56,13 @@ rule abstract-target ( name # name of the target in Jamfile return $(location)/$(self.name) ; } + # Adds one more direct build request for this targets. If later generate + # is called with the same non-free non-incidental properties as in one + # of direct build requests, then that build request is used instead. + rule direct-build-request ( properties * ) + { + } + # Takes properties in split form ("foo bar"). # Generates virtual targets for this abstract targets which are matching # 'properties' as closely as possible. It 'properties' are not specified, @@ -78,15 +85,30 @@ rule project-target ( name : project : requirements * : default-build * ) self.requirements = $(requirements) ; self.default-build = $(default-build) ; + rule direct-build-request ( properties * ) + { + for local name in $(self.main-targets) + { + local t = [ main-target $(name) ] ; + result += [ $(t).direct-build-request $(properties) ] ; + } + for local pn in [ project.attribute $(self.project) projects-to-build ] + { + local p = [ project.module-name $(pn) ] ; + local t = [ project.target [ project.attribute $(p) location ] ] ; + result += [ $(t).direct-build-request $(properties) ] ; + } + } + # Generates all possible targets contained in this project. rule generate ( properties * ) { # Project properties are directly imposed on all main targets. # However, we'd need to check if this project can be build at # all. - local properties = + local xproperties = [ property.refine $(properties) : $(self.requirements) ] ; - if $(properties[1]) = "@error" + if $(xproperties[1]) = "@error" { local id = [ project.attribute $(self.project) id ] ; if $(id) @@ -156,12 +178,34 @@ rule main-target ( name : project ) self.alternatives += $(target) ; } + rule direct-build-request ( properties * ) + { + local base = [ property.remove free incidental : $(properties) ] ; + local ep = $(self.direct-request.$(base:J=-)) ; + if $(ep) && $(ep) != $(properties) + { + error "Conflicting direct build requests" $(ep) "and" $(properties) ; + } + else + { + self.direct-request.$(base:J=-) = $(properties) ; + } + } + + # Select an alternative for this main target, by finding all alternatives # which requirements are satisfied by 'properties' and picking the one with # longest requirements set. # Returns the result of calling 'generate' on that alternative. rule generate ( properties * ) { + local base = [ property.remove free incidental : $(properties) ] ; + local ep = $(self.direct-request.$(base:J=-)) ; + if $(ep) + { + properties = $(ep) ; + } + # Try to generate all the alternatives. local alternatives = [ new vector ] ; @@ -228,8 +272,16 @@ rule main-target ( name : project ) } # Add additional subvariant element for the targets which free, - # non-incidental properties are not equal to project's. - + # non-incidental properties are not equal to project's, plus + # those in build request + + # Note that free properties can appear on 'properties' only + # from direct build request, because free properties are not + # allowed to be propagated. + local ref = [ project.attribute $(self.project) requirements ] + $(properties) ; + ref = [ property.take free : [ property.remove incidental : $(ref) ] ] ; + local pr = [ property.take free : [ property.remove incidental : [ project.attribute $(self.project) requirements ] ] ] ; @@ -248,7 +300,7 @@ rule main-target ( name : project ) local properties = [ property.take free : [ property.remove incidental : [ $(action).properties ] ] ] ; - if $(properties) != $(pr) + if $(properties) != $(ref) { $(v).extra-path [ sequence.join main-target- $(self.name) ] ; } @@ -305,7 +357,8 @@ rule basic-target ( name : project return $(result) ; } else { - property-path = [ property.as-path $(properties) ] ; + property-path = [ property.as-path + [ property.remove free incidental : $(properties) ] ] ; if ! $(property-path) { property-path = X ; diff --git a/v2/test/direct-request-test/Jamfile b/v2/test/direct-request-test/Jamfile new file mode 100644 index 000000000..48541ca30 --- /dev/null +++ b/v2/test/direct-request-test/Jamfile @@ -0,0 +1,9 @@ + +# This will link correctly only if symbol MACROS is defined when compiling +# b.cpp. However, this is only possible if that symbol is requested +# on command line and b.cpp is compiled with directly requested +# properties. + +exe a : a.cpp b ; + +lib b : b.cpp ; \ No newline at end of file diff --git a/v2/test/direct-request-test/a.cpp b/v2/test/direct-request-test/a.cpp new file mode 100644 index 000000000..aa4c32f18 --- /dev/null +++ b/v2/test/direct-request-test/a.cpp @@ -0,0 +1,7 @@ + +void foo(); + +int main() +{ + foo(); +} \ No newline at end of file diff --git a/v2/test/direct-request-test/b.cpp b/v2/test/direct-request-test/b.cpp new file mode 100644 index 000000000..93137a0c9 --- /dev/null +++ b/v2/test/direct-request-test/b.cpp @@ -0,0 +1,4 @@ + +#ifdef MACROS +void foo() {} +#endif \ No newline at end of file diff --git a/v2/test/direct-request-test/project-root.jam b/v2/test/direct-request-test/project-root.jam new file mode 100644 index 000000000..487eef980 --- /dev/null +++ b/v2/test/direct-request-test/project-root.jam @@ -0,0 +1,2 @@ + +import gcc ; diff --git a/v2/test/direct_request_test.py b/v2/test/direct_request_test.py new file mode 100644 index 000000000..fd9d33f0d --- /dev/null +++ b/v2/test/direct_request_test.py @@ -0,0 +1,15 @@ +#!/usr/bin/python + +from BoostBuild import Tester, List +import os +from string import strip + +t = Tester() + +# First check some startup +t.set_tree("direct-request-test") +t.run_build_system(extra_args="define=MACROS") + +t.expect_addition("bin/gcc/debug/shared-false/threading-single/" * List("a.o b.o b.a a")) + +t.cleanup() diff --git a/v2/test/test_all.py b/v2/test/test_all.py index 19e34050d..5c4dfdbcc 100644 --- a/v2/test/test_all.py +++ b/v2/test/test_all.py @@ -20,3 +20,4 @@ import project_test3 import project_test4 import generators_test import dependency_test +import direct_request_test