diff --git a/new/boostbook.jam b/new/boostbook.jam index 2ba33d16d..fef2646dc 100644 --- a/new/boostbook.jam +++ b/new/boostbook.jam @@ -19,6 +19,7 @@ import property-set ; import regex ; import scanner ; import make ; +import type ; feature.feature xsl:param : : free ; feature.feature format : html onehtml man pdf ps docbook fo tests diff --git a/new/borland.jam b/new/borland.jam index 16f62e759..a37acc6f3 100644 --- a/new/borland.jam +++ b/new/borland.jam @@ -11,6 +11,8 @@ import property ; import generators ; import os ; import toolset : flags ; +import feature ; +import type ; toolset.register borland ; diff --git a/new/build-request.jam b/new/build-request.jam index 2df513c6a..78977e787 100644 --- a/new/build-request.jam +++ b/new/build-request.jam @@ -11,6 +11,7 @@ import property ; import numbers ; import container ; import class : class new ; +import string ; # Transform property-set by applying f to each component property. local rule apply-to-property-set ( f property-set ) @@ -21,29 +22,27 @@ local rule apply-to-property-set ( f property-set ) # expand the given build request by combining all property-sets which don't # specify conflicting non-free features. -rule expand-no-defaults ( property-sets * : feature-space ? ) +rule expand-no-defaults ( property-sets * ) { - feature-space ?= feature ; - # First make all features and subfeatures explicit local expanded-property-sets = [ - sequence.transform apply-to-property-set $(feature-space).expand-subfeatures + sequence.transform apply-to-property-set feature.expand-subfeatures : $(property-sets) ] ; # Now combine all of the expanded property-sets local product = [ x-product $(expanded-property-sets) : $(feature-space) ] ; return [ - sequence.transform apply-to-property-set $(feature-space).expand-composites + sequence.transform apply-to-property-set feature.expand-composites : $(product) ] ; } # implementaiton of x-product, below -local rule x-product-aux ( property-sets + : feature-space ) +local rule x-product-aux ( property-sets + ) { local result ; local p = [ feature.split $(property-sets[1]) ] ; - local f = [ set.difference $(p:G) : [ $(feature-space).free-features ] ] ; + local f = [ set.difference $(p:G) : [ feature.free-features ] ] ; local seen ; # No conflict with things used at a higher level? if ! [ set.intersection $(f) : $(x-product-used) ] @@ -85,7 +84,7 @@ local rule x-product-aux ( property-sets + : feature-space ) # Return the cross-product of all elements of property-sets, less any # that would contain conflicting values for single-valued features. -local rule x-product ( property-sets * : feature-space ) +local rule x-product ( property-sets * ) { if $(property-sets).non-empty { @@ -100,9 +99,8 @@ local rule x-product ( property-sets * : feature-space ) # # Returns the result of 'expand-no-defaults' after appying feature default to it. # -rule expand ( property-sets * : feature-space ? ) +rule expand ( property-sets * ) { - feature-space ?= feature ; local expanded = [ expand-no-defaults $(property-sets) : $(feature-space) ] ; expanded ?= "" ; @@ -110,14 +108,14 @@ rule expand ( property-sets * : feature-space ? ) local result ; for local p in $(expanded) { - p = [ $(feature-space).split $(p) ] ; + p = [ feature.split $(p) ] ; if ! $(p) { p = ; } - p = [ $(feature-space).add-defaults $(p) ] ; + p = [ feature.add-defaults $(p) ] ; result += $(p:J=/) ; } return $(result) ; @@ -125,18 +123,17 @@ rule expand ( property-sets * : feature-space ? ) # Returns true if 'v' is either implicit value, or # the part before the first '-' symbol is implicit value -local rule looks-like-implicit-value ( v : feature-space ? ) +local rule looks-like-implicit-value ( v ) { - feature-space ?= feature ; - if [ $(feature-space).is-implicit-value $(v) ] + if [ feature.is-implicit-value $(v) ] { return true ; } else { local split = [ regex.split $(v) - ] ; - if [ $(feature-space).is-implicit-value $(split[1]) ] + if [ feature.is-implicit-value $(split[1]) ] { return true ; } @@ -149,11 +146,10 @@ local rule looks-like-implicit-value ( v : feature-space ? ) # Returns a vector of two vectors (where "vector" means container.jam's "vector"). # First is the set of targets specified in the command line, and second is # the set of requested build properties. -rule from-command-line ( command-line * : feature-space ? ) +rule from-command-line ( command-line * ) { local targets ; local properties ; - feature-space ?= feature ; command-line = $(command-line[2-]) ; for local e in $(command-line) @@ -179,7 +175,7 @@ rule from-command-line ( command-line * : feature-space ? ) # Converts one element of command line build request specification into # internal form. -local rule convert-command-line-element ( e : feature-space ) +local rule convert-command-line-element ( e ) { local result ; local parts = [ regex.split $(e) "/" ] ; @@ -227,6 +223,7 @@ local rule convert-command-line-element ( e : feature-space ) # targets. rule directly-requested-properties-adjuster { + import property-set ; self.empty-request-requirements = ; self.all-requests = [ new property-map ] ; rule add-requested-property-set ( property-set ) @@ -275,123 +272,111 @@ class directly-requested-properties-adjuster ; rule __test__ ( ) { import assert ; - import errors : try catch ; - import class ; - local test-space = [ class.new feature-space ] ; + feature.prepare-test build-request-test-temp ; + + import build-request ; + import build-request : expand-no-defaults : build-request.expand-no-defaults ; + import errors : try catch ; + import feature : feature subfeature ; - module $(test-space) + feature toolset : gcc msvc borland : implicit ; + subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 + 3.0 3.0.1 3.0.2 : optional ; + + feature variant : debug release : implicit composite ; + feature inlining : on off ; + feature "include" : : free ; + + feature stdlib : native stlport : implicit ; + + feature runtime-link : dynamic static : symmetric ; + + # empty build requests should expand to empty. + assert.result + : build-request.expand-no-defaults + ; + + assert.result gcc/debug/on/native/dynamic + : build-request.expand + ; + + assert.result + gcc/3.0.1/stlport/debug + msvc/stlport/debug + msvc/debug + + : build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug + ; + + assert.result + gcc/3.0.1/stlport/debug/on/dynamic + msvc/stlport/debug/on/dynamic + msvc/debug/on/native/dynamic + + : build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug + ; + + assert.result + gcc/3.0.1/stlport/debug + msvc/debug + debug/msvc/stlport + + : build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport + ; + + assert.result + gcc/3.0.1/stlport/debug/off + gcc/3.0.1/stlport/release/off + + : build-request.expand-no-defaults gcc-3.0.1/stlport debug release off + ; + + assert.result + a/b/c/gcc/3.0.1/stlport/debug/x/y/z + a/b/c/msvc/stlport/debug/x/y/z + a/b/c/msvc/debug/x/y/z + + : build-request.expand-no-defaults a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug x/y/z + ; + + local r ; + + r = [ build-request.from-command-line bjam debug runtime-link=dynamic ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : debug dynamic ; + + try ; { - local test-space = [ modules.peek build-request : test-space ] ; - - import build-request ; - import build-request : expand-no-defaults : build-request.expand-no-defaults ; - import errors : try catch ; - feature toolset : gcc msvc borland : implicit ; - subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 - 3.0 3.0.1 3.0.2 : optional ; - - feature variant : debug release : implicit composite ; - feature inlining : on off ; - feature "include" : : free ; - - feature stdlib : native stlport : implicit ; - - feature runtime-link : dynamic static : symmetric ; - - # empty build requests should expand to empty. - assert.result - : build-request.expand-no-defaults - : $(test-space) ; - - assert.result gcc/debug/on/native/dynamic - : build-request.expand - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug - msvc/stlport/debug - msvc/debug - - : build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug/on/dynamic - msvc/stlport/debug/on/dynamic - msvc/debug/on/native/dynamic - - : build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug - msvc/debug - debug/msvc/stlport - - : build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug/off - gcc/3.0.1/stlport/release/off - - : build-request.expand-no-defaults gcc-3.0.1/stlport debug release off - : $(test-space) ; - - assert.result - a/b/c/gcc/3.0.1/stlport/debug/x/y/z - a/b/c/msvc/stlport/debug/x/y/z - a/b/c/msvc/debug/x/y/z - - : build-request.expand-no-defaults a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug x/y/z - : $(test-space) ; - - local r ; - - r = [ build-request.from-command-line bjam debug runtime-link=dynamic - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : debug dynamic ; - - try ; - build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static - : $(test-space) ; - catch \"static\" is not a value of an implicit feature ; - - - r = [ build-request.from-command-line bjam -d2 --debug debug target - runtime-link=dynamic - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : target ; - assert.equal [ $(r).get-at 2 ] : debug dynamic ; - - r = [ build-request.from-command-line bjam debug - runtime-link=dynamic,static - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : debug dynamic static ; - - r = [ build-request.from-command-line bjam debug - gcc/runtime-link=dynamic,static - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : debug gcc/dynamic - gcc/static ; - - r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : msvc gcc/static - borland/static ; - - r = [ build-request.from-command-line bjam gcc-3.0 - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : gcc-3.0 ; - + build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ; } + catch \"static\" is not a value of an implicit feature ; + + + r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ; + assert.equal [ $(r).get-at 1 ] : target ; + assert.equal [ $(r).get-at 2 ] : debug dynamic ; + + r = [ build-request.from-command-line bjam debug runtime-link=dynamic,static ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : debug dynamic static ; + + r = [ build-request.from-command-line bjam debug gcc/runtime-link=dynamic,static ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : debug gcc/dynamic + gcc/static ; + + r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : msvc gcc/static + borland/static ; + + r = [ build-request.from-command-line bjam gcc-3.0 ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : gcc-3.0 ; + + feature.finish-test build-request-test-temp ; } diff --git a/new/builtin.jam b/new/builtin.jam index ae78ecbbb..388e09baa 100644 --- a/new/builtin.jam +++ b/new/builtin.jam @@ -8,6 +8,8 @@ import class : class new ; import feature : feature compose ; +import toolset : flags ; +import errors : error ; import type ; import scanner ; import generators ; @@ -15,10 +17,10 @@ import regex ; import virtual-target ; import os ; import prebuilt ; -import toolset : flags ; -import errors : error ; import symlink ; import alias ; +import property ; +import print ; # This feature is used to determine which OS we're on. # In future, this may become and @@ -147,11 +149,12 @@ variant release : speed off full propagated, because (i) free features cannot be propagated and # (ii) this is dangerous. -rule builtin.handle-ndebug ( property : properties * ) +rule handle-ndebug ( property : properties * ) { return NDEBUG ; } -feature.action speed : builtin.handle-ndebug ; + +feature.action speed : handle-ndebug ; rule searched-lib-target ( name @@ -306,6 +309,8 @@ actions quietly piecemeal response-file-2 rule c-scanner ( includes * ) { scanner.__init__ ; + + import regex virtual-target path scanner ; self.includes = $(includes) ; rule pattern ( ) @@ -457,6 +462,7 @@ generators.register [ new searched-lib-generator ] ; rule compile-action ( targets + : sources * : action-name : properties * ) { action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ; + import sequence ; # For all virtual targets for the same dependency graph as self, # i.e. which belong to the same main target, add their directories @@ -505,7 +511,8 @@ IMPORT $(__name__) : register-c-compiler : : generators.register-c-compiler ; rule link-action ( targets + : sources * : action-name : properties * ) { action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ; - + import path ; + # Find all libraries in sources, and properties # For each source/property-value, which is instance of searched-lib-target, # add appropriate or property. @@ -668,6 +675,6 @@ declare-type : RSP : rsp ; flags builtin.response-file FINDLIBS_ST ; flags builtin.response-file FINDLIBS_SA ; flags builtin.response-file LIBRARY_PATH ; -builtin.register-linker builtin.response-file : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : RSP ; +register-linker builtin.response-file : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : RSP ; diff --git a/new/class.jam b/new/class.jam index 65259b97e..1da068b31 100644 --- a/new/class.jam +++ b/new/class.jam @@ -80,10 +80,15 @@ local rule __init__ ( # initialization function. ) { + # pull the name of the class being initialized from the backtrace local bt = [ BACKTRACE 1 ] ; local class = [ MATCH ^(.*)[.]__init__$ : $(bt[4]) ] ; - assert.nonempty-variable class ; + if ! $(class) + { + import errors : error ; + error couldn't extract class name from backtrace ; + } # set the __class__ __class__ ?= $(class) ; @@ -106,7 +111,8 @@ local rule __init__ ( { if ! $($(b).__init__.called) { - errors.error $(class).$(class) failed to call base class constructor $(b).__init__ ; + import errors : error ; + error $(class).$(class) failed to call base class constructor $(b).__init__ ; } } # Make all the class' member rules available as qualified names @@ -220,14 +226,19 @@ rule instance ( name : class args * : * ) rule new ( class args * : * ) { .next-instance.$(class) ?= 1 ; - local name = object($(class))@$(.next-instance.$(class)) ; - instance $(name) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + local id = object($(class))@$(.next-instance.$(class)) ; + instance $(id) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + # import the instance's methods, with qualification, into the + # global namespace. + local methods = [ RULENAMES $(id) ] ; + IMPORT $(id) : $(methods) : : $(id).$(methods) ; + # bump the next unique object name .next-instance.$(class) = [ numbers.increment $(.next-instance.$(class)) ] ; # Return the name of the new instance. - return $(name) ; + return $(id) ; } rule bases ( class ) @@ -300,215 +311,212 @@ local rule typecheck ( x ) } } -rule __test__ ( ) +local rule __test__ ( ) { - module class.__test__ + import class : * ; + import assert ; + import errors : * ; + + # This will be the construction function for a class called + # 'myclass' + local rule myclass ( x_ * : y_ * ) { - import class : * ; - import assert ; - import errors : * ; - - # This will be the construction function for a class called - # 'myclass' - local rule myclass ( x_ * : y_ * ) + # set some instance variables + x = $(x_) ; + y = $(y_) ; + + rule set-x ( newx * ) { - # set some instance variables - x = $(x_) ; - y = $(y_) ; - - rule set-x ( newx * ) - { - x = $(newx) ; - } - - rule get-x ( ) + x = $(newx) ; + } + + rule get-x ( ) + { + return $(x) ; + } + + rule set-y ( newy * ) + { + y = $(newy) ; + } + + rule get-y ( ) + { + return $(y) ; + } + + rule f ( ) + { + return [ g $(x) ] ; + } + + rule g ( args * ) + { + if $(x) in $(y) { return $(x) ; } - - rule set-y ( newy * ) - { - y = $(newy) ; - } - - rule get-y ( ) + else if $(y) in $(x) { return $(y) ; } - - rule f ( ) + else { - return [ g $(x) ] ; - } - - rule g ( args * ) - { - if $(x) in $(y) - { - return $(x) ; - } - else if $(y) in $(x) - { - return $(y) ; - } - else - { - return ; - } - } - - rule get-class ( ) - { - return $(__class__) ; + return ; } } - class myclass ; - - local rule derived1 ( z_ ) + + rule get-class ( ) { - myclass.__init__ $(z_) : X ; - z = $(z_) ; - - # override g - rule g ( args * ) - { - return derived1.g ; - } - - rule h ( ) - { - return derived1.h ; - } - - rule get-z ( ) - { - return $(z) ; - } + return $(__class__) ; } - class derived1 : myclass ; - - local rule derived2 ( ) + } + class myclass ; + + local rule derived1 ( z_ ) + { + myclass.__init__ $(z_) : X ; + z = $(z_) ; + + # override g + rule g ( args * ) { - myclass.__init__ 1 : 2 ; - - # override g - rule g ( args * ) - { - return derived2.g ; - } - - rule get-x ( ) - { - # Test the ability to call base class functions with qualification. - return [ myclass.get-x ] ; - } + return derived1.g ; } - class derived2 : myclass ; - - local rule derived2a ( ) + + rule h ( ) { - derived2.__init__ ; + return derived1.h ; } - class derived2a : derived2 ; - - local rule expect_derived2 ( [derived2] x ) { } - - local rule bad_subclass ( ) + + rule get-z ( ) { - # fails to call base class __init__ function + return $(z) ; } - class bad_subclass : myclass ; - - local a = [ new myclass 3 4 5 : 4 5 ] ; - local b = [ new derived1 4 ] ; - local c = [ new derived2 ] ; - local d = [ new derived2 ] ; - local e = [ new derived2a ] ; - - expect_derived2 $(d) ; - expect_derived2 $(e) ; - - # argument checking is set up to call exit(1) directly on - # failure, and we can't hijack that with try, so we'd better - # not do this test by default. We could fix this by having - # errors look up and invoke the EXIT rule instead; EXIT can be - # hijacked ;-) - if --fail-typecheck in [ modules.peek : ARGV ] + } + class derived1 : myclass ; + + local rule derived2 ( ) + { + myclass.__init__ 1 : 2 ; + + # override g + rule g ( args * ) { - try ; - { - expect_derived2 $(a) ; - } - catch - "Expected an instance of derived2 but got" instead - ; + return derived2.g ; } - - + + rule get-x ( ) + { + # Test the ability to call base class functions with qualification. + return [ myclass.get-x ] ; + } + } + class derived2 : myclass ; + + local rule derived2a ( ) + { + derived2.__init__ ; + } + class derived2a : derived2 ; + + local rule expect_derived2 ( [derived2] x ) { } + + local rule bad_subclass ( ) + { + # fails to call base class __init__ function + } + class bad_subclass : myclass ; + + local a = [ new myclass 3 4 5 : 4 5 ] ; + local b = [ new derived1 4 ] ; + local c = [ new derived2 ] ; + local d = [ new derived2 ] ; + local e = [ new derived2a ] ; + + expect_derived2 $(d) ; + expect_derived2 $(e) ; + + # argument checking is set up to call exit(1) directly on + # failure, and we can't hijack that with try, so we'd better + # not do this test by default. We could fix this by having + # errors look up and invoke the EXIT rule instead; EXIT can be + # hijacked (;-) + if --fail-typecheck in [ modules.peek : ARGV ] + { try ; { - new bad_subclass ; + expect_derived2 $(a) ; } catch - bad_subclass.bad_subclass failed to call base class constructor myclass.__init__ + "Expected an instance of derived2 but got" instead ; - - try ; - { - class bad_subclass ; - } - catch bad_subclass has already been declared ; - - assert.result 3 4 5 : $(a).get-x ; - assert.result 4 5 : $(a).get-y ; - assert.result 4 : $(b).get-x ; - assert.result X : $(b).get-y ; - assert.result 4 : $(b).get-z ; - assert.result 1 : $(c).get-x ; - assert.result 2 : $(c).get-y ; - assert.result 4 5 : $(a).f ; - assert.result derived1.g : $(b).f ; - assert.result derived2.g : $(c).f ; - assert.result derived2.g : $(d).f ; - - # Check that the __class__ attribute is getting properly set. - assert.result myclass : $(a).get-class ; - assert.result derived1 : $(b).get-class ; - - $(a).set-x a.x ; - $(b).set-x b.x ; - $(c).set-x c.x ; - $(d).set-x d.x ; - assert.result a.x : $(a).get-x ; - assert.result b.x : $(b).get-x ; - assert.result c.x : $(c).get-x ; - assert.result d.x : $(d).get-x ; - - rule derived3 ( ) - { - } - class derived3 : derived1 derived2 ; - - assert.result : bases myclass ; - assert.result myclass : bases derived1 ; - assert.result myclass : bases derived2 ; - assert.result derived1 derived2 : bases derived3 ; - - assert.true is-derived derived1 : myclass ; - assert.true is-derived derived2 : myclass ; - assert.true is-derived derived3 : derived1 ; - assert.true is-derived derived3 : derived2 ; - assert.true is-derived derived3 : derived1 derived2 myclass ; - assert.true is-derived derived3 : myclass ; - - assert.false is-derived myclass : derived1 ; - - assert.true is-instance $(a) ; - assert.false is-instance bar ; - - assert.true is-a $(a) : myclass ; - assert.true is-a $(c) : derived2 ; - assert.true is-a $(d) : myclass ; - assert.false is-a literal : myclass ; } + + + try ; + { + new bad_subclass ; + } + catch + bad_subclass.bad_subclass failed to call base class constructor myclass.__init__ + ; + + try ; + { + class bad_subclass ; + } + catch bad_subclass has already been declared ; + + assert.result 3 4 5 : $(a).get-x ; + assert.result 4 5 : $(a).get-y ; + assert.result 4 : $(b).get-x ; + assert.result X : $(b).get-y ; + assert.result 4 : $(b).get-z ; + assert.result 1 : $(c).get-x ; + assert.result 2 : $(c).get-y ; + assert.result 4 5 : $(a).f ; + assert.result derived1.g : $(b).f ; + assert.result derived2.g : $(c).f ; + assert.result derived2.g : $(d).f ; + + # Check that the __class__ attribute is getting properly set. + assert.result myclass : $(a).get-class ; + assert.result derived1 : $(b).get-class ; + + $(a).set-x a.x ; + $(b).set-x b.x ; + $(c).set-x c.x ; + $(d).set-x d.x ; + assert.result a.x : $(a).get-x ; + assert.result b.x : $(b).get-x ; + assert.result c.x : $(c).get-x ; + assert.result d.x : $(d).get-x ; + + rule derived3 ( ) + { + } + class derived3 : derived1 derived2 ; + + assert.result : bases myclass ; + assert.result myclass : bases derived1 ; + assert.result myclass : bases derived2 ; + assert.result derived1 derived2 : bases derived3 ; + + assert.true is-derived derived1 : myclass ; + assert.true is-derived derived2 : myclass ; + assert.true is-derived derived3 : derived1 ; + assert.true is-derived derived3 : derived2 ; + assert.true is-derived derived3 : derived1 derived2 myclass ; + assert.true is-derived derived3 : myclass ; + + assert.false is-derived myclass : derived1 ; + + assert.true is-instance $(a) ; + assert.false is-instance bar ; + + assert.true is-a $(a) : myclass ; + assert.true is-a $(c) : derived2 ; + assert.true is-a $(d) : myclass ; + assert.false is-a literal : myclass ; } \ No newline at end of file diff --git a/new/container.jam b/new/container.jam index 79c239edf..09b96ca67 100644 --- a/new/container.jam +++ b/new/container.jam @@ -6,9 +6,6 @@ # Various container classes. import class : * ; -import sequence ; -import utility ; - # Base for container objects. This lets us construct recursive structures. # That is containers with containers in them, specifically so we can tell @@ -46,6 +43,8 @@ rule vector ( ) { import numbers : range ; + import utility ; + import sequence ; node.__init__ ; self.value = $(values) ; @@ -246,6 +245,7 @@ module class@vector local rule __test__ ( ) { import assert ; + import class : new ; local l = [ new vector ] ; assert.result 0 : $(l).size ; diff --git a/new/feature.jam b/new/feature.jam index 883fde241..2fac9177e 100644 --- a/new/feature.jam +++ b/new/feature.jam @@ -5,34 +5,73 @@ import class : * ; -# A feature-space is a class to facilitate testing. We want to be able -# to make and populate instances of a feature-space for testing -# purposes without intruding on the default feature-space -local rule feature-space ( ) -{ import errors : error lol->list ; import sequence ; import regex ; import set ; import utility ; +import modules ; -.all-attributes = +local rule setup ( ) +{ + .all-attributes = - implicit - executed - composite - optional - symmetric - free - incidental - path - dependency - propagated - link-incompatible - ; + implicit + executed + composite + optional + symmetric + free + incidental + path + dependency + propagated + link-incompatible + ; + + .all-features = ; + .all-implicit-values = ; +} +setup ; + +# prepare a fresh space to test in by moving all global variable +# settings into the given temporary module and erasing them here. +rule prepare-test ( temp-module ) +{ + DELETE_MODULE $(temp-module) ; + + # transfer globals to temp-module + for local v in [ VARNAMES feature ] + { + if [ MATCH (\\.) : $(v) ] + { + modules.poke $(temp-module) : $(v) : $($(v)) ; + $(v) = ; + } + } + setup ; +} + +# clear out all global variables and recover all variables from the +# given temporary module +rule finish-test ( temp-module ) +{ + # clear globals + for local v in [ VARNAMES feature ] + { + if [ MATCH (\\.) : $(v) ] + { + $(v) = ; + } + } + + for local v in [ VARNAMES $(temp-module) ] + { + $(v) = [ modules.peek $(temp-module) : $(v) ] ; + } + DELETE_MODULE $(temp-module) ; +} -.all-features = ; -.all-implicit-values = ; # Transform features by bracketing any elements which aren't already # bracketed by "<>" @@ -79,7 +118,7 @@ rule feature ( { error $(error) : "in" feature declaration: - : feature [ errors.lol->list $(1) : $(2) : $(3) ] ; + : feature [ lol->list $(1) : $(2) : $(3) ] ; } $(name).values ?= ; @@ -808,17 +847,8 @@ rule split ( property-set ) # value, and feature should be specified as . rule action ( property-or-feature : rule-name ) { - # Is the name in global scope - if ! $(rule-name) in [ RULENAMES ] - { - # No, should be in caller's scope - local caller = [ CALLER_MODULE ] ; - if ! $(rule-name) in [ RULENAMES $(caller) ] - { - error "invalid rule name" ; - } - rule-name = $(caller).$(rule-name) ; - } + local caller = [ CALLER_MODULE ] ; + rule-name = $(caller).$(rule-name) ; .rules.$(property-or-feature) += $(rule-name) ; } @@ -841,224 +871,219 @@ rule run-actions ( properties * ) } for local r in $(rules) { - added += [ $(r) $(e) : $(properties) ] ; + added += [ modules.call-locally $(r) $(e) : $(properties) ] ; } } return $(properties) $(added) ; } -} -class feature-space ; - -# Tricky: makes this module into an instance of feature-space so that -# normally users work with the global feature-space without having to -# be aware that it's a class instance. -instance feature : feature-space ; - # tests of module feature local rule __test__ ( ) { - local test-space = [ new feature-space ] ; + # use a fresh copy of the feature module + prepare-test feature-test-temp ; - module $(test-space) + # This is a local rule and so must be explicitly reimported into + # the testing module + import feature : extend-feature validate-feature ; + + import errors : try catch ; + import assert ; + + feature toolset : gcc : implicit ; + feature define : : free ; + feature runtime-link : dynamic static : symmetric ; + feature optimization : on off ; + feature variant : debug release : implicit composite ; + feature stdlib : native stlport ; + feature magic : : free ; + + compose debug : _DEBUG off ; + compose release : NDEBUG on ; + + extend-feature toolset : msvc metrowerks ; + subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 + 3.0 3.0.1 3.0.2 : optional ; + + local rule handle-stlport ( property : properties * ) { - import errors : try catch ; - import assert ; - - feature toolset : gcc : implicit ; - feature define : : free ; - feature runtime-link : dynamic static : symmetric ; - feature optimization : on off ; - feature variant : debug release : implicit composite ; - feature stdlib : native stlport ; - feature magic : : free ; - - compose debug : _DEBUG off ; - compose release : NDEBUG on ; - - extend-feature toolset : msvc metrowerks ; - subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 - 3.0 3.0.1 3.0.2 : optional ; - - rule handle-stlport ( property : properties * ) - { - return /path/to/stlport ; - } - - rule handle-magic ( property : properties * ) - { - return MAGIC=$(property:G=) ; - } - - rule handle-magic2 ( property : properties * ) - { - return MAGIC=BIG_MAGIC ; - } - - rule handle-magic3 ( property : properties * ) - { - return MAGIC=VERY_BIG_MAGIC ; - } - - - - action stlport : handle-stlport ; - action : handle-magic ; - action 17 : handle-magic2 ; - action 17 : handle-magic3 ; - - assert.result gcc 3.0.1 - : expand-subfeatures gcc-3.0.1 ; - - assert.result foo=x-y - : expand-subfeatures foo=x-y ; - - assert.result gcc 3.0.1 - : expand-subfeatures gcc-3.0.1 ; - - feature dummy : dummy1 dummy2 ; - subfeature dummy : subdummy : x y z : optional ; - - assert.result a c e - : get-values x : a b c d e ; - - assert.result gcc 3.0.1 - debug _DEBUG on - : expand gcc-3.0.1 debug on - ; - - assert.result debug _DEBUG on - : expand debug on - ; - - assert.result on debug _DEBUG - : expand on debug - ; - - assert.result dynamic on - : defaults - ; - - assert.result static foobar on gcc:FOO - gcc debug native dummy1 - : add-defaults static foobar on gcc:FOO - ; - - assert.result gcc foo stlport 3 /path/to/stlport MAGIC=3 - : run-actions gcc foo stlport 3 - ; - - assert.result 17 MAGIC=BIG_MAGIC MAGIC=VERY_BIG_MAGIC - : run-actions 17 - ; - - - assert.result gcc-3.0.1 debug on - : minimize [ expand gcc-3.0.1 debug on native ] - ; - - assert.result gcc-3.0.1 debug dynamic - : minimize [ expand gcc-3.0.1 debug off dynamic ] - ; - - assert.result gcc-3.0.1 debug - : minimize [ expand gcc-3.0.1 debug off ] - ; - - assert.result debug on - : minimize [ expand debug on ] - ; - - assert.result gcc-3.0 - : minimize gcc 3.0 - ; - - assert.result gcc-3.0 - : minimize 3.0 gcc - ; - - assert.result y/z b/c e/f - : split y/z/b/c/e/f - ; - - assert.result y/z b/c e/f - : split y\\z\\b\\c\\e\\f - ; - - assert.result a b c e/f/g i/j/k - : split a/b/c/e/f/g/i/j/k - ; - - assert.result a b c e/f/g i/j/k - : split a\\b\\c\\e\\f\\g\\i\\j\\k - ; - - # test error checking - - try ; - { - expand release off on ; - } - catch explicitly-specified values of non-free feature conflict ; - - try ; - { - validate-feature foobar ; - } - catch unknown feature ; - - validate-value-string gcc ; - validate-value-string gcc-3.0.1 ; - - try ; - { - validate-value-string digital_mars ; - } - catch \"digital_mars\" is not a known value of ; - - try ; - { - feature foobar : : baz ; - } - catch unknown attributes: baz ; - - feature feature1 ; - try ; - { - feature feature1 ; - } - catch feature already defined: ; - - try ; - { - feature feature2 : : free implicit ; - } - catch free features cannot also be implicit ; - - try ; - { - feature feature3 : : free propagated ; - } - catch free features cannot be propagated ; - - try ; - { - implied-feature lackluster ; - } - catch \"lackluster\" is not a value of an implicit feature ; - - try ; - { - implied-subfeature toolset 3.0.1 ; - } - catch \"3.0.1\" is not a known subfeature value of - feature ; - - try ; - { - implied-subfeature toolset not-a-version : gcc ; - } - catch \"not-a-version\" is not a known subfeature value of - feature ; + return /path/to/stlport ; } + + local rule handle-magic ( property : properties * ) + { + return MAGIC=$(property:G=) ; + } + + local rule handle-magic2 ( property : properties * ) + { + return MAGIC=BIG_MAGIC ; + } + + local rule handle-magic3 ( property : properties * ) + { + return MAGIC=VERY_BIG_MAGIC ; + } + + action stlport : handle-stlport ; + action : handle-magic ; + action 17 : handle-magic2 ; + action 17 : handle-magic3 ; + + assert.result gcc 3.0.1 + : expand-subfeatures gcc-3.0.1 ; + + assert.result foo=x-y + : expand-subfeatures foo=x-y ; + + assert.result gcc 3.0.1 + : expand-subfeatures gcc-3.0.1 ; + + feature dummy : dummy1 dummy2 ; + subfeature dummy : subdummy : x y z : optional ; + + assert.result a c e + : get-values x : a b c d e ; + + assert.result gcc 3.0.1 + debug _DEBUG on + : expand gcc-3.0.1 debug on + ; + + assert.result debug _DEBUG on + : expand debug on + ; + + assert.result on debug _DEBUG + : expand on debug + ; + + assert.result dynamic on + : defaults + ; + + assert.result static foobar on gcc:FOO + gcc debug native dummy1 + : add-defaults static foobar on gcc:FOO + ; + + assert.result gcc foo stlport 3 /path/to/stlport MAGIC=3 + : run-actions gcc foo stlport 3 + ; + + assert.result 17 MAGIC=BIG_MAGIC MAGIC=VERY_BIG_MAGIC + : run-actions 17 + ; + + + assert.result gcc-3.0.1 debug on + : minimize [ expand gcc-3.0.1 debug on native ] + ; + + assert.result gcc-3.0.1 debug dynamic + : minimize [ expand gcc-3.0.1 debug off dynamic ] + ; + + assert.result gcc-3.0.1 debug + : minimize [ expand gcc-3.0.1 debug off ] + ; + + assert.result debug on + : minimize [ expand debug on ] + ; + + assert.result gcc-3.0 + : minimize gcc 3.0 + ; + + assert.result gcc-3.0 + : minimize 3.0 gcc + ; + + assert.result y/z b/c e/f + : split y/z/b/c/e/f + ; + + assert.result y/z b/c e/f + : split y\\z\\b\\c\\e\\f + ; + + assert.result a b c e/f/g i/j/k + : split a/b/c/e/f/g/i/j/k + ; + + assert.result a b c e/f/g i/j/k + : split a\\b\\c\\e\\f\\g\\i\\j\\k + ; + + # test error checking + + try ; + { + expand release off on ; + } + catch explicitly-specified values of non-free feature conflict ; + + try ; + { + validate-feature foobar ; + } + catch unknown feature ; + + validate-value-string gcc ; + validate-value-string gcc-3.0.1 ; + + try ; + { + validate-value-string digital_mars ; + } + catch \"digital_mars\" is not a known value of ; + + try ; + { + feature foobar : : baz ; + } + catch unknown attributes: baz ; + + feature feature1 ; + try ; + { + feature feature1 ; + } + catch feature already defined: ; + + try ; + { + feature feature2 : : free implicit ; + } + catch free features cannot also be implicit ; + + try ; + { + feature feature3 : : free propagated ; + } + catch free features cannot be propagated ; + + try ; + { + implied-feature lackluster ; + } + catch \"lackluster\" is not a value of an implicit feature ; + + try ; + { + implied-subfeature toolset 3.0.1 ; + } + catch \"3.0.1\" is not a known subfeature value of + feature ; + + try ; + { + implied-subfeature toolset not-a-version : gcc ; + } + catch \"not-a-version\" is not a known subfeature value of + feature ; + + # leave a clean copy of the features module behind + finish-test feature-test-temp ; } diff --git a/new/gcc.jam b/new/gcc.jam index 8b4e525be..d90e6f86b 100644 --- a/new/gcc.jam +++ b/new/gcc.jam @@ -8,6 +8,7 @@ import property ; import generators ; import os ; import type ; +import feature ; feature.extend toolset : gcc ; feature.subfeature toolset gcc : version : : optional propagated link-incompatible ; diff --git a/new/generators.jam b/new/generators.jam index 970517822..2291ef4aa 100644 --- a/new/generators.jam +++ b/new/generators.jam @@ -44,7 +44,9 @@ import class : class new is-a ; import container : vector ; import numbers : range ; import utility : str equal ; -import set ; +import set sequence ; +import assert ; +import virtual-target ; if "--debug-generators" in [ modules.peek : ARGV ] { @@ -113,7 +115,10 @@ rule generator ( import utility : equal ; import feature ; import errors : error ; - + import sequence ; + import type ; + import virtual-target ; + self.id = $(id) ; self.composing = $(composing) ; self.source-types = $(source-types) ; diff --git a/new/make.jam b/new/make.jam index d55af4f47..e2f09bb57 100644 --- a/new/make.jam +++ b/new/make.jam @@ -17,6 +17,8 @@ import property-set ; rule make-target-class ( name : project : sources * : requirements * : make-rule + : default-build * ) { + import type regex virtual-target ; + basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements) : $(default-build) ; @@ -33,7 +35,6 @@ rule make-target-class ( name : project : sources * : requirements * return [ virtual-target.register $(t) ] ; } } - class make-target-class : basic-target ; rule make ( target-name : sources * : generating-rule + : requirements * diff --git a/new/modules.jam b/new/modules.jam index b906da2f3..c8e0cc5ad 100644 --- a/new/modules.jam +++ b/new/modules.jam @@ -17,11 +17,12 @@ # meant to be invoked from import when no __test__ rule is defined in a given # module -local rule no_test_defined +local rule no-test-defined { - if ! ( --quiet in [ peek : ARGV ] ) + import modules ; + if ! ( --quiet in [ modules.peek : ARGV ] ) { - ECHO warning: no __test__ rule defined in module [ CALLER_MODULE ] ; + ECHO warning: no __test__ rule defined in module $(__module__) ; } } @@ -66,6 +67,21 @@ rule call-in ( module-name ? : rule-name args * : * ) } } +# Given a possibly qualified rule name and arguments, remove any +# initial module qualification from the rule and invoke it in that +# module. If there is no module qualification, the rule is invoked in +# the global module. +rule call-locally ( qualified-rule-name args * : * ) +{ + local module-rule = [ MATCH (.*)\\.(.*) : $(qualified-rule-name) ] ; + local rule-name = $(module-rule[2]) ; + rule-name ?= $(qualified-rule-name) ; + return [ + call-in $(module-rule[1]) + : $(rule-name) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) + ] ; +} + # load the indicated module if it is not already loaded. rule load ( module-name # name of module to load. Rules will be defined in this module @@ -97,7 +113,7 @@ rule load ( module $(module-name) { # Prepare a default behavior, in case no __test__ is defined. - IMPORT modules : no_test_defined : $(__name__) : __test__ ; + IMPORT modules : no-test-defined : $(__name__) : __test__ ; # Add some grist so that the module will have a unique target name local module-target = $(__file__:G=module@) ; @@ -106,7 +122,12 @@ rule load ( search ?= [ modules.peek : BOOST_BUILD_PATH ] ; SEARCH on $(module-target) = $(search) ; BINDRULE on $(module-target) = modules.record-binding ; + include $(module-target) ; + + # Allow the module to see its own names with full qualification + local rules = [ RULENAMES $(__name__) ] ; + IMPORT $(__name__) : $(rules) : $(__name__) : $(__name__).$(rules) ; } # Pop the loading stack. Must happen before testing or we'll find a circular loading dependency @@ -127,8 +148,18 @@ rule load ( ECHO testing module $(m)... ; } - module $(m) + # execute the module's __test__ rule in its own module to + # eliminate the inadvertent effects of testing + # module dependencies (such as assert) on the module itself. + IMPORT $(m) : __test__ : __test-$(m)__ : __test__ : LOCALIZE ; + + # Import the rest of m's rules into __test-$(m)__ for easy access + IMPORT $(m) : [ RULENAMES $(m) ] : __test-$(m)__ : [ RULENAMES $(m) ] ; + module __test-$(m)__ { + # set up the name of the module we're testing + # so that no-test-defined can find it. + __module__ = $(1) ; __test__ ; } } @@ -138,9 +169,10 @@ rule load ( } else if $(module-name) in $(.loading) { - ECHO loading \"$(module-name)\" ; - ECHO circular module loading dependency: ; - EXIT $(.loading)" ->" $(module-name) ; + import errors ; + errors.error loading \"$(module-name)\" + : circular module loading dependency: + : $(.loading)" ->" $(module-name) ; } } @@ -159,26 +191,52 @@ rule record-binding ( module-target : binding ) # all rules from the indicated module are imported into the caller's # module. If rename-opt is supplied, it must have the same number of # elements as rules-opt. -rule import ( module-name : rules-opt * : rename-opt * ) +rule import ( module-names + : rules-opt * : rename-opt * ) { + if $(rules-opt) = * || ! $(rules-opt) + { + if $(rename-opt) + { + errors.error "rule aliasing is only available for explicit imports." ; + } + } + + if $(module-names[2]) && ( $(rules-opt) || $(rename-opt) ) + { + errors.error when loading multiple modules, no specific rules or renaming is allowed ; + } + local caller = [ CALLER_MODULE ] ; local caller-location ; if $(caller) { caller-location = [ binding $(caller) ] ; } - - load $(module-name) : : $(caller-location:D) [ modules.peek : BOOST_BUILD_PATH ] ; - local source-names = $(rules-opt) ; - if $(rules-opt) = * + for local m in $(module-names) { - source-names = [ RULENAMES $(module-name) ] ; - } + load $(m) : : $(caller-location:D) [ peek : BOOST_BUILD_PATH ] ; + local all-rules = [ RULENAMES $(m) ] ; - local target-names = $(rename-opt) ; - target-names ?= $(source-names) ; - IMPORT $(module-name) : $(source-names) : [ CALLER_MODULE ] : $(target-names) ; + # import all the rules with qualification + IMPORT $(m) : $(all-rules) : $(caller) : $(m).$(all-rules) ; + + if $(rules-opt) + { + local source-names ; + if $(rules-opt) = * + { + source-names = $(all-rules) ; + } + else + { + source-names = $(rules-opt) ; + } + local target-names = $(rename-opt) ; + target-names ?= $(source-names) ; + IMPORT $(m) : $(source-names) : $(caller) : $(target-names) ; + } + } } # Define exported copies in $(target-module) of all rules exported @@ -197,6 +255,11 @@ rule clone-rules ( IMPORT $(target-module) : $(rules) : : $(target-module).$(rules) ; } +# These rules need to be available in all modules to implement +# module loading itself and other fundamental operations. +local globalize = peek poke record-binding ; +IMPORT modules : $(globalize) : : modules.$(globalize) ; + local rule __test__ ( ) { import assert ; diff --git a/new/msvc.jam b/new/msvc.jam index 01d21f136..14c2c7d03 100755 --- a/new/msvc.jam +++ b/new/msvc.jam @@ -10,6 +10,7 @@ import type ; import toolset : flags ; import errors : error ; import feature : feature ; +import path ; import sequence : unique ; if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] diff --git a/new/os.jam b/new/os.jam index 1d2fb8465..57979ba87 100644 --- a/new/os.jam +++ b/new/os.jam @@ -16,6 +16,7 @@ import regex ; rule __test__ { + import assert ; rule identity ( args * ) { return $(args) ; } if ! ( --quiet in [ modules.peek : ARGV ] ) diff --git a/new/prebuilt.jam b/new/prebuilt.jam index 1fda260de..922c1f0fd 100644 --- a/new/prebuilt.jam +++ b/new/prebuilt.jam @@ -6,21 +6,18 @@ # This module defines a special generator, which handles targets with # property. It allows to use prebuilt targets. -import targets ; import class : class new ; -import property ; -import errors : error ; -import type : type ; -import regex ; -import feature ; import generators ; +import feature : feature ; -feature.feature file : : free path ; +feature file : : free path ; rule prebuilt-file-generator { generator.__init__ prebuilt-file-generator : : * : ; - + + import feature type errors path ; + rule run ( project name ? : property-set : sources * ) { local properties = [ $(property-set).raw ] ; diff --git a/new/project-root.jam b/new/project-root.jam index 240efd24e..70e968559 100644 --- a/new/project-root.jam +++ b/new/project-root.jam @@ -92,6 +92,9 @@ rule project-root-object ( location # The root location. ) { + import path ; + import set ; + # The module name of the project-root. self.module = project-root<$(location)> ; diff --git a/new/project.jam b/new/project.jam index 36cd430fb..6365eb619 100644 --- a/new/project.jam +++ b/new/project.jam @@ -16,12 +16,12 @@ import modules : peek poke ; import numbers ; import path ; import sequence ; -import targets ; import errors : error ; import project-root ; import print ; import class : class new ; import errors ; +import property-set ; # # Loads jamfile at the given location. After loading, project global @@ -415,6 +415,11 @@ rule register-id ( id : location ) # "requirements", "default-build", "source-location" and "projects-to-build". rule project-attributes ( location ) { + import property ; + import property-set ; + import errors ; + import path ; + self.location = $(location) ; # Set the named attribute from the specification given by the user. @@ -589,11 +594,14 @@ rule use ( id : location ) } # This module defines rules common to all projects -module project-rules { +module project-rules +{ rule project ( id ? : option1 * : option2 * : option3 * ) { import project ; + import path ; + local attributes = [ project.attributes $(__name__) ] ; if $(id) { @@ -619,6 +627,7 @@ module project-rules { rule use-project ( id : where ) { import project ; + import path ; local attributes = [ project.attributes $(__name__) ] ; project.use $(id) : [ path.root [ path.make $(where) ] [ $(attributes).get location ] ] ; diff --git a/new/property-set.jam b/new/property-set.jam index 691ae8a33..9a91e0497 100644 --- a/new/property-set.jam +++ b/new/property-set.jam @@ -21,6 +21,10 @@ import sequence ; # local rule property-set ( raw-properties * ) { + import feature ; + import property-set ; + import property ; + self.raw = $(raw-properties) ; for local p in $(raw-properties) @@ -177,10 +181,13 @@ rule create ( raw-properties * ) return $(.ps.$(key)) ; } -.empty = [ create ] ; - # Returns property-set with empty set of properties. rule empty ( ) { + if ! $(.empty) + { + .empty = [ create ] ; + } + return $(.empty) ; } diff --git a/new/property.jam b/new/property.jam index e0d4cc417..05897b440 100644 --- a/new/property.jam +++ b/new/property.jam @@ -8,7 +8,11 @@ import utility : ungrist ; import sequence : unique ; import errors : error ; import class : class ; - +import feature ; +import regex ; +import sequence ; +import set ; +import path ; # Refines 'properties' by overriding any elements for which a different # value is specified in 'requirements'. If the resulting property set @@ -17,10 +21,8 @@ import class : class ; # On success, returns properties. On error, returns a list which first # element is "@error" and the other elements compose the explanation # string. -rule refine ( properties * : requirements * : feature-space ? ) +rule refine ( properties * : requirements * ) { - feature-space ?= feature ; - local result ; local error ; @@ -38,7 +40,7 @@ rule refine ( properties * : requirements * : feature-space ? ) for local p in $(properties) { # No processing for free properties - if free in [ $(feature-space).attributes $(p:G) ] + if free in [ feature.attributes $(p:G) ] { result += $(p) ; } @@ -50,7 +52,7 @@ rule refine ( properties * : requirements * : feature-space ? ) local value = $(p:G=) ; if $(value) != $(required-value) { - if link-incompatible in [ $(feature-space).attributes $(p:G) ] + if link-incompatible in [ feature.attributes $(p:G) ] { error = @error link-incompatible properties $(p) and $(p:G)$(required-value) ; @@ -134,7 +136,7 @@ rule evaluate-conditionals ( properties * ) # Helper for as-path, below. Orders properties with the implicit ones # first, and within the two sections in alphabetical order of feature # name. -local rule path-order ( feature-space x y ) +local rule path-order ( x y ) { if $(y:G) && ! $(x:G) { @@ -148,8 +150,8 @@ local rule path-order ( feature-space x y ) { if ! $(x:G) { - x = [ $(feature-space).expand-subfeatures $(x) ] ; - y = [ $(feature-space).expand-subfeatures $(y) ] ; + x = [ feature.expand-subfeatures $(x) ] ; + y = [ feature.expand-subfeatures $(y) ] ; } if $(x[1]) < $(y[1]) @@ -160,19 +162,17 @@ local rule path-order ( feature-space x y ) } # Returns a path which represents the given expanded property set. -rule as-path ( properties * : feature-space ? ) +rule as-path ( properties * ) { - feature-space ?= feature ; - - local entry = .result.$(properties:J=-).$(feature-space) ; + local entry = .result.$(properties:J=-) ; if ! $($(entry)) { # trim redundancy - properties = [ $(feature-space).minimize $(properties) ] ; + properties = [ feature.minimize $(properties) ] ; # sort according to path-order - properties = [ sequence.insertion-sort $(properties) : path-order $(feature-space) ] ; + properties = [ sequence.insertion-sort $(properties) : path-order ] ; local components ; for local p in $(properties) @@ -195,22 +195,21 @@ rule as-path ( properties * : feature-space ? ) } # Exit with error if property is not valid. -local rule validate1 ( property : feature-space ? ) +local rule validate1 ( property ) { - feature-space ?= feature ; local msg ; if $(property:G) { local feature = [ ungrist $(property:G) ] ; # Ungrist for better error messages local value = $(property:G=) ; - if ! [ $(feature-space).valid $(feature) ] + if ! [ feature.valid $(feature) ] { msg = "unknown feature '$(feature)'" ; } - else if $(value) && ! free in [ $(feature-space).attributes $(feature) ] + else if $(value) && ! free in [ feature.attributes $(feature) ] { - $(feature-space).validate-value-string $(feature) $(value) ; + feature.validate-value-string $(feature) $(value) ; } else if ! $(value) { @@ -219,8 +218,8 @@ local rule validate1 ( property : feature-space ? ) } else { - local feature = [ $(feature-space).implied-feature $(property) ] ; - $(feature-space).validate-value-string $(feature) $(property) ; + local feature = [ feature.implied-feature $(property) ] ; + feature.validate-value-string $(feature) $(property) ; } if $(msg) { @@ -228,25 +227,24 @@ local rule validate1 ( property : feature-space ? ) } } -rule validate ( properties * : feature-space ? ) +rule validate ( properties * ) { for local p in $(properties) { - validate1 $(p) : $(feature-space) ; + validate1 $(p) ; } } -rule validate-property-sets ( property-sets * : feature-space ? ) +rule validate-property-sets ( property-sets * ) { for local s in $(property-sets) { - validate [ feature.split $(s) ] : $(feature-space) ; + validate [ feature.split $(s) ] ; } } # Makes a property set from 'specification', converting implicit values into # full properties. -# TODO: Might want to use 'feature-space' here as well as in other rules. rule make ( specification * ) { local result ; @@ -271,13 +269,12 @@ rule make ( specification * ) # Returns a property sets which include all the elements in 'properties' that # do not have attributes listed in 'attributes'. -rule remove ( attributes + : properties * : feature-space ? ) +rule remove ( attributes + : properties * ) { - feature-space ?= feature ; local result ; for local e in $(properties) { - if ! [ set.intersection $(attributes) : [ $(feature-space).attributes $(e:G) ] ] + if ! [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ] { result += $(e) ; } @@ -287,13 +284,12 @@ rule remove ( attributes + : properties * : feature-space ? ) # Returns a property set which include all properties in 'properties' that have # any of 'attributes'. -rule take ( attributes + : properties * : feature-space ? ) +rule take ( attributes + : properties * ) { - feature-space ?= feature ; local result ; for local e in $(properties) { - if [ set.intersection $(attributes) : [ $(feature-space).attributes $(e:G) ] ] + if [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ] { result += $(e) ; } @@ -392,6 +388,10 @@ rule translate-paths ( properties * : path ) # mapping rule property-map ( ) { + import numbers ; + import sequence ; + import errors : error ; + self.next-flag = 1 ; # Associate 'value' with 'properties' @@ -434,7 +434,7 @@ rule property-map ( ) $(matches) : $(match-ranks) ] ; if $(best[2]) { - errors.error "Ambiguous key" ; + error "Ambiguous key" ; } local original = $(self.value.$(best)) ; if $(value) @@ -450,29 +450,30 @@ class property-map ; local rule __test__ ( ) { - import class : new ; import errors : try catch ; + import feature ; + import feature : feature subfeature compose ; + + # local rules must be explicitly re-imported + import property : path-order ; + + feature.prepare-test property-test-temp ; - local test-space = [ new feature-space ] ; + feature toolset : gcc : implicit ; + subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 + 3.0 3.0.1 3.0.2 : optional ; + feature define : : free ; + feature runtime-link : dynamic static : symmetric link-incompatible ; + feature optimization : on off ; + feature variant : debug release : implicit composite ; + feature rtti : on off : link-incompatible ; - module $(test-space) - { - import assert ; - - feature toolset : gcc : implicit ; - subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 - 3.0 3.0.1 3.0.2 : optional ; - feature define : : free ; - feature runtime-link : dynamic static : symmetric link-incompatible ; - feature optimization : on off ; - feature variant : debug release : implicit composite ; - feature rtti : on off : link-incompatible ; - - compose debug : _DEBUG off ; - compose release : NDEBUG on ; - - } + compose debug : _DEBUG off ; + compose release : NDEBUG on ; + import assert ; + import class : new ; + validate gcc gcc-3.0.1 : $(test-space) ; validate gcc gcc-3.0.1 : $(test-space) ; @@ -587,6 +588,7 @@ local rule __test__ ( ) assert.result gcc,3.0 FOO : split-conditional gcc,3.0:FOO ; - + + feature.finish-test property-test-temp ; } diff --git a/new/scanner.jam b/new/scanner.jam index e61cc172f..ea04c17d7 100644 --- a/new/scanner.jam +++ b/new/scanner.jam @@ -27,7 +27,7 @@ # way, instead of relying on just target type. import class : class new ; -import property ; +import property virtual-target ; # Base scanner class. rule scanner ( ) @@ -116,6 +116,9 @@ rule hdrrule ( target : matches * ) local scanner = [ on $(target) return $(SCANNER) ] ; $(scanner).process $(target) : $(matches) ; } +# hdrrule must be available at global scope so that it can be invoked +# by header scanning +IMPORT scanner : hdrrule : : scanner.hdrrule ; diff --git a/new/sequence.jam b/new/sequence.jam index c3f86965b..2ef13c325 100644 --- a/new/sequence.jam +++ b/new/sequence.jam @@ -5,6 +5,7 @@ import assert ; import numbers ; +import modules ; # Note that algorithms in this module execute largely in the caller's # module namespace, so that local rules can be used as function @@ -225,7 +226,9 @@ local rule __test__ ( ) # use a unique module so we can test the use of local rules. module sequence.__test__ { - + import assert ; + import sequence ; + local rule is-even ( n ) { if $(n) in 0 2 4 6 8 diff --git a/new/stage.jam b/new/stage.jam index 885e13b53..3096b4f3c 100644 --- a/new/stage.jam +++ b/new/stage.jam @@ -24,13 +24,17 @@ import class : class new ; import property ; import errors : error ; import type : type ; +import type ; import regex ; +import generators ; rule stage-target-class ( name-and-dir : project : sources * : requirements * : default-build * ) { basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : $(requirements) : $(default-build) ; + import feature project type errors generators ; + rule construct ( source-targets * : property-set ) { local location = [ feature.get-values : @@ -92,6 +96,7 @@ type.register STAGED_EXE : : EXE ; rule stage-exe-generator { generator.__init__ stage-exe : EXE : STAGED_EXE ; + import type property-set modules ; rule run ( project name ? : property-set : source : multiple ? ) { diff --git a/new/symlink.jam b/new/symlink.jam index a8aa227b5..622817d87 100644 --- a/new/symlink.jam +++ b/new/symlink.jam @@ -6,16 +6,9 @@ # Defines the "symlink" special target. 'symlink' targets make symbolic links # to the sources. -import numbers ; -import targets ; -import virtual-target ; -import class ; -import property ; -import modules ; -import os ; -import feature ; +import targets modules path class os feature ; -count = 0 ; +.count = 0 ; feature.feature symlink-location : project-relative build-relative : incidental ; @@ -27,9 +20,11 @@ rule symlink-targets ( : sources * ) { + import numbers modules class property project ; + # Generate a fake name for now. Need unnamed targets eventually. - local c = [ modules.peek symlink : count ] ; - modules.poke symlink : count : [ numbers.increment $(c) ] ; + local c = [ modules.peek symlink : .count ] ; + modules.poke symlink : .count : [ numbers.increment $(c) ] ; local fake-name = symlink#$(c) ; basic-target.__init__ $(fake-name) : $(project) : $(sources) ; diff --git a/new/targets.jam b/new/targets.jam index 395deeb9f..e9b93c99f 100644 --- a/new/targets.jam +++ b/new/targets.jam @@ -73,14 +73,16 @@ import property ; import errors ; import common ; import property-set ; -import utility : ungrist ; - +import project ; +import feature ; # Base class for all abstract targets. rule abstract-target ( name # name of the target in Jamfile : project # the project module where the target is declared ) { + import project ; + # Note: it might seem that we don't need either name or project at all. # However, there are places where we really need it. One example is error # messages which should name problematic targets. Another is setting correct @@ -138,6 +140,10 @@ class abstract-target ; # Project target class (derived from 'abstract-target') rule project-target ( name : project : requirements * : default-build * ) { + import project targets ; + import path ; + import print ; + abstract-target.__init__ $(name) : $(project) ; self.requirements = $(requirements) ; @@ -248,11 +254,15 @@ class project-target : abstract-target ; # A named top-level target in Jamfile rule main-target ( name : project ) { - import errors : error ; - import numbers : range ; - abstract-target.__init__ $(name) : $(project) ; + import errors : error ; + import assert ; + import numbers : range ; + import sequence ; + import print ; + import build-request feature property-set ; + # Add a new alternative for this target rule add-alternative ( target ) { @@ -474,10 +484,12 @@ rule generate-dependencies ( property-set : project : generation-ps ) rule basic-target ( name : project : sources * : requirements * : default-build * : usage-requirements * ) { - import build-request ; - import virtual-target ; - abstract-target.__init__ $(name) : $(project) ; + + import build-request ; + import virtual-target targets ; + import property-set ; + import set sequence errors ; self.sources = $(sources) ; if ! $(requirements) { @@ -730,6 +742,8 @@ rule typed-target ( name : project : type basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ; + import generators ; + self.type = $(type) ; rule construct ( source-targets * : property-set ) @@ -747,7 +761,6 @@ rule typed-target ( name : project : type return $(r) ; } } - class typed-target : basic-target ; # Returns the requirement to use when declaring a main target, diff --git a/new/toolset.jam b/new/toolset.jam index d05d231ee..94e2147f0 100644 --- a/new/toolset.jam +++ b/new/toolset.jam @@ -9,11 +9,12 @@ import feature ; import numbers ; import errors : error ; import property ; +import path ; .flag-no = 1 ; # Initializes an additional toolset-like module. -# First load 'toolset-module' and then calls it's 'init' +# First load 'toolset-module' and then calls its 'init' # rule with trailing arguments rule using ( toolset-module : * ) { diff --git a/new/type.jam b/new/type.jam index 6a30712f8..e18581786 100644 --- a/new/type.jam +++ b/new/type.jam @@ -11,6 +11,8 @@ import generators : * ; import class : class new ; import errors ; import property ; +import scanner ; +import targets ; # The feature is optional so that it never implicitly added. # It's used only for internal purposes, and in all cases we diff --git a/new/virtual-target.jam b/new/virtual-target.jam index 80707b708..0119ab0ad 100644 --- a/new/virtual-target.jam +++ b/new/virtual-target.jam @@ -9,9 +9,7 @@ # if particular target should be created at all. import class : class new ; -import type ; -import property-set ; -import utility ; +import path property-set utility sequence errors ; # +--------------------------+ # | virtual-target | @@ -69,6 +67,8 @@ rule virtual-target ( name # Name of this target -- specifies the name of : project # Project to which this target belongs ) { + import virtual-target utility scanner ; + self.name = $(name) ; self.project = $(project) ; self.dependencies = ; @@ -92,7 +92,7 @@ rule virtual-target ( name # Name of this target -- specifies the name of return $(self.dependencies) ; } - # Generates all the actual targets and set ups build actions for + # Generates all the actual targets and sets up build actions for # this target. # # If 'scanner' is specified, creates an additional target @@ -134,7 +134,7 @@ rule virtual-target ( name # Name of this target -- specifies the name of # private: (overridables) - # Sets up build actions for 'target'. Should call appriate rules + # Sets up build actions for 'target'. Should call appropriate rules # and set target variables. rule actualize-action ( target ) { @@ -205,6 +205,7 @@ rule abstract-file-target ( name ) { virtual-target.__init__ $(name) : $(project) ; + import project regex sequence path type ; self.type = $(type) ; self.action = ; @@ -431,7 +432,8 @@ rule file-target ( ) { abstract-file-target.__init__ $(name) : $(type) : $(project) ; - + import common ; + rule actualize-location ( target ) { if $(self.path) @@ -530,7 +532,9 @@ rule remember-binding ( target : bound-path ) { .binding.$(target) = $(bound-path) ; } - +# virtual-target.remember-binding must be available in the global +# module in order to be invoked by the builtin binding process. +IMPORT virtual-target : remember-binding : : virtual-target.remember-binding ; # Class which represents an action. # Both 'targets' and 'sources' should list instances of 'virtual-target'. @@ -540,10 +544,18 @@ rule remember-binding ( target : bound-path ) # not establish dependency relationship, but should do everything else. rule action ( targets + : sources * : action-name + : property-set ? ) { + import type toolset property-set ; + self.targets = $(targets) ; self.sources = $(sources) ; self.action-name = $(action-name) ; + if ! [ MATCH (\\.) : $(action-name[1]) ] + { + local caller = [ CALLER_MODULE ] ; + self.action-name = $(caller).$(action-name[1]) $(action-name[2-]) ; + } + if ! $(property-set) { property-set = [ property-set.empty ] ; @@ -602,8 +614,14 @@ rule action ( targets + : sources * : action-name + : property-set ? ) toolset.set-target-variables $(self.action-name[1]) $(actual-targets) : $(properties) ; - $(self.action-name) - $(actual-targets) : $(self.actual-sources) : $(properties) ; + ECHO $(self.action-name) ; + + modules.call-locally $(self.action-name) + $(actual-targets) + : $(self.actual-sources) + : $(properties) + ; + # Since we set up creating action here, we also set up # action for cleaning up common.Clean clean : $(actual-targets) ; @@ -688,6 +706,8 @@ class null-action : action ; # TODO: passing project with all virtual targets starts to be annoying. rule from-file ( file : project ) { + import type ; # had to do this here to break a circular dependency + if $(.files.$(file).$(project)) { return $(.files.$(file).$(project)) ; @@ -904,6 +924,8 @@ local rule subvariant-dg ( main-target # The instance of main-target class : actual-properties # Actual used properties : virtual-targets * ) { + import sequence ; + self.main-target = $(main-target) ; self.properties = $(property-set) ; self.actual-properties = $(actual-properties) ; diff --git a/v2/boostbook.jam b/v2/boostbook.jam index 2ba33d16d..fef2646dc 100644 --- a/v2/boostbook.jam +++ b/v2/boostbook.jam @@ -19,6 +19,7 @@ import property-set ; import regex ; import scanner ; import make ; +import type ; feature.feature xsl:param : : free ; feature.feature format : html onehtml man pdf ps docbook fo tests diff --git a/v2/borland.jam b/v2/borland.jam index 16f62e759..a37acc6f3 100644 --- a/v2/borland.jam +++ b/v2/borland.jam @@ -11,6 +11,8 @@ import property ; import generators ; import os ; import toolset : flags ; +import feature ; +import type ; toolset.register borland ; diff --git a/v2/build/build-request.jam b/v2/build/build-request.jam index 2df513c6a..78977e787 100644 --- a/v2/build/build-request.jam +++ b/v2/build/build-request.jam @@ -11,6 +11,7 @@ import property ; import numbers ; import container ; import class : class new ; +import string ; # Transform property-set by applying f to each component property. local rule apply-to-property-set ( f property-set ) @@ -21,29 +22,27 @@ local rule apply-to-property-set ( f property-set ) # expand the given build request by combining all property-sets which don't # specify conflicting non-free features. -rule expand-no-defaults ( property-sets * : feature-space ? ) +rule expand-no-defaults ( property-sets * ) { - feature-space ?= feature ; - # First make all features and subfeatures explicit local expanded-property-sets = [ - sequence.transform apply-to-property-set $(feature-space).expand-subfeatures + sequence.transform apply-to-property-set feature.expand-subfeatures : $(property-sets) ] ; # Now combine all of the expanded property-sets local product = [ x-product $(expanded-property-sets) : $(feature-space) ] ; return [ - sequence.transform apply-to-property-set $(feature-space).expand-composites + sequence.transform apply-to-property-set feature.expand-composites : $(product) ] ; } # implementaiton of x-product, below -local rule x-product-aux ( property-sets + : feature-space ) +local rule x-product-aux ( property-sets + ) { local result ; local p = [ feature.split $(property-sets[1]) ] ; - local f = [ set.difference $(p:G) : [ $(feature-space).free-features ] ] ; + local f = [ set.difference $(p:G) : [ feature.free-features ] ] ; local seen ; # No conflict with things used at a higher level? if ! [ set.intersection $(f) : $(x-product-used) ] @@ -85,7 +84,7 @@ local rule x-product-aux ( property-sets + : feature-space ) # Return the cross-product of all elements of property-sets, less any # that would contain conflicting values for single-valued features. -local rule x-product ( property-sets * : feature-space ) +local rule x-product ( property-sets * ) { if $(property-sets).non-empty { @@ -100,9 +99,8 @@ local rule x-product ( property-sets * : feature-space ) # # Returns the result of 'expand-no-defaults' after appying feature default to it. # -rule expand ( property-sets * : feature-space ? ) +rule expand ( property-sets * ) { - feature-space ?= feature ; local expanded = [ expand-no-defaults $(property-sets) : $(feature-space) ] ; expanded ?= "" ; @@ -110,14 +108,14 @@ rule expand ( property-sets * : feature-space ? ) local result ; for local p in $(expanded) { - p = [ $(feature-space).split $(p) ] ; + p = [ feature.split $(p) ] ; if ! $(p) { p = ; } - p = [ $(feature-space).add-defaults $(p) ] ; + p = [ feature.add-defaults $(p) ] ; result += $(p:J=/) ; } return $(result) ; @@ -125,18 +123,17 @@ rule expand ( property-sets * : feature-space ? ) # Returns true if 'v' is either implicit value, or # the part before the first '-' symbol is implicit value -local rule looks-like-implicit-value ( v : feature-space ? ) +local rule looks-like-implicit-value ( v ) { - feature-space ?= feature ; - if [ $(feature-space).is-implicit-value $(v) ] + if [ feature.is-implicit-value $(v) ] { return true ; } else { local split = [ regex.split $(v) - ] ; - if [ $(feature-space).is-implicit-value $(split[1]) ] + if [ feature.is-implicit-value $(split[1]) ] { return true ; } @@ -149,11 +146,10 @@ local rule looks-like-implicit-value ( v : feature-space ? ) # Returns a vector of two vectors (where "vector" means container.jam's "vector"). # First is the set of targets specified in the command line, and second is # the set of requested build properties. -rule from-command-line ( command-line * : feature-space ? ) +rule from-command-line ( command-line * ) { local targets ; local properties ; - feature-space ?= feature ; command-line = $(command-line[2-]) ; for local e in $(command-line) @@ -179,7 +175,7 @@ rule from-command-line ( command-line * : feature-space ? ) # Converts one element of command line build request specification into # internal form. -local rule convert-command-line-element ( e : feature-space ) +local rule convert-command-line-element ( e ) { local result ; local parts = [ regex.split $(e) "/" ] ; @@ -227,6 +223,7 @@ local rule convert-command-line-element ( e : feature-space ) # targets. rule directly-requested-properties-adjuster { + import property-set ; self.empty-request-requirements = ; self.all-requests = [ new property-map ] ; rule add-requested-property-set ( property-set ) @@ -275,123 +272,111 @@ class directly-requested-properties-adjuster ; rule __test__ ( ) { import assert ; - import errors : try catch ; - import class ; - local test-space = [ class.new feature-space ] ; + feature.prepare-test build-request-test-temp ; + + import build-request ; + import build-request : expand-no-defaults : build-request.expand-no-defaults ; + import errors : try catch ; + import feature : feature subfeature ; - module $(test-space) + feature toolset : gcc msvc borland : implicit ; + subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 + 3.0 3.0.1 3.0.2 : optional ; + + feature variant : debug release : implicit composite ; + feature inlining : on off ; + feature "include" : : free ; + + feature stdlib : native stlport : implicit ; + + feature runtime-link : dynamic static : symmetric ; + + # empty build requests should expand to empty. + assert.result + : build-request.expand-no-defaults + ; + + assert.result gcc/debug/on/native/dynamic + : build-request.expand + ; + + assert.result + gcc/3.0.1/stlport/debug + msvc/stlport/debug + msvc/debug + + : build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug + ; + + assert.result + gcc/3.0.1/stlport/debug/on/dynamic + msvc/stlport/debug/on/dynamic + msvc/debug/on/native/dynamic + + : build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug + ; + + assert.result + gcc/3.0.1/stlport/debug + msvc/debug + debug/msvc/stlport + + : build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport + ; + + assert.result + gcc/3.0.1/stlport/debug/off + gcc/3.0.1/stlport/release/off + + : build-request.expand-no-defaults gcc-3.0.1/stlport debug release off + ; + + assert.result + a/b/c/gcc/3.0.1/stlport/debug/x/y/z + a/b/c/msvc/stlport/debug/x/y/z + a/b/c/msvc/debug/x/y/z + + : build-request.expand-no-defaults a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug x/y/z + ; + + local r ; + + r = [ build-request.from-command-line bjam debug runtime-link=dynamic ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : debug dynamic ; + + try ; { - local test-space = [ modules.peek build-request : test-space ] ; - - import build-request ; - import build-request : expand-no-defaults : build-request.expand-no-defaults ; - import errors : try catch ; - feature toolset : gcc msvc borland : implicit ; - subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 - 3.0 3.0.1 3.0.2 : optional ; - - feature variant : debug release : implicit composite ; - feature inlining : on off ; - feature "include" : : free ; - - feature stdlib : native stlport : implicit ; - - feature runtime-link : dynamic static : symmetric ; - - # empty build requests should expand to empty. - assert.result - : build-request.expand-no-defaults - : $(test-space) ; - - assert.result gcc/debug/on/native/dynamic - : build-request.expand - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug - msvc/stlport/debug - msvc/debug - - : build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug/on/dynamic - msvc/stlport/debug/on/dynamic - msvc/debug/on/native/dynamic - - : build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug - msvc/debug - debug/msvc/stlport - - : build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport - : $(test-space) ; - - assert.result - gcc/3.0.1/stlport/debug/off - gcc/3.0.1/stlport/release/off - - : build-request.expand-no-defaults gcc-3.0.1/stlport debug release off - : $(test-space) ; - - assert.result - a/b/c/gcc/3.0.1/stlport/debug/x/y/z - a/b/c/msvc/stlport/debug/x/y/z - a/b/c/msvc/debug/x/y/z - - : build-request.expand-no-defaults a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug x/y/z - : $(test-space) ; - - local r ; - - r = [ build-request.from-command-line bjam debug runtime-link=dynamic - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : debug dynamic ; - - try ; - build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static - : $(test-space) ; - catch \"static\" is not a value of an implicit feature ; - - - r = [ build-request.from-command-line bjam -d2 --debug debug target - runtime-link=dynamic - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : target ; - assert.equal [ $(r).get-at 2 ] : debug dynamic ; - - r = [ build-request.from-command-line bjam debug - runtime-link=dynamic,static - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : debug dynamic static ; - - r = [ build-request.from-command-line bjam debug - gcc/runtime-link=dynamic,static - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : debug gcc/dynamic - gcc/static ; - - r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : msvc gcc/static - borland/static ; - - r = [ build-request.from-command-line bjam gcc-3.0 - : $(test-space) ] ; - assert.equal [ $(r).get-at 1 ] : ; - assert.equal [ $(r).get-at 2 ] : gcc-3.0 ; - + build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ; } + catch \"static\" is not a value of an implicit feature ; + + + r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ; + assert.equal [ $(r).get-at 1 ] : target ; + assert.equal [ $(r).get-at 2 ] : debug dynamic ; + + r = [ build-request.from-command-line bjam debug runtime-link=dynamic,static ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : debug dynamic static ; + + r = [ build-request.from-command-line bjam debug gcc/runtime-link=dynamic,static ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : debug gcc/dynamic + gcc/static ; + + r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : msvc gcc/static + borland/static ; + + r = [ build-request.from-command-line bjam gcc-3.0 ] ; + assert.equal [ $(r).get-at 1 ] : ; + assert.equal [ $(r).get-at 2 ] : gcc-3.0 ; + + feature.finish-test build-request-test-temp ; } diff --git a/v2/build/feature.jam b/v2/build/feature.jam index 883fde241..2fac9177e 100644 --- a/v2/build/feature.jam +++ b/v2/build/feature.jam @@ -5,34 +5,73 @@ import class : * ; -# A feature-space is a class to facilitate testing. We want to be able -# to make and populate instances of a feature-space for testing -# purposes without intruding on the default feature-space -local rule feature-space ( ) -{ import errors : error lol->list ; import sequence ; import regex ; import set ; import utility ; +import modules ; -.all-attributes = +local rule setup ( ) +{ + .all-attributes = - implicit - executed - composite - optional - symmetric - free - incidental - path - dependency - propagated - link-incompatible - ; + implicit + executed + composite + optional + symmetric + free + incidental + path + dependency + propagated + link-incompatible + ; + + .all-features = ; + .all-implicit-values = ; +} +setup ; + +# prepare a fresh space to test in by moving all global variable +# settings into the given temporary module and erasing them here. +rule prepare-test ( temp-module ) +{ + DELETE_MODULE $(temp-module) ; + + # transfer globals to temp-module + for local v in [ VARNAMES feature ] + { + if [ MATCH (\\.) : $(v) ] + { + modules.poke $(temp-module) : $(v) : $($(v)) ; + $(v) = ; + } + } + setup ; +} + +# clear out all global variables and recover all variables from the +# given temporary module +rule finish-test ( temp-module ) +{ + # clear globals + for local v in [ VARNAMES feature ] + { + if [ MATCH (\\.) : $(v) ] + { + $(v) = ; + } + } + + for local v in [ VARNAMES $(temp-module) ] + { + $(v) = [ modules.peek $(temp-module) : $(v) ] ; + } + DELETE_MODULE $(temp-module) ; +} -.all-features = ; -.all-implicit-values = ; # Transform features by bracketing any elements which aren't already # bracketed by "<>" @@ -79,7 +118,7 @@ rule feature ( { error $(error) : "in" feature declaration: - : feature [ errors.lol->list $(1) : $(2) : $(3) ] ; + : feature [ lol->list $(1) : $(2) : $(3) ] ; } $(name).values ?= ; @@ -808,17 +847,8 @@ rule split ( property-set ) # value, and feature should be specified as . rule action ( property-or-feature : rule-name ) { - # Is the name in global scope - if ! $(rule-name) in [ RULENAMES ] - { - # No, should be in caller's scope - local caller = [ CALLER_MODULE ] ; - if ! $(rule-name) in [ RULENAMES $(caller) ] - { - error "invalid rule name" ; - } - rule-name = $(caller).$(rule-name) ; - } + local caller = [ CALLER_MODULE ] ; + rule-name = $(caller).$(rule-name) ; .rules.$(property-or-feature) += $(rule-name) ; } @@ -841,224 +871,219 @@ rule run-actions ( properties * ) } for local r in $(rules) { - added += [ $(r) $(e) : $(properties) ] ; + added += [ modules.call-locally $(r) $(e) : $(properties) ] ; } } return $(properties) $(added) ; } -} -class feature-space ; - -# Tricky: makes this module into an instance of feature-space so that -# normally users work with the global feature-space without having to -# be aware that it's a class instance. -instance feature : feature-space ; - # tests of module feature local rule __test__ ( ) { - local test-space = [ new feature-space ] ; + # use a fresh copy of the feature module + prepare-test feature-test-temp ; - module $(test-space) + # This is a local rule and so must be explicitly reimported into + # the testing module + import feature : extend-feature validate-feature ; + + import errors : try catch ; + import assert ; + + feature toolset : gcc : implicit ; + feature define : : free ; + feature runtime-link : dynamic static : symmetric ; + feature optimization : on off ; + feature variant : debug release : implicit composite ; + feature stdlib : native stlport ; + feature magic : : free ; + + compose debug : _DEBUG off ; + compose release : NDEBUG on ; + + extend-feature toolset : msvc metrowerks ; + subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 + 3.0 3.0.1 3.0.2 : optional ; + + local rule handle-stlport ( property : properties * ) { - import errors : try catch ; - import assert ; - - feature toolset : gcc : implicit ; - feature define : : free ; - feature runtime-link : dynamic static : symmetric ; - feature optimization : on off ; - feature variant : debug release : implicit composite ; - feature stdlib : native stlport ; - feature magic : : free ; - - compose debug : _DEBUG off ; - compose release : NDEBUG on ; - - extend-feature toolset : msvc metrowerks ; - subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 - 3.0 3.0.1 3.0.2 : optional ; - - rule handle-stlport ( property : properties * ) - { - return /path/to/stlport ; - } - - rule handle-magic ( property : properties * ) - { - return MAGIC=$(property:G=) ; - } - - rule handle-magic2 ( property : properties * ) - { - return MAGIC=BIG_MAGIC ; - } - - rule handle-magic3 ( property : properties * ) - { - return MAGIC=VERY_BIG_MAGIC ; - } - - - - action stlport : handle-stlport ; - action : handle-magic ; - action 17 : handle-magic2 ; - action 17 : handle-magic3 ; - - assert.result gcc 3.0.1 - : expand-subfeatures gcc-3.0.1 ; - - assert.result foo=x-y - : expand-subfeatures foo=x-y ; - - assert.result gcc 3.0.1 - : expand-subfeatures gcc-3.0.1 ; - - feature dummy : dummy1 dummy2 ; - subfeature dummy : subdummy : x y z : optional ; - - assert.result a c e - : get-values x : a b c d e ; - - assert.result gcc 3.0.1 - debug _DEBUG on - : expand gcc-3.0.1 debug on - ; - - assert.result debug _DEBUG on - : expand debug on - ; - - assert.result on debug _DEBUG - : expand on debug - ; - - assert.result dynamic on - : defaults - ; - - assert.result static foobar on gcc:FOO - gcc debug native dummy1 - : add-defaults static foobar on gcc:FOO - ; - - assert.result gcc foo stlport 3 /path/to/stlport MAGIC=3 - : run-actions gcc foo stlport 3 - ; - - assert.result 17 MAGIC=BIG_MAGIC MAGIC=VERY_BIG_MAGIC - : run-actions 17 - ; - - - assert.result gcc-3.0.1 debug on - : minimize [ expand gcc-3.0.1 debug on native ] - ; - - assert.result gcc-3.0.1 debug dynamic - : minimize [ expand gcc-3.0.1 debug off dynamic ] - ; - - assert.result gcc-3.0.1 debug - : minimize [ expand gcc-3.0.1 debug off ] - ; - - assert.result debug on - : minimize [ expand debug on ] - ; - - assert.result gcc-3.0 - : minimize gcc 3.0 - ; - - assert.result gcc-3.0 - : minimize 3.0 gcc - ; - - assert.result y/z b/c e/f - : split y/z/b/c/e/f - ; - - assert.result y/z b/c e/f - : split y\\z\\b\\c\\e\\f - ; - - assert.result a b c e/f/g i/j/k - : split a/b/c/e/f/g/i/j/k - ; - - assert.result a b c e/f/g i/j/k - : split a\\b\\c\\e\\f\\g\\i\\j\\k - ; - - # test error checking - - try ; - { - expand release off on ; - } - catch explicitly-specified values of non-free feature conflict ; - - try ; - { - validate-feature foobar ; - } - catch unknown feature ; - - validate-value-string gcc ; - validate-value-string gcc-3.0.1 ; - - try ; - { - validate-value-string digital_mars ; - } - catch \"digital_mars\" is not a known value of ; - - try ; - { - feature foobar : : baz ; - } - catch unknown attributes: baz ; - - feature feature1 ; - try ; - { - feature feature1 ; - } - catch feature already defined: ; - - try ; - { - feature feature2 : : free implicit ; - } - catch free features cannot also be implicit ; - - try ; - { - feature feature3 : : free propagated ; - } - catch free features cannot be propagated ; - - try ; - { - implied-feature lackluster ; - } - catch \"lackluster\" is not a value of an implicit feature ; - - try ; - { - implied-subfeature toolset 3.0.1 ; - } - catch \"3.0.1\" is not a known subfeature value of - feature ; - - try ; - { - implied-subfeature toolset not-a-version : gcc ; - } - catch \"not-a-version\" is not a known subfeature value of - feature ; + return /path/to/stlport ; } + + local rule handle-magic ( property : properties * ) + { + return MAGIC=$(property:G=) ; + } + + local rule handle-magic2 ( property : properties * ) + { + return MAGIC=BIG_MAGIC ; + } + + local rule handle-magic3 ( property : properties * ) + { + return MAGIC=VERY_BIG_MAGIC ; + } + + action stlport : handle-stlport ; + action : handle-magic ; + action 17 : handle-magic2 ; + action 17 : handle-magic3 ; + + assert.result gcc 3.0.1 + : expand-subfeatures gcc-3.0.1 ; + + assert.result foo=x-y + : expand-subfeatures foo=x-y ; + + assert.result gcc 3.0.1 + : expand-subfeatures gcc-3.0.1 ; + + feature dummy : dummy1 dummy2 ; + subfeature dummy : subdummy : x y z : optional ; + + assert.result a c e + : get-values x : a b c d e ; + + assert.result gcc 3.0.1 + debug _DEBUG on + : expand gcc-3.0.1 debug on + ; + + assert.result debug _DEBUG on + : expand debug on + ; + + assert.result on debug _DEBUG + : expand on debug + ; + + assert.result dynamic on + : defaults + ; + + assert.result static foobar on gcc:FOO + gcc debug native dummy1 + : add-defaults static foobar on gcc:FOO + ; + + assert.result gcc foo stlport 3 /path/to/stlport MAGIC=3 + : run-actions gcc foo stlport 3 + ; + + assert.result 17 MAGIC=BIG_MAGIC MAGIC=VERY_BIG_MAGIC + : run-actions 17 + ; + + + assert.result gcc-3.0.1 debug on + : minimize [ expand gcc-3.0.1 debug on native ] + ; + + assert.result gcc-3.0.1 debug dynamic + : minimize [ expand gcc-3.0.1 debug off dynamic ] + ; + + assert.result gcc-3.0.1 debug + : minimize [ expand gcc-3.0.1 debug off ] + ; + + assert.result debug on + : minimize [ expand debug on ] + ; + + assert.result gcc-3.0 + : minimize gcc 3.0 + ; + + assert.result gcc-3.0 + : minimize 3.0 gcc + ; + + assert.result y/z b/c e/f + : split y/z/b/c/e/f + ; + + assert.result y/z b/c e/f + : split y\\z\\b\\c\\e\\f + ; + + assert.result a b c e/f/g i/j/k + : split a/b/c/e/f/g/i/j/k + ; + + assert.result a b c e/f/g i/j/k + : split a\\b\\c\\e\\f\\g\\i\\j\\k + ; + + # test error checking + + try ; + { + expand release off on ; + } + catch explicitly-specified values of non-free feature conflict ; + + try ; + { + validate-feature foobar ; + } + catch unknown feature ; + + validate-value-string gcc ; + validate-value-string gcc-3.0.1 ; + + try ; + { + validate-value-string digital_mars ; + } + catch \"digital_mars\" is not a known value of ; + + try ; + { + feature foobar : : baz ; + } + catch unknown attributes: baz ; + + feature feature1 ; + try ; + { + feature feature1 ; + } + catch feature already defined: ; + + try ; + { + feature feature2 : : free implicit ; + } + catch free features cannot also be implicit ; + + try ; + { + feature feature3 : : free propagated ; + } + catch free features cannot be propagated ; + + try ; + { + implied-feature lackluster ; + } + catch \"lackluster\" is not a value of an implicit feature ; + + try ; + { + implied-subfeature toolset 3.0.1 ; + } + catch \"3.0.1\" is not a known subfeature value of + feature ; + + try ; + { + implied-subfeature toolset not-a-version : gcc ; + } + catch \"not-a-version\" is not a known subfeature value of + feature ; + + # leave a clean copy of the features module behind + finish-test feature-test-temp ; } diff --git a/v2/build/generators.jam b/v2/build/generators.jam index 970517822..2291ef4aa 100644 --- a/v2/build/generators.jam +++ b/v2/build/generators.jam @@ -44,7 +44,9 @@ import class : class new is-a ; import container : vector ; import numbers : range ; import utility : str equal ; -import set ; +import set sequence ; +import assert ; +import virtual-target ; if "--debug-generators" in [ modules.peek : ARGV ] { @@ -113,7 +115,10 @@ rule generator ( import utility : equal ; import feature ; import errors : error ; - + import sequence ; + import type ; + import virtual-target ; + self.id = $(id) ; self.composing = $(composing) ; self.source-types = $(source-types) ; diff --git a/v2/build/project.jam b/v2/build/project.jam index 36cd430fb..6365eb619 100644 --- a/v2/build/project.jam +++ b/v2/build/project.jam @@ -16,12 +16,12 @@ import modules : peek poke ; import numbers ; import path ; import sequence ; -import targets ; import errors : error ; import project-root ; import print ; import class : class new ; import errors ; +import property-set ; # # Loads jamfile at the given location. After loading, project global @@ -415,6 +415,11 @@ rule register-id ( id : location ) # "requirements", "default-build", "source-location" and "projects-to-build". rule project-attributes ( location ) { + import property ; + import property-set ; + import errors ; + import path ; + self.location = $(location) ; # Set the named attribute from the specification given by the user. @@ -589,11 +594,14 @@ rule use ( id : location ) } # This module defines rules common to all projects -module project-rules { +module project-rules +{ rule project ( id ? : option1 * : option2 * : option3 * ) { import project ; + import path ; + local attributes = [ project.attributes $(__name__) ] ; if $(id) { @@ -619,6 +627,7 @@ module project-rules { rule use-project ( id : where ) { import project ; + import path ; local attributes = [ project.attributes $(__name__) ] ; project.use $(id) : [ path.root [ path.make $(where) ] [ $(attributes).get location ] ] ; diff --git a/v2/build/property-set.jam b/v2/build/property-set.jam index 691ae8a33..9a91e0497 100644 --- a/v2/build/property-set.jam +++ b/v2/build/property-set.jam @@ -21,6 +21,10 @@ import sequence ; # local rule property-set ( raw-properties * ) { + import feature ; + import property-set ; + import property ; + self.raw = $(raw-properties) ; for local p in $(raw-properties) @@ -177,10 +181,13 @@ rule create ( raw-properties * ) return $(.ps.$(key)) ; } -.empty = [ create ] ; - # Returns property-set with empty set of properties. rule empty ( ) { + if ! $(.empty) + { + .empty = [ create ] ; + } + return $(.empty) ; } diff --git a/v2/build/property.jam b/v2/build/property.jam index e0d4cc417..05897b440 100644 --- a/v2/build/property.jam +++ b/v2/build/property.jam @@ -8,7 +8,11 @@ import utility : ungrist ; import sequence : unique ; import errors : error ; import class : class ; - +import feature ; +import regex ; +import sequence ; +import set ; +import path ; # Refines 'properties' by overriding any elements for which a different # value is specified in 'requirements'. If the resulting property set @@ -17,10 +21,8 @@ import class : class ; # On success, returns properties. On error, returns a list which first # element is "@error" and the other elements compose the explanation # string. -rule refine ( properties * : requirements * : feature-space ? ) +rule refine ( properties * : requirements * ) { - feature-space ?= feature ; - local result ; local error ; @@ -38,7 +40,7 @@ rule refine ( properties * : requirements * : feature-space ? ) for local p in $(properties) { # No processing for free properties - if free in [ $(feature-space).attributes $(p:G) ] + if free in [ feature.attributes $(p:G) ] { result += $(p) ; } @@ -50,7 +52,7 @@ rule refine ( properties * : requirements * : feature-space ? ) local value = $(p:G=) ; if $(value) != $(required-value) { - if link-incompatible in [ $(feature-space).attributes $(p:G) ] + if link-incompatible in [ feature.attributes $(p:G) ] { error = @error link-incompatible properties $(p) and $(p:G)$(required-value) ; @@ -134,7 +136,7 @@ rule evaluate-conditionals ( properties * ) # Helper for as-path, below. Orders properties with the implicit ones # first, and within the two sections in alphabetical order of feature # name. -local rule path-order ( feature-space x y ) +local rule path-order ( x y ) { if $(y:G) && ! $(x:G) { @@ -148,8 +150,8 @@ local rule path-order ( feature-space x y ) { if ! $(x:G) { - x = [ $(feature-space).expand-subfeatures $(x) ] ; - y = [ $(feature-space).expand-subfeatures $(y) ] ; + x = [ feature.expand-subfeatures $(x) ] ; + y = [ feature.expand-subfeatures $(y) ] ; } if $(x[1]) < $(y[1]) @@ -160,19 +162,17 @@ local rule path-order ( feature-space x y ) } # Returns a path which represents the given expanded property set. -rule as-path ( properties * : feature-space ? ) +rule as-path ( properties * ) { - feature-space ?= feature ; - - local entry = .result.$(properties:J=-).$(feature-space) ; + local entry = .result.$(properties:J=-) ; if ! $($(entry)) { # trim redundancy - properties = [ $(feature-space).minimize $(properties) ] ; + properties = [ feature.minimize $(properties) ] ; # sort according to path-order - properties = [ sequence.insertion-sort $(properties) : path-order $(feature-space) ] ; + properties = [ sequence.insertion-sort $(properties) : path-order ] ; local components ; for local p in $(properties) @@ -195,22 +195,21 @@ rule as-path ( properties * : feature-space ? ) } # Exit with error if property is not valid. -local rule validate1 ( property : feature-space ? ) +local rule validate1 ( property ) { - feature-space ?= feature ; local msg ; if $(property:G) { local feature = [ ungrist $(property:G) ] ; # Ungrist for better error messages local value = $(property:G=) ; - if ! [ $(feature-space).valid $(feature) ] + if ! [ feature.valid $(feature) ] { msg = "unknown feature '$(feature)'" ; } - else if $(value) && ! free in [ $(feature-space).attributes $(feature) ] + else if $(value) && ! free in [ feature.attributes $(feature) ] { - $(feature-space).validate-value-string $(feature) $(value) ; + feature.validate-value-string $(feature) $(value) ; } else if ! $(value) { @@ -219,8 +218,8 @@ local rule validate1 ( property : feature-space ? ) } else { - local feature = [ $(feature-space).implied-feature $(property) ] ; - $(feature-space).validate-value-string $(feature) $(property) ; + local feature = [ feature.implied-feature $(property) ] ; + feature.validate-value-string $(feature) $(property) ; } if $(msg) { @@ -228,25 +227,24 @@ local rule validate1 ( property : feature-space ? ) } } -rule validate ( properties * : feature-space ? ) +rule validate ( properties * ) { for local p in $(properties) { - validate1 $(p) : $(feature-space) ; + validate1 $(p) ; } } -rule validate-property-sets ( property-sets * : feature-space ? ) +rule validate-property-sets ( property-sets * ) { for local s in $(property-sets) { - validate [ feature.split $(s) ] : $(feature-space) ; + validate [ feature.split $(s) ] ; } } # Makes a property set from 'specification', converting implicit values into # full properties. -# TODO: Might want to use 'feature-space' here as well as in other rules. rule make ( specification * ) { local result ; @@ -271,13 +269,12 @@ rule make ( specification * ) # Returns a property sets which include all the elements in 'properties' that # do not have attributes listed in 'attributes'. -rule remove ( attributes + : properties * : feature-space ? ) +rule remove ( attributes + : properties * ) { - feature-space ?= feature ; local result ; for local e in $(properties) { - if ! [ set.intersection $(attributes) : [ $(feature-space).attributes $(e:G) ] ] + if ! [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ] { result += $(e) ; } @@ -287,13 +284,12 @@ rule remove ( attributes + : properties * : feature-space ? ) # Returns a property set which include all properties in 'properties' that have # any of 'attributes'. -rule take ( attributes + : properties * : feature-space ? ) +rule take ( attributes + : properties * ) { - feature-space ?= feature ; local result ; for local e in $(properties) { - if [ set.intersection $(attributes) : [ $(feature-space).attributes $(e:G) ] ] + if [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ] { result += $(e) ; } @@ -392,6 +388,10 @@ rule translate-paths ( properties * : path ) # mapping rule property-map ( ) { + import numbers ; + import sequence ; + import errors : error ; + self.next-flag = 1 ; # Associate 'value' with 'properties' @@ -434,7 +434,7 @@ rule property-map ( ) $(matches) : $(match-ranks) ] ; if $(best[2]) { - errors.error "Ambiguous key" ; + error "Ambiguous key" ; } local original = $(self.value.$(best)) ; if $(value) @@ -450,29 +450,30 @@ class property-map ; local rule __test__ ( ) { - import class : new ; import errors : try catch ; + import feature ; + import feature : feature subfeature compose ; + + # local rules must be explicitly re-imported + import property : path-order ; + + feature.prepare-test property-test-temp ; - local test-space = [ new feature-space ] ; + feature toolset : gcc : implicit ; + subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 + 3.0 3.0.1 3.0.2 : optional ; + feature define : : free ; + feature runtime-link : dynamic static : symmetric link-incompatible ; + feature optimization : on off ; + feature variant : debug release : implicit composite ; + feature rtti : on off : link-incompatible ; - module $(test-space) - { - import assert ; - - feature toolset : gcc : implicit ; - subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 - 3.0 3.0.1 3.0.2 : optional ; - feature define : : free ; - feature runtime-link : dynamic static : symmetric link-incompatible ; - feature optimization : on off ; - feature variant : debug release : implicit composite ; - feature rtti : on off : link-incompatible ; - - compose debug : _DEBUG off ; - compose release : NDEBUG on ; - - } + compose debug : _DEBUG off ; + compose release : NDEBUG on ; + import assert ; + import class : new ; + validate gcc gcc-3.0.1 : $(test-space) ; validate gcc gcc-3.0.1 : $(test-space) ; @@ -587,6 +588,7 @@ local rule __test__ ( ) assert.result gcc,3.0 FOO : split-conditional gcc,3.0:FOO ; - + + feature.finish-test property-test-temp ; } diff --git a/v2/build/scanner.jam b/v2/build/scanner.jam index e61cc172f..ea04c17d7 100644 --- a/v2/build/scanner.jam +++ b/v2/build/scanner.jam @@ -27,7 +27,7 @@ # way, instead of relying on just target type. import class : class new ; -import property ; +import property virtual-target ; # Base scanner class. rule scanner ( ) @@ -116,6 +116,9 @@ rule hdrrule ( target : matches * ) local scanner = [ on $(target) return $(SCANNER) ] ; $(scanner).process $(target) : $(matches) ; } +# hdrrule must be available at global scope so that it can be invoked +# by header scanning +IMPORT scanner : hdrrule : : scanner.hdrrule ; diff --git a/v2/build/targets.jam b/v2/build/targets.jam index 395deeb9f..e9b93c99f 100644 --- a/v2/build/targets.jam +++ b/v2/build/targets.jam @@ -73,14 +73,16 @@ import property ; import errors ; import common ; import property-set ; -import utility : ungrist ; - +import project ; +import feature ; # Base class for all abstract targets. rule abstract-target ( name # name of the target in Jamfile : project # the project module where the target is declared ) { + import project ; + # Note: it might seem that we don't need either name or project at all. # However, there are places where we really need it. One example is error # messages which should name problematic targets. Another is setting correct @@ -138,6 +140,10 @@ class abstract-target ; # Project target class (derived from 'abstract-target') rule project-target ( name : project : requirements * : default-build * ) { + import project targets ; + import path ; + import print ; + abstract-target.__init__ $(name) : $(project) ; self.requirements = $(requirements) ; @@ -248,11 +254,15 @@ class project-target : abstract-target ; # A named top-level target in Jamfile rule main-target ( name : project ) { - import errors : error ; - import numbers : range ; - abstract-target.__init__ $(name) : $(project) ; + import errors : error ; + import assert ; + import numbers : range ; + import sequence ; + import print ; + import build-request feature property-set ; + # Add a new alternative for this target rule add-alternative ( target ) { @@ -474,10 +484,12 @@ rule generate-dependencies ( property-set : project : generation-ps ) rule basic-target ( name : project : sources * : requirements * : default-build * : usage-requirements * ) { - import build-request ; - import virtual-target ; - abstract-target.__init__ $(name) : $(project) ; + + import build-request ; + import virtual-target targets ; + import property-set ; + import set sequence errors ; self.sources = $(sources) ; if ! $(requirements) { @@ -730,6 +742,8 @@ rule typed-target ( name : project : type basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ; + import generators ; + self.type = $(type) ; rule construct ( source-targets * : property-set ) @@ -747,7 +761,6 @@ rule typed-target ( name : project : type return $(r) ; } } - class typed-target : basic-target ; # Returns the requirement to use when declaring a main target, diff --git a/v2/build/toolset.jam b/v2/build/toolset.jam index d05d231ee..94e2147f0 100644 --- a/v2/build/toolset.jam +++ b/v2/build/toolset.jam @@ -9,11 +9,12 @@ import feature ; import numbers ; import errors : error ; import property ; +import path ; .flag-no = 1 ; # Initializes an additional toolset-like module. -# First load 'toolset-module' and then calls it's 'init' +# First load 'toolset-module' and then calls its 'init' # rule with trailing arguments rule using ( toolset-module : * ) { diff --git a/v2/build/type.jam b/v2/build/type.jam index 6a30712f8..e18581786 100644 --- a/v2/build/type.jam +++ b/v2/build/type.jam @@ -11,6 +11,8 @@ import generators : * ; import class : class new ; import errors ; import property ; +import scanner ; +import targets ; # The feature is optional so that it never implicitly added. # It's used only for internal purposes, and in all cases we diff --git a/v2/build/virtual-target.jam b/v2/build/virtual-target.jam index 80707b708..0119ab0ad 100644 --- a/v2/build/virtual-target.jam +++ b/v2/build/virtual-target.jam @@ -9,9 +9,7 @@ # if particular target should be created at all. import class : class new ; -import type ; -import property-set ; -import utility ; +import path property-set utility sequence errors ; # +--------------------------+ # | virtual-target | @@ -69,6 +67,8 @@ rule virtual-target ( name # Name of this target -- specifies the name of : project # Project to which this target belongs ) { + import virtual-target utility scanner ; + self.name = $(name) ; self.project = $(project) ; self.dependencies = ; @@ -92,7 +92,7 @@ rule virtual-target ( name # Name of this target -- specifies the name of return $(self.dependencies) ; } - # Generates all the actual targets and set ups build actions for + # Generates all the actual targets and sets up build actions for # this target. # # If 'scanner' is specified, creates an additional target @@ -134,7 +134,7 @@ rule virtual-target ( name # Name of this target -- specifies the name of # private: (overridables) - # Sets up build actions for 'target'. Should call appriate rules + # Sets up build actions for 'target'. Should call appropriate rules # and set target variables. rule actualize-action ( target ) { @@ -205,6 +205,7 @@ rule abstract-file-target ( name ) { virtual-target.__init__ $(name) : $(project) ; + import project regex sequence path type ; self.type = $(type) ; self.action = ; @@ -431,7 +432,8 @@ rule file-target ( ) { abstract-file-target.__init__ $(name) : $(type) : $(project) ; - + import common ; + rule actualize-location ( target ) { if $(self.path) @@ -530,7 +532,9 @@ rule remember-binding ( target : bound-path ) { .binding.$(target) = $(bound-path) ; } - +# virtual-target.remember-binding must be available in the global +# module in order to be invoked by the builtin binding process. +IMPORT virtual-target : remember-binding : : virtual-target.remember-binding ; # Class which represents an action. # Both 'targets' and 'sources' should list instances of 'virtual-target'. @@ -540,10 +544,18 @@ rule remember-binding ( target : bound-path ) # not establish dependency relationship, but should do everything else. rule action ( targets + : sources * : action-name + : property-set ? ) { + import type toolset property-set ; + self.targets = $(targets) ; self.sources = $(sources) ; self.action-name = $(action-name) ; + if ! [ MATCH (\\.) : $(action-name[1]) ] + { + local caller = [ CALLER_MODULE ] ; + self.action-name = $(caller).$(action-name[1]) $(action-name[2-]) ; + } + if ! $(property-set) { property-set = [ property-set.empty ] ; @@ -602,8 +614,14 @@ rule action ( targets + : sources * : action-name + : property-set ? ) toolset.set-target-variables $(self.action-name[1]) $(actual-targets) : $(properties) ; - $(self.action-name) - $(actual-targets) : $(self.actual-sources) : $(properties) ; + ECHO $(self.action-name) ; + + modules.call-locally $(self.action-name) + $(actual-targets) + : $(self.actual-sources) + : $(properties) + ; + # Since we set up creating action here, we also set up # action for cleaning up common.Clean clean : $(actual-targets) ; @@ -688,6 +706,8 @@ class null-action : action ; # TODO: passing project with all virtual targets starts to be annoying. rule from-file ( file : project ) { + import type ; # had to do this here to break a circular dependency + if $(.files.$(file).$(project)) { return $(.files.$(file).$(project)) ; @@ -904,6 +924,8 @@ local rule subvariant-dg ( main-target # The instance of main-target class : actual-properties # Actual used properties : virtual-targets * ) { + import sequence ; + self.main-target = $(main-target) ; self.properties = $(property-set) ; self.actual-properties = $(actual-properties) ; diff --git a/v2/gcc.jam b/v2/gcc.jam index 8b4e525be..d90e6f86b 100644 --- a/v2/gcc.jam +++ b/v2/gcc.jam @@ -8,6 +8,7 @@ import property ; import generators ; import os ; import type ; +import feature ; feature.extend toolset : gcc ; feature.subfeature toolset gcc : version : : optional propagated link-incompatible ; diff --git a/v2/kernel/class.jam b/v2/kernel/class.jam index 65259b97e..1da068b31 100644 --- a/v2/kernel/class.jam +++ b/v2/kernel/class.jam @@ -80,10 +80,15 @@ local rule __init__ ( # initialization function. ) { + # pull the name of the class being initialized from the backtrace local bt = [ BACKTRACE 1 ] ; local class = [ MATCH ^(.*)[.]__init__$ : $(bt[4]) ] ; - assert.nonempty-variable class ; + if ! $(class) + { + import errors : error ; + error couldn't extract class name from backtrace ; + } # set the __class__ __class__ ?= $(class) ; @@ -106,7 +111,8 @@ local rule __init__ ( { if ! $($(b).__init__.called) { - errors.error $(class).$(class) failed to call base class constructor $(b).__init__ ; + import errors : error ; + error $(class).$(class) failed to call base class constructor $(b).__init__ ; } } # Make all the class' member rules available as qualified names @@ -220,14 +226,19 @@ rule instance ( name : class args * : * ) rule new ( class args * : * ) { .next-instance.$(class) ?= 1 ; - local name = object($(class))@$(.next-instance.$(class)) ; - instance $(name) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + local id = object($(class))@$(.next-instance.$(class)) ; + instance $(id) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; + # import the instance's methods, with qualification, into the + # global namespace. + local methods = [ RULENAMES $(id) ] ; + IMPORT $(id) : $(methods) : : $(id).$(methods) ; + # bump the next unique object name .next-instance.$(class) = [ numbers.increment $(.next-instance.$(class)) ] ; # Return the name of the new instance. - return $(name) ; + return $(id) ; } rule bases ( class ) @@ -300,215 +311,212 @@ local rule typecheck ( x ) } } -rule __test__ ( ) +local rule __test__ ( ) { - module class.__test__ + import class : * ; + import assert ; + import errors : * ; + + # This will be the construction function for a class called + # 'myclass' + local rule myclass ( x_ * : y_ * ) { - import class : * ; - import assert ; - import errors : * ; - - # This will be the construction function for a class called - # 'myclass' - local rule myclass ( x_ * : y_ * ) + # set some instance variables + x = $(x_) ; + y = $(y_) ; + + rule set-x ( newx * ) { - # set some instance variables - x = $(x_) ; - y = $(y_) ; - - rule set-x ( newx * ) - { - x = $(newx) ; - } - - rule get-x ( ) + x = $(newx) ; + } + + rule get-x ( ) + { + return $(x) ; + } + + rule set-y ( newy * ) + { + y = $(newy) ; + } + + rule get-y ( ) + { + return $(y) ; + } + + rule f ( ) + { + return [ g $(x) ] ; + } + + rule g ( args * ) + { + if $(x) in $(y) { return $(x) ; } - - rule set-y ( newy * ) - { - y = $(newy) ; - } - - rule get-y ( ) + else if $(y) in $(x) { return $(y) ; } - - rule f ( ) + else { - return [ g $(x) ] ; - } - - rule g ( args * ) - { - if $(x) in $(y) - { - return $(x) ; - } - else if $(y) in $(x) - { - return $(y) ; - } - else - { - return ; - } - } - - rule get-class ( ) - { - return $(__class__) ; + return ; } } - class myclass ; - - local rule derived1 ( z_ ) + + rule get-class ( ) { - myclass.__init__ $(z_) : X ; - z = $(z_) ; - - # override g - rule g ( args * ) - { - return derived1.g ; - } - - rule h ( ) - { - return derived1.h ; - } - - rule get-z ( ) - { - return $(z) ; - } + return $(__class__) ; } - class derived1 : myclass ; - - local rule derived2 ( ) + } + class myclass ; + + local rule derived1 ( z_ ) + { + myclass.__init__ $(z_) : X ; + z = $(z_) ; + + # override g + rule g ( args * ) { - myclass.__init__ 1 : 2 ; - - # override g - rule g ( args * ) - { - return derived2.g ; - } - - rule get-x ( ) - { - # Test the ability to call base class functions with qualification. - return [ myclass.get-x ] ; - } + return derived1.g ; } - class derived2 : myclass ; - - local rule derived2a ( ) + + rule h ( ) { - derived2.__init__ ; + return derived1.h ; } - class derived2a : derived2 ; - - local rule expect_derived2 ( [derived2] x ) { } - - local rule bad_subclass ( ) + + rule get-z ( ) { - # fails to call base class __init__ function + return $(z) ; } - class bad_subclass : myclass ; - - local a = [ new myclass 3 4 5 : 4 5 ] ; - local b = [ new derived1 4 ] ; - local c = [ new derived2 ] ; - local d = [ new derived2 ] ; - local e = [ new derived2a ] ; - - expect_derived2 $(d) ; - expect_derived2 $(e) ; - - # argument checking is set up to call exit(1) directly on - # failure, and we can't hijack that with try, so we'd better - # not do this test by default. We could fix this by having - # errors look up and invoke the EXIT rule instead; EXIT can be - # hijacked ;-) - if --fail-typecheck in [ modules.peek : ARGV ] + } + class derived1 : myclass ; + + local rule derived2 ( ) + { + myclass.__init__ 1 : 2 ; + + # override g + rule g ( args * ) { - try ; - { - expect_derived2 $(a) ; - } - catch - "Expected an instance of derived2 but got" instead - ; + return derived2.g ; } - - + + rule get-x ( ) + { + # Test the ability to call base class functions with qualification. + return [ myclass.get-x ] ; + } + } + class derived2 : myclass ; + + local rule derived2a ( ) + { + derived2.__init__ ; + } + class derived2a : derived2 ; + + local rule expect_derived2 ( [derived2] x ) { } + + local rule bad_subclass ( ) + { + # fails to call base class __init__ function + } + class bad_subclass : myclass ; + + local a = [ new myclass 3 4 5 : 4 5 ] ; + local b = [ new derived1 4 ] ; + local c = [ new derived2 ] ; + local d = [ new derived2 ] ; + local e = [ new derived2a ] ; + + expect_derived2 $(d) ; + expect_derived2 $(e) ; + + # argument checking is set up to call exit(1) directly on + # failure, and we can't hijack that with try, so we'd better + # not do this test by default. We could fix this by having + # errors look up and invoke the EXIT rule instead; EXIT can be + # hijacked (;-) + if --fail-typecheck in [ modules.peek : ARGV ] + { try ; { - new bad_subclass ; + expect_derived2 $(a) ; } catch - bad_subclass.bad_subclass failed to call base class constructor myclass.__init__ + "Expected an instance of derived2 but got" instead ; - - try ; - { - class bad_subclass ; - } - catch bad_subclass has already been declared ; - - assert.result 3 4 5 : $(a).get-x ; - assert.result 4 5 : $(a).get-y ; - assert.result 4 : $(b).get-x ; - assert.result X : $(b).get-y ; - assert.result 4 : $(b).get-z ; - assert.result 1 : $(c).get-x ; - assert.result 2 : $(c).get-y ; - assert.result 4 5 : $(a).f ; - assert.result derived1.g : $(b).f ; - assert.result derived2.g : $(c).f ; - assert.result derived2.g : $(d).f ; - - # Check that the __class__ attribute is getting properly set. - assert.result myclass : $(a).get-class ; - assert.result derived1 : $(b).get-class ; - - $(a).set-x a.x ; - $(b).set-x b.x ; - $(c).set-x c.x ; - $(d).set-x d.x ; - assert.result a.x : $(a).get-x ; - assert.result b.x : $(b).get-x ; - assert.result c.x : $(c).get-x ; - assert.result d.x : $(d).get-x ; - - rule derived3 ( ) - { - } - class derived3 : derived1 derived2 ; - - assert.result : bases myclass ; - assert.result myclass : bases derived1 ; - assert.result myclass : bases derived2 ; - assert.result derived1 derived2 : bases derived3 ; - - assert.true is-derived derived1 : myclass ; - assert.true is-derived derived2 : myclass ; - assert.true is-derived derived3 : derived1 ; - assert.true is-derived derived3 : derived2 ; - assert.true is-derived derived3 : derived1 derived2 myclass ; - assert.true is-derived derived3 : myclass ; - - assert.false is-derived myclass : derived1 ; - - assert.true is-instance $(a) ; - assert.false is-instance bar ; - - assert.true is-a $(a) : myclass ; - assert.true is-a $(c) : derived2 ; - assert.true is-a $(d) : myclass ; - assert.false is-a literal : myclass ; } + + + try ; + { + new bad_subclass ; + } + catch + bad_subclass.bad_subclass failed to call base class constructor myclass.__init__ + ; + + try ; + { + class bad_subclass ; + } + catch bad_subclass has already been declared ; + + assert.result 3 4 5 : $(a).get-x ; + assert.result 4 5 : $(a).get-y ; + assert.result 4 : $(b).get-x ; + assert.result X : $(b).get-y ; + assert.result 4 : $(b).get-z ; + assert.result 1 : $(c).get-x ; + assert.result 2 : $(c).get-y ; + assert.result 4 5 : $(a).f ; + assert.result derived1.g : $(b).f ; + assert.result derived2.g : $(c).f ; + assert.result derived2.g : $(d).f ; + + # Check that the __class__ attribute is getting properly set. + assert.result myclass : $(a).get-class ; + assert.result derived1 : $(b).get-class ; + + $(a).set-x a.x ; + $(b).set-x b.x ; + $(c).set-x c.x ; + $(d).set-x d.x ; + assert.result a.x : $(a).get-x ; + assert.result b.x : $(b).get-x ; + assert.result c.x : $(c).get-x ; + assert.result d.x : $(d).get-x ; + + rule derived3 ( ) + { + } + class derived3 : derived1 derived2 ; + + assert.result : bases myclass ; + assert.result myclass : bases derived1 ; + assert.result myclass : bases derived2 ; + assert.result derived1 derived2 : bases derived3 ; + + assert.true is-derived derived1 : myclass ; + assert.true is-derived derived2 : myclass ; + assert.true is-derived derived3 : derived1 ; + assert.true is-derived derived3 : derived2 ; + assert.true is-derived derived3 : derived1 derived2 myclass ; + assert.true is-derived derived3 : myclass ; + + assert.false is-derived myclass : derived1 ; + + assert.true is-instance $(a) ; + assert.false is-instance bar ; + + assert.true is-a $(a) : myclass ; + assert.true is-a $(c) : derived2 ; + assert.true is-a $(d) : myclass ; + assert.false is-a literal : myclass ; } \ No newline at end of file diff --git a/v2/modules.jam b/v2/modules.jam index b906da2f3..c8e0cc5ad 100644 --- a/v2/modules.jam +++ b/v2/modules.jam @@ -17,11 +17,12 @@ # meant to be invoked from import when no __test__ rule is defined in a given # module -local rule no_test_defined +local rule no-test-defined { - if ! ( --quiet in [ peek : ARGV ] ) + import modules ; + if ! ( --quiet in [ modules.peek : ARGV ] ) { - ECHO warning: no __test__ rule defined in module [ CALLER_MODULE ] ; + ECHO warning: no __test__ rule defined in module $(__module__) ; } } @@ -66,6 +67,21 @@ rule call-in ( module-name ? : rule-name args * : * ) } } +# Given a possibly qualified rule name and arguments, remove any +# initial module qualification from the rule and invoke it in that +# module. If there is no module qualification, the rule is invoked in +# the global module. +rule call-locally ( qualified-rule-name args * : * ) +{ + local module-rule = [ MATCH (.*)\\.(.*) : $(qualified-rule-name) ] ; + local rule-name = $(module-rule[2]) ; + rule-name ?= $(qualified-rule-name) ; + return [ + call-in $(module-rule[1]) + : $(rule-name) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) + ] ; +} + # load the indicated module if it is not already loaded. rule load ( module-name # name of module to load. Rules will be defined in this module @@ -97,7 +113,7 @@ rule load ( module $(module-name) { # Prepare a default behavior, in case no __test__ is defined. - IMPORT modules : no_test_defined : $(__name__) : __test__ ; + IMPORT modules : no-test-defined : $(__name__) : __test__ ; # Add some grist so that the module will have a unique target name local module-target = $(__file__:G=module@) ; @@ -106,7 +122,12 @@ rule load ( search ?= [ modules.peek : BOOST_BUILD_PATH ] ; SEARCH on $(module-target) = $(search) ; BINDRULE on $(module-target) = modules.record-binding ; + include $(module-target) ; + + # Allow the module to see its own names with full qualification + local rules = [ RULENAMES $(__name__) ] ; + IMPORT $(__name__) : $(rules) : $(__name__) : $(__name__).$(rules) ; } # Pop the loading stack. Must happen before testing or we'll find a circular loading dependency @@ -127,8 +148,18 @@ rule load ( ECHO testing module $(m)... ; } - module $(m) + # execute the module's __test__ rule in its own module to + # eliminate the inadvertent effects of testing + # module dependencies (such as assert) on the module itself. + IMPORT $(m) : __test__ : __test-$(m)__ : __test__ : LOCALIZE ; + + # Import the rest of m's rules into __test-$(m)__ for easy access + IMPORT $(m) : [ RULENAMES $(m) ] : __test-$(m)__ : [ RULENAMES $(m) ] ; + module __test-$(m)__ { + # set up the name of the module we're testing + # so that no-test-defined can find it. + __module__ = $(1) ; __test__ ; } } @@ -138,9 +169,10 @@ rule load ( } else if $(module-name) in $(.loading) { - ECHO loading \"$(module-name)\" ; - ECHO circular module loading dependency: ; - EXIT $(.loading)" ->" $(module-name) ; + import errors ; + errors.error loading \"$(module-name)\" + : circular module loading dependency: + : $(.loading)" ->" $(module-name) ; } } @@ -159,26 +191,52 @@ rule record-binding ( module-target : binding ) # all rules from the indicated module are imported into the caller's # module. If rename-opt is supplied, it must have the same number of # elements as rules-opt. -rule import ( module-name : rules-opt * : rename-opt * ) +rule import ( module-names + : rules-opt * : rename-opt * ) { + if $(rules-opt) = * || ! $(rules-opt) + { + if $(rename-opt) + { + errors.error "rule aliasing is only available for explicit imports." ; + } + } + + if $(module-names[2]) && ( $(rules-opt) || $(rename-opt) ) + { + errors.error when loading multiple modules, no specific rules or renaming is allowed ; + } + local caller = [ CALLER_MODULE ] ; local caller-location ; if $(caller) { caller-location = [ binding $(caller) ] ; } - - load $(module-name) : : $(caller-location:D) [ modules.peek : BOOST_BUILD_PATH ] ; - local source-names = $(rules-opt) ; - if $(rules-opt) = * + for local m in $(module-names) { - source-names = [ RULENAMES $(module-name) ] ; - } + load $(m) : : $(caller-location:D) [ peek : BOOST_BUILD_PATH ] ; + local all-rules = [ RULENAMES $(m) ] ; - local target-names = $(rename-opt) ; - target-names ?= $(source-names) ; - IMPORT $(module-name) : $(source-names) : [ CALLER_MODULE ] : $(target-names) ; + # import all the rules with qualification + IMPORT $(m) : $(all-rules) : $(caller) : $(m).$(all-rules) ; + + if $(rules-opt) + { + local source-names ; + if $(rules-opt) = * + { + source-names = $(all-rules) ; + } + else + { + source-names = $(rules-opt) ; + } + local target-names = $(rename-opt) ; + target-names ?= $(source-names) ; + IMPORT $(m) : $(source-names) : $(caller) : $(target-names) ; + } + } } # Define exported copies in $(target-module) of all rules exported @@ -197,6 +255,11 @@ rule clone-rules ( IMPORT $(target-module) : $(rules) : : $(target-module).$(rules) ; } +# These rules need to be available in all modules to implement +# module loading itself and other fundamental operations. +local globalize = peek poke record-binding ; +IMPORT modules : $(globalize) : : modules.$(globalize) ; + local rule __test__ ( ) { import assert ; diff --git a/v2/msvc.jam b/v2/msvc.jam index 01d21f136..14c2c7d03 100755 --- a/v2/msvc.jam +++ b/v2/msvc.jam @@ -10,6 +10,7 @@ import type ; import toolset : flags ; import errors : error ; import feature : feature ; +import path ; import sequence : unique ; if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] diff --git a/v2/project-root.jam b/v2/project-root.jam index 240efd24e..70e968559 100644 --- a/v2/project-root.jam +++ b/v2/project-root.jam @@ -92,6 +92,9 @@ rule project-root-object ( location # The root location. ) { + import path ; + import set ; + # The module name of the project-root. self.module = project-root<$(location)> ; diff --git a/v2/tools/builtin.jam b/v2/tools/builtin.jam index ae78ecbbb..388e09baa 100644 --- a/v2/tools/builtin.jam +++ b/v2/tools/builtin.jam @@ -8,6 +8,8 @@ import class : class new ; import feature : feature compose ; +import toolset : flags ; +import errors : error ; import type ; import scanner ; import generators ; @@ -15,10 +17,10 @@ import regex ; import virtual-target ; import os ; import prebuilt ; -import toolset : flags ; -import errors : error ; import symlink ; import alias ; +import property ; +import print ; # This feature is used to determine which OS we're on. # In future, this may become and @@ -147,11 +149,12 @@ variant release : speed off full propagated, because (i) free features cannot be propagated and # (ii) this is dangerous. -rule builtin.handle-ndebug ( property : properties * ) +rule handle-ndebug ( property : properties * ) { return NDEBUG ; } -feature.action speed : builtin.handle-ndebug ; + +feature.action speed : handle-ndebug ; rule searched-lib-target ( name @@ -306,6 +309,8 @@ actions quietly piecemeal response-file-2 rule c-scanner ( includes * ) { scanner.__init__ ; + + import regex virtual-target path scanner ; self.includes = $(includes) ; rule pattern ( ) @@ -457,6 +462,7 @@ generators.register [ new searched-lib-generator ] ; rule compile-action ( targets + : sources * : action-name : properties * ) { action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ; + import sequence ; # For all virtual targets for the same dependency graph as self, # i.e. which belong to the same main target, add their directories @@ -505,7 +511,8 @@ IMPORT $(__name__) : register-c-compiler : : generators.register-c-compiler ; rule link-action ( targets + : sources * : action-name : properties * ) { action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ; - + import path ; + # Find all libraries in sources, and properties # For each source/property-value, which is instance of searched-lib-target, # add appropriate or property. @@ -668,6 +675,6 @@ declare-type : RSP : rsp ; flags builtin.response-file FINDLIBS_ST ; flags builtin.response-file FINDLIBS_SA ; flags builtin.response-file LIBRARY_PATH ; -builtin.register-linker builtin.response-file : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : RSP ; +register-linker builtin.response-file : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : RSP ; diff --git a/v2/tools/make.jam b/v2/tools/make.jam index d55af4f47..e2f09bb57 100644 --- a/v2/tools/make.jam +++ b/v2/tools/make.jam @@ -17,6 +17,8 @@ import property-set ; rule make-target-class ( name : project : sources * : requirements * : make-rule + : default-build * ) { + import type regex virtual-target ; + basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements) : $(default-build) ; @@ -33,7 +35,6 @@ rule make-target-class ( name : project : sources * : requirements * return [ virtual-target.register $(t) ] ; } } - class make-target-class : basic-target ; rule make ( target-name : sources * : generating-rule + : requirements * diff --git a/v2/tools/prebuilt.jam b/v2/tools/prebuilt.jam index 1fda260de..922c1f0fd 100644 --- a/v2/tools/prebuilt.jam +++ b/v2/tools/prebuilt.jam @@ -6,21 +6,18 @@ # This module defines a special generator, which handles targets with # property. It allows to use prebuilt targets. -import targets ; import class : class new ; -import property ; -import errors : error ; -import type : type ; -import regex ; -import feature ; import generators ; +import feature : feature ; -feature.feature file : : free path ; +feature file : : free path ; rule prebuilt-file-generator { generator.__init__ prebuilt-file-generator : : * : ; - + + import feature type errors path ; + rule run ( project name ? : property-set : sources * ) { local properties = [ $(property-set).raw ] ; diff --git a/v2/tools/stage.jam b/v2/tools/stage.jam index 885e13b53..3096b4f3c 100644 --- a/v2/tools/stage.jam +++ b/v2/tools/stage.jam @@ -24,13 +24,17 @@ import class : class new ; import property ; import errors : error ; import type : type ; +import type ; import regex ; +import generators ; rule stage-target-class ( name-and-dir : project : sources * : requirements * : default-build * ) { basic-target.__init__ $(name-and-dir) : $(project) : $(sources) : $(requirements) : $(default-build) ; + import feature project type errors generators ; + rule construct ( source-targets * : property-set ) { local location = [ feature.get-values : @@ -92,6 +96,7 @@ type.register STAGED_EXE : : EXE ; rule stage-exe-generator { generator.__init__ stage-exe : EXE : STAGED_EXE ; + import type property-set modules ; rule run ( project name ? : property-set : source : multiple ? ) { diff --git a/v2/tools/symlink.jam b/v2/tools/symlink.jam index a8aa227b5..622817d87 100644 --- a/v2/tools/symlink.jam +++ b/v2/tools/symlink.jam @@ -6,16 +6,9 @@ # Defines the "symlink" special target. 'symlink' targets make symbolic links # to the sources. -import numbers ; -import targets ; -import virtual-target ; -import class ; -import property ; -import modules ; -import os ; -import feature ; +import targets modules path class os feature ; -count = 0 ; +.count = 0 ; feature.feature symlink-location : project-relative build-relative : incidental ; @@ -27,9 +20,11 @@ rule symlink-targets ( : sources * ) { + import numbers modules class property project ; + # Generate a fake name for now. Need unnamed targets eventually. - local c = [ modules.peek symlink : count ] ; - modules.poke symlink : count : [ numbers.increment $(c) ] ; + local c = [ modules.peek symlink : .count ] ; + modules.poke symlink : .count : [ numbers.increment $(c) ] ; local fake-name = symlink#$(c) ; basic-target.__init__ $(fake-name) : $(project) : $(sources) ; diff --git a/v2/util/container.jam b/v2/util/container.jam index 79c239edf..09b96ca67 100644 --- a/v2/util/container.jam +++ b/v2/util/container.jam @@ -6,9 +6,6 @@ # Various container classes. import class : * ; -import sequence ; -import utility ; - # Base for container objects. This lets us construct recursive structures. # That is containers with containers in them, specifically so we can tell @@ -46,6 +43,8 @@ rule vector ( ) { import numbers : range ; + import utility ; + import sequence ; node.__init__ ; self.value = $(values) ; @@ -246,6 +245,7 @@ module class@vector local rule __test__ ( ) { import assert ; + import class : new ; local l = [ new vector ] ; assert.result 0 : $(l).size ; diff --git a/v2/util/os.jam b/v2/util/os.jam index 1d2fb8465..57979ba87 100644 --- a/v2/util/os.jam +++ b/v2/util/os.jam @@ -16,6 +16,7 @@ import regex ; rule __test__ { + import assert ; rule identity ( args * ) { return $(args) ; } if ! ( --quiet in [ modules.peek : ARGV ] ) diff --git a/v2/util/sequence.jam b/v2/util/sequence.jam index c3f86965b..2ef13c325 100644 --- a/v2/util/sequence.jam +++ b/v2/util/sequence.jam @@ -5,6 +5,7 @@ import assert ; import numbers ; +import modules ; # Note that algorithms in this module execute largely in the caller's # module namespace, so that local rules can be used as function @@ -225,7 +226,9 @@ local rule __test__ ( ) # use a unique module so we can test the use of local rules. module sequence.__test__ { - + import assert ; + import sequence ; + local rule is-even ( n ) { if $(n) in 0 2 4 6 8