diff --git a/src/build/generators.jam b/src/build/generators.jam index 8da0ad12a..8bfd5674e 100644 --- a/src/build/generators.jam +++ b/src/build/generators.jam @@ -624,10 +624,17 @@ local rule select-dependency-graph ( options ) rule construct ( project name ? : target-type multiple ? : properties * : sources + : allow-composing-generators ? ) { + local use-requirements ; if (.construct-stack) { ensure-type $(sources) ; + for local e in $(sources) + { + use-requirements += [ $(e).use-requirements ] ; + } } + properties += $(use-requirements) ; + properties = [ sequence.unique $(properties) ] ; .construct-stack += 1 ; diff --git a/src/build/project.jam b/src/build/project.jam index cd023b3c6..0bf3c513d 100644 --- a/src/build/project.jam +++ b/src/build/project.jam @@ -381,6 +381,8 @@ local rule initialize ( : [ $(pattributes).get default-build ] ; $(attributes).set requirements : [ $(pattributes).get requirements ] : exact ; + $(attributes).set use-requirements + : [ $(pattributes).get use-requirements ] : exact ; } } @@ -430,6 +432,15 @@ rule project-attributes ( location ) self.requirements = $(result) ; } } + else if $(attribute) = "use-requirements" + { + if [ property.remove free : $(specification) ] + { + errors.error "use-requirements" $($(real-pos2)) "have non-free properties" ; + } + self.use-requirements += [ property.translate-paths $(specification) + : $(self.location) ] ; + } else if $(attribute) = "source-location" { self.source-location = [ path.join $(self.location) $(specification) ] ; diff --git a/src/build/targets.jam b/src/build/targets.jam index 2caaa031d..5d6560719 100644 --- a/src/build/targets.jam +++ b/src/build/targets.jam @@ -34,6 +34,7 @@ import regex ; import property ; import errors ; import common ; +import errors ; # Base class for all abstract targets. @@ -331,7 +332,7 @@ class main-target : abstract-target ; # The second variant specifies additional properties that should be used # when building the target. rule basic-target ( name : project - : sources * : requirements * : default-build * ) + : sources * : requirements * : default-build * : use-requirements * ) { import build-request ; import virtual-target ; @@ -341,6 +342,7 @@ rule basic-target ( name : project self.sources = $(sources) ; self.requirements = $(requirements) ; self.default-build = $(default-build) ; + self.use-requirements = $(use-requirements) ; # Applies default-build if 'properties' are empty or # have only single element. @@ -396,9 +398,13 @@ rule basic-target ( name : project # Just a source file source-targets += [ virtual-target.from-file $(s) : $(self.project) ] ; } - } + } self.generated.$(property-path) = [ construct $(source-targets) : $(rproperties) ] ; + for local e in $(self.generated.$(property-path)) + { + $(e).set-use-requirements $(self.use-requirements) ; + } } else { @@ -460,14 +466,14 @@ rule basic-target ( name : project class basic-target : abstract-target ; -.args = 4 5 6 7 8 9 ; +.args = 5 6 7 8 9 ; # Creates a main target alternative of type 'class-name'. The ctor will be # passed 'target-name', 'project' and all trailing arguments. # If 'requirements-pos' and 'default-build-pos' are specified, the corresponding # trailing arguments will be specially processed. rule main-target-alternative ( target-name project class-name - : requirements-pos ? : default-build-pos ? + : requirements-pos ? : use-requirements-pos ? : default-build-pos ? : * ) { for local i in $(.args) @@ -478,10 +484,22 @@ rule main-target-alternative ( target-name project class-name if $(requirements-pos) { local real-pos = $(.args[$(requirements-pos)]) ; + local real-pos2 = $(.args[$(use-requirements-pos)]) ; local project-requirements = [ project.attribute $(project) requirements ] ; + local project-use-requirements = [ project.attribute $(project) use-requirements ] ; local loc = [ project.attribute $(project) location ] ; - local requirements = [ property.translate-paths $($(real-pos)) : $(loc) ] ; + local requirements = + [ property.translate-paths $($(real-pos)) : $(loc) ] ; + # Should have only free properties + if [ property.remove free : $($(real-pos2)) ] + { + errors.error "use-requirements" $($(real-pos2)) "have non-free properties" ; + } + + local use-requirements = + [ property.translate-paths $($(real-pos2)) : $(loc) ] ; + use-requirements += $(project-use-requirements) ; requirements = [ property.refine $(project-requirements) : $(requirements) ] ; if $(requirements[1]) = "@error" @@ -490,8 +508,9 @@ rule main-target-alternative ( target-name project class-name } else { - a$(real-pos) = $(requirements) ; + a$(real-pos) = $(requirements) $(use-requirements) ; } + a$(real-pos2) = $(use-requirements) ; } if $(default-build-pos) @@ -509,15 +528,15 @@ rule main-target-alternative ( target-name project class-name $(target).add-alternative [ new $(class-name) $(target-name) : $(project) - : $(a4) : $(a5) : $(a6) : $(a7) : $(a8) : $(a9) ] ; + : $(a5) : $(a6) : $(a7) : $(a8) : $(a9) ] ; } rule typed-target ( name : project : type - : sources * : requirements * : default-build * ) + : sources * : requirements * : default-build * : use-requirements * ) { basic-target.__init__ $(name) : $(project) - : $(sources) : $(requirements) : $(default-build) ; + : $(sources) : $(requirements) : $(default-build) : $(use-requirements) ; self.type = $(type) ; diff --git a/src/build/type.jam b/src/build/type.jam index af2fdc0b3..fcd7c6bbb 100644 --- a/src/build/type.jam +++ b/src/build/type.jam @@ -102,15 +102,16 @@ rule type ( suffix ) } -rule main-target-rule ( name : sources * : requirements * : default-build * ) +rule main-target-rule ( name : sources * : requirements * : default-build * + : use-requirements * ) { # First find requuired target type, which is equal to the name used to # invoke us. local bt = [ BACKTRACE 1 ] ; local type = $(bt[4]) ; - targets.main-target-alternative $(name) [ CALLER_MODULE ] typed-target : 3 : 4 - : $(type:U) : $(sources) : $(requirements) : $(default-build) + targets.main-target-alternative $(name) [ CALLER_MODULE ] typed-target : 3 : 5 : 4 + : $(type:U) : $(sources) : $(requirements) : $(default-build) : $(use-requirements) ; } diff --git a/src/build/virtual-target.jam b/src/build/virtual-target.jam index 5b86b9376..7ac6ca8c3 100644 --- a/src/build/virtual-target.jam +++ b/src/build/virtual-target.jam @@ -81,7 +81,18 @@ rule virtual-target ( name : type ? : project return $(self.root) ; } - + # Gets 'use' requirements. + rule use-requirements ( ) + { + return $(self.use-requirements) ; + } + + # Sets 'use' requirements + rule set-use-requirements ( requirements * ) + { + self.use-requirements = $(requirements) ; + } + # Sets the dependency graph this target is part of. # 'dg' is an instance of 'subvariant-dg' class. rule dg ( dg ? ) diff --git a/src/tools/make.jam b/src/tools/make.jam index 16bb9ee4a..217c76804 100644 --- a/src/tools/make.jam +++ b/src/tools/make.jam @@ -39,7 +39,7 @@ rule make ( target-name : sources * : generating-rule : requirements * ) # Default build is not specified: 'main-target-alternative' will take # care of it. targets.main-target-alternative - $(target-name) [ CALLER_MODULE ] make-target-class : 2 : 4 + $(target-name) [ CALLER_MODULE ] make-target-class : 2 : : 4 : $(sources) : $(requirements) : $(generating-rule) : $(default-build) ; } diff --git a/test/test_all.py b/test/test_all.py index 8351ee8b9..7d661e1b4 100644 --- a/test/test_all.py +++ b/test/test_all.py @@ -28,3 +28,5 @@ import no_type import chain import default_build import main_properties +import use_requirements + diff --git a/test/use_requirements.py b/test/use_requirements.py new file mode 100644 index 000000000..f398f6c63 --- /dev/null +++ b/test/use_requirements.py @@ -0,0 +1,64 @@ +#!/usr/bin/python + +from BoostBuild import Tester +t = Tester() + +# Test that use requirements on main target work +t.write("project-root.jam", "import gcc ;") +t.write("Jamfile", """ + lib b : b.cpp : : : FOO ; + exe a : a.cpp b ; +""") +t.write("b.cpp", "void foo() {}") +t.write("a.cpp", """ +#ifdef FOO +void foo() {} +#endif +int main() { foo(); } +""") + +t.run_build_system() + +t.run_build_system("--clean") + +# Test that use requirement on project work +t.write("Jamfile", "exe a : a.cpp lib/b ;") +t.write("lib/Jamfile", """ +project : + use-requirements FOO + ; +lib b : b.cpp ; +""") +t.write("lib/b.cpp", "void foo() {}") +t.run_build_system() + +# Test that use requirements are inherited correctly + +t.write("Jamfile", "exe a : a.cpp lib/1/b ;") + +t.write("a.cpp", """ +#if defined(FOO) && defined(ZOO) +void foo() {} +#endif +int main() { foo(); } +""") + +t.write("lib/Jamfile", """ +project : + use-requirements FOO + ; +""") + +t.write("lib/1/Jamfile", """ +project : + use-requirements ZOO + ; +lib b : b.cpp ; +""") +t.write("lib/1/b.cpp", "void foo() {}") + +t.run_build_system() + + + +t.cleanup()