2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-15 13:02:11 +00:00

Note: there is currently a circular dependency between type.jam and

virtual-target.jam.

- Added the missing explicit imports, now that we don't dump
  everything into the global module with qualification

- stopped using the feature-space hack for temporary testing states of
  the feature module.  Instead we move its global variable definitions
  to a temporary module.

- the way feature.action was invoking the rule it was being passed was
  evil.  Now you pass (even local) rules without qualification and
  they are invoked in the source module context.

- module __test__ rules are always executed in a separate module, so
  that their import dependencies can be separated from those of the
  module being tested.

- better reporting of circular module-loading dependencies
  implemented.

- minor changes:

    property-set.jam:  moved .empty initialization to avert circular
    load dependency .

    symlink.jam: fixed global variable naming.


[SVN r18407]
This commit is contained in:
Dave Abrahams
2003-05-15 22:22:13 +00:00
parent be2d15e71d
commit 5eb7ea1192
52 changed files with 1700 additions and 1376 deletions

View File

@@ -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

View File

@@ -11,6 +11,8 @@ import property ;
import generators ;
import os ;
import toolset : flags ;
import feature ;
import type ;
toolset.register borland ;

View File

@@ -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 <toolset>gcc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
<variant>debug/<toolset>msvc/<stdlib>stlport
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>off
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>release/<inlining>off
: build-request.expand-no-defaults gcc-3.0.1/stlport debug release <inlining>off
;
assert.result
<include>a/b/c/<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<variant>debug/<include>x/y/z
: build-request.expand-no-defaults <include>a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug <include>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 <runtime-link>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 <toolset>gcc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
<variant>debug/<toolset>msvc/<stdlib>stlport
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>off
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>release/<inlining>off
: build-request.expand-no-defaults gcc-3.0.1/stlport debug release <inlining>off
: $(test-space) ;
assert.result
<include>a/b/c/<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<variant>debug/<include>x/y/z
: build-request.expand-no-defaults <include>a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug <include>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 <runtime-link>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 <runtime-link>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 <runtime-link>dynamic <runtime-link>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/<runtime-link>dynamic
gcc/<runtime-link>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/<runtime-link>static
borland/<runtime-link>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 <runtime-link>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 <runtime-link>dynamic <runtime-link>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/<runtime-link>dynamic
gcc/<runtime-link>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/<runtime-link>static
borland/<runtime-link>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 ;
}

View File

@@ -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 <target-os> and <host-os>
@@ -147,11 +149,12 @@ variant release : <optimization>speed <debug-symbols>off <inlining>full <runtime
# not propagated, we can't just add it to 'release'. And we cannot make
# <define> 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 <define>NDEBUG ;
}
feature.action <optimization>speed : builtin.handle-ndebug ;
feature.action <optimization>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 <library> properties
# For each source/property-value, which is instance of searched-lib-target,
# add appropriate <find-shared-library> or <find-static-library> property.
@@ -668,6 +675,6 @@ declare-type : RSP : rsp ;
flags builtin.response-file FINDLIBS_ST <find-static-library> ;
flags builtin.response-file FINDLIBS_SA <find-shared-library> ;
flags builtin.response-file LIBRARY_PATH <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 ;

View File

@@ -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 ;
}

View File

@@ -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 ;

View File

@@ -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 )
# <feature>value, and feature should be specified as <feature>.
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 <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>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 <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>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 <include>/path/to/stlport ;
}
rule handle-magic ( property : properties * )
{
return <define>MAGIC=$(property:G=) ;
}
rule handle-magic2 ( property : properties * )
{
return <define>MAGIC=BIG_MAGIC ;
}
rule handle-magic3 ( property : properties * )
{
return <define>MAGIC=VERY_BIG_MAGIC ;
}
action <stdlib>stlport : handle-stlport ;
action <magic> : handle-magic ;
action <magic>17 : handle-magic2 ;
action <magic>17 : handle-magic3 ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
: expand-subfeatures <toolset>gcc-3.0.1 ;
assert.result <define>foo=x-y
: expand-subfeatures <define>foo=x-y ;
assert.result <toolset>gcc <toolset-gcc:version>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 : <x>a <y>b <x>c <y>d <x>e ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
<variant>debug <define>_DEBUG <optimization>on
: expand gcc-3.0.1 debug <optimization>on
;
assert.result <variant>debug <define>_DEBUG <optimization>on
: expand debug <optimization>on
;
assert.result <optimization>on <variant>debug <define>_DEBUG
: expand <optimization>on debug
;
assert.result <runtime-link>dynamic <optimization>on
: defaults <runtime-link> <define> <optimization>
;
assert.result <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
<toolset>gcc <variant>debug <stdlib>native <dummy>dummy1
: add-defaults <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
;
assert.result <toolset>gcc <define>foo <stdlib>stlport <magic>3 <include>/path/to/stlport <define>MAGIC=3
: run-actions <toolset>gcc <define>foo <stdlib>stlport <magic>3
;
assert.result <magic>17 <define>MAGIC=BIG_MAGIC <define>MAGIC=VERY_BIG_MAGIC
: run-actions <magic>17
;
assert.result gcc-3.0.1 debug <optimization>on
: minimize [ expand gcc-3.0.1 debug <optimization>on <stdlib>native ]
;
assert.result gcc-3.0.1 debug <runtime-link>dynamic
: minimize [ expand gcc-3.0.1 debug <optimization>off <runtime-link>dynamic ]
;
assert.result gcc-3.0.1 debug
: minimize [ expand gcc-3.0.1 debug <optimization>off ]
;
assert.result debug <optimization>on
: minimize [ expand debug <optimization>on ]
;
assert.result gcc-3.0
: minimize <toolset>gcc <toolset-gcc:version>3.0
;
assert.result gcc-3.0
: minimize <toolset-gcc:version>3.0 <toolset>gcc
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y/z/<a>b/c/<d>e/f
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y\\z\\<a>b\\c\\<d>e\\f
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a/b/c/<d>e/f/g/<h>i/j/k
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a\\b\\c\\<d>e\\f\\g\\<h>i\\j\\k
;
# test error checking
try ;
{
expand release <optimization>off <optimization>on ;
}
catch explicitly-specified values of non-free feature <optimization> conflict ;
try ;
{
validate-feature foobar ;
}
catch unknown feature ;
validate-value-string <toolset> gcc ;
validate-value-string <toolset> gcc-3.0.1 ;
try ;
{
validate-value-string <toolset> digital_mars ;
}
catch \"digital_mars\" is not a known value of <toolset> ;
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 <toolset> ;
try ;
{
implied-subfeature toolset not-a-version : gcc ;
}
catch \"not-a-version\" is not a known subfeature value of
feature <toolset> ;
return <include>/path/to/stlport ;
}
local rule handle-magic ( property : properties * )
{
return <define>MAGIC=$(property:G=) ;
}
local rule handle-magic2 ( property : properties * )
{
return <define>MAGIC=BIG_MAGIC ;
}
local rule handle-magic3 ( property : properties * )
{
return <define>MAGIC=VERY_BIG_MAGIC ;
}
action <stdlib>stlport : handle-stlport ;
action <magic> : handle-magic ;
action <magic>17 : handle-magic2 ;
action <magic>17 : handle-magic3 ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
: expand-subfeatures <toolset>gcc-3.0.1 ;
assert.result <define>foo=x-y
: expand-subfeatures <define>foo=x-y ;
assert.result <toolset>gcc <toolset-gcc:version>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 : <x>a <y>b <x>c <y>d <x>e ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
<variant>debug <define>_DEBUG <optimization>on
: expand gcc-3.0.1 debug <optimization>on
;
assert.result <variant>debug <define>_DEBUG <optimization>on
: expand debug <optimization>on
;
assert.result <optimization>on <variant>debug <define>_DEBUG
: expand <optimization>on debug
;
assert.result <runtime-link>dynamic <optimization>on
: defaults <runtime-link> <define> <optimization>
;
assert.result <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
<toolset>gcc <variant>debug <stdlib>native <dummy>dummy1
: add-defaults <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
;
assert.result <toolset>gcc <define>foo <stdlib>stlport <magic>3 <include>/path/to/stlport <define>MAGIC=3
: run-actions <toolset>gcc <define>foo <stdlib>stlport <magic>3
;
assert.result <magic>17 <define>MAGIC=BIG_MAGIC <define>MAGIC=VERY_BIG_MAGIC
: run-actions <magic>17
;
assert.result gcc-3.0.1 debug <optimization>on
: minimize [ expand gcc-3.0.1 debug <optimization>on <stdlib>native ]
;
assert.result gcc-3.0.1 debug <runtime-link>dynamic
: minimize [ expand gcc-3.0.1 debug <optimization>off <runtime-link>dynamic ]
;
assert.result gcc-3.0.1 debug
: minimize [ expand gcc-3.0.1 debug <optimization>off ]
;
assert.result debug <optimization>on
: minimize [ expand debug <optimization>on ]
;
assert.result gcc-3.0
: minimize <toolset>gcc <toolset-gcc:version>3.0
;
assert.result gcc-3.0
: minimize <toolset-gcc:version>3.0 <toolset>gcc
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y/z/<a>b/c/<d>e/f
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y\\z\\<a>b\\c\\<d>e\\f
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a/b/c/<d>e/f/g/<h>i/j/k
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a\\b\\c\\<d>e\\f\\g\\<h>i\\j\\k
;
# test error checking
try ;
{
expand release <optimization>off <optimization>on ;
}
catch explicitly-specified values of non-free feature <optimization> conflict ;
try ;
{
validate-feature foobar ;
}
catch unknown feature ;
validate-value-string <toolset> gcc ;
validate-value-string <toolset> gcc-3.0.1 ;
try ;
{
validate-value-string <toolset> digital_mars ;
}
catch \"digital_mars\" is not a known value of <toolset> ;
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 <toolset> ;
try ;
{
implied-subfeature toolset not-a-version : gcc ;
}
catch \"not-a-version\" is not a known subfeature value of
feature <toolset> ;
# leave a clean copy of the features module behind
finish-test feature-test-temp ;
}

View File

@@ -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 ;

View File

@@ -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) ;

View File

@@ -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 *

View File

@@ -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 ;

View File

@@ -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 ] ]

View File

@@ -16,6 +16,7 @@ import regex ;
rule __test__
{
import assert ;
rule identity ( args * ) { return $(args) ; }
if ! ( --quiet in [ modules.peek : ARGV ] )

View File

@@ -6,21 +6,18 @@
# This module defines a special generator, which handles targets with
# <file> 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 : : * : <file> ;
import feature type errors path ;
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;

View File

@@ -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)> ;

View File

@@ -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 ] ] ;

View File

@@ -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) ;
}

View File

@@ -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 <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>on ;
}
compose <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>on ;
import assert ;
import class : new ;
validate gcc gcc-3.0.1 : $(test-space) ;
validate <toolset>gcc <toolset>gcc-3.0.1 : $(test-space) ;
@@ -587,6 +588,7 @@ local rule __test__ ( )
assert.result <toolset>gcc,<toolset-gcc:version>3.0 <define>FOO
: split-conditional <toolset>gcc,<toolset-gcc:version>3.0:<define>FOO
;
feature.finish-test property-test-temp ;
}

View File

@@ -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 ;

View File

@@ -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

View File

@@ -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 <location> :
@@ -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 ? )
{

View File

@@ -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) ;

View File

@@ -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,

View File

@@ -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 : * )
{

View File

@@ -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

View File

@@ -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) ;

View File

@@ -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

View File

@@ -11,6 +11,8 @@ import property ;
import generators ;
import os ;
import toolset : flags ;
import feature ;
import type ;
toolset.register borland ;

View File

@@ -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 <toolset>gcc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
<variant>debug/<toolset>msvc/<stdlib>stlport
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport
;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>off
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>release/<inlining>off
: build-request.expand-no-defaults gcc-3.0.1/stlport debug release <inlining>off
;
assert.result
<include>a/b/c/<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<variant>debug/<include>x/y/z
: build-request.expand-no-defaults <include>a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug <include>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 <runtime-link>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 <toolset>gcc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<stdlib>stlport/<variant>debug/<inlining>on/<runtime-link>dynamic
<toolset>msvc/<variant>debug/<inlining>on/<stdlib>native/<runtime-link>dynamic
: build-request.expand gcc-3.0.1/stlport msvc/stlport msvc debug
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
<toolset>msvc/<variant>debug
<variant>debug/<toolset>msvc/<stdlib>stlport
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport
: $(test-space) ;
assert.result
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>off
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>release/<inlining>off
: build-request.expand-no-defaults gcc-3.0.1/stlport debug release <inlining>off
: $(test-space) ;
assert.result
<include>a/b/c/<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<stdlib>stlport/<variant>debug/<include>x/y/z
<include>a/b/c/<toolset>msvc/<variant>debug/<include>x/y/z
: build-request.expand-no-defaults <include>a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug <include>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 <runtime-link>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 <runtime-link>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 <runtime-link>dynamic <runtime-link>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/<runtime-link>dynamic
gcc/<runtime-link>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/<runtime-link>static
borland/<runtime-link>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 <runtime-link>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 <runtime-link>dynamic <runtime-link>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/<runtime-link>dynamic
gcc/<runtime-link>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/<runtime-link>static
borland/<runtime-link>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 ;
}

View File

@@ -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 )
# <feature>value, and feature should be specified as <feature>.
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 <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>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 <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>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 <include>/path/to/stlport ;
}
rule handle-magic ( property : properties * )
{
return <define>MAGIC=$(property:G=) ;
}
rule handle-magic2 ( property : properties * )
{
return <define>MAGIC=BIG_MAGIC ;
}
rule handle-magic3 ( property : properties * )
{
return <define>MAGIC=VERY_BIG_MAGIC ;
}
action <stdlib>stlport : handle-stlport ;
action <magic> : handle-magic ;
action <magic>17 : handle-magic2 ;
action <magic>17 : handle-magic3 ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
: expand-subfeatures <toolset>gcc-3.0.1 ;
assert.result <define>foo=x-y
: expand-subfeatures <define>foo=x-y ;
assert.result <toolset>gcc <toolset-gcc:version>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 : <x>a <y>b <x>c <y>d <x>e ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
<variant>debug <define>_DEBUG <optimization>on
: expand gcc-3.0.1 debug <optimization>on
;
assert.result <variant>debug <define>_DEBUG <optimization>on
: expand debug <optimization>on
;
assert.result <optimization>on <variant>debug <define>_DEBUG
: expand <optimization>on debug
;
assert.result <runtime-link>dynamic <optimization>on
: defaults <runtime-link> <define> <optimization>
;
assert.result <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
<toolset>gcc <variant>debug <stdlib>native <dummy>dummy1
: add-defaults <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
;
assert.result <toolset>gcc <define>foo <stdlib>stlport <magic>3 <include>/path/to/stlport <define>MAGIC=3
: run-actions <toolset>gcc <define>foo <stdlib>stlport <magic>3
;
assert.result <magic>17 <define>MAGIC=BIG_MAGIC <define>MAGIC=VERY_BIG_MAGIC
: run-actions <magic>17
;
assert.result gcc-3.0.1 debug <optimization>on
: minimize [ expand gcc-3.0.1 debug <optimization>on <stdlib>native ]
;
assert.result gcc-3.0.1 debug <runtime-link>dynamic
: minimize [ expand gcc-3.0.1 debug <optimization>off <runtime-link>dynamic ]
;
assert.result gcc-3.0.1 debug
: minimize [ expand gcc-3.0.1 debug <optimization>off ]
;
assert.result debug <optimization>on
: minimize [ expand debug <optimization>on ]
;
assert.result gcc-3.0
: minimize <toolset>gcc <toolset-gcc:version>3.0
;
assert.result gcc-3.0
: minimize <toolset-gcc:version>3.0 <toolset>gcc
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y/z/<a>b/c/<d>e/f
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y\\z\\<a>b\\c\\<d>e\\f
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a/b/c/<d>e/f/g/<h>i/j/k
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a\\b\\c\\<d>e\\f\\g\\<h>i\\j\\k
;
# test error checking
try ;
{
expand release <optimization>off <optimization>on ;
}
catch explicitly-specified values of non-free feature <optimization> conflict ;
try ;
{
validate-feature foobar ;
}
catch unknown feature ;
validate-value-string <toolset> gcc ;
validate-value-string <toolset> gcc-3.0.1 ;
try ;
{
validate-value-string <toolset> digital_mars ;
}
catch \"digital_mars\" is not a known value of <toolset> ;
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 <toolset> ;
try ;
{
implied-subfeature toolset not-a-version : gcc ;
}
catch \"not-a-version\" is not a known subfeature value of
feature <toolset> ;
return <include>/path/to/stlport ;
}
local rule handle-magic ( property : properties * )
{
return <define>MAGIC=$(property:G=) ;
}
local rule handle-magic2 ( property : properties * )
{
return <define>MAGIC=BIG_MAGIC ;
}
local rule handle-magic3 ( property : properties * )
{
return <define>MAGIC=VERY_BIG_MAGIC ;
}
action <stdlib>stlport : handle-stlport ;
action <magic> : handle-magic ;
action <magic>17 : handle-magic2 ;
action <magic>17 : handle-magic3 ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
: expand-subfeatures <toolset>gcc-3.0.1 ;
assert.result <define>foo=x-y
: expand-subfeatures <define>foo=x-y ;
assert.result <toolset>gcc <toolset-gcc:version>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 : <x>a <y>b <x>c <y>d <x>e ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
<variant>debug <define>_DEBUG <optimization>on
: expand gcc-3.0.1 debug <optimization>on
;
assert.result <variant>debug <define>_DEBUG <optimization>on
: expand debug <optimization>on
;
assert.result <optimization>on <variant>debug <define>_DEBUG
: expand <optimization>on debug
;
assert.result <runtime-link>dynamic <optimization>on
: defaults <runtime-link> <define> <optimization>
;
assert.result <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
<toolset>gcc <variant>debug <stdlib>native <dummy>dummy1
: add-defaults <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
;
assert.result <toolset>gcc <define>foo <stdlib>stlport <magic>3 <include>/path/to/stlport <define>MAGIC=3
: run-actions <toolset>gcc <define>foo <stdlib>stlport <magic>3
;
assert.result <magic>17 <define>MAGIC=BIG_MAGIC <define>MAGIC=VERY_BIG_MAGIC
: run-actions <magic>17
;
assert.result gcc-3.0.1 debug <optimization>on
: minimize [ expand gcc-3.0.1 debug <optimization>on <stdlib>native ]
;
assert.result gcc-3.0.1 debug <runtime-link>dynamic
: minimize [ expand gcc-3.0.1 debug <optimization>off <runtime-link>dynamic ]
;
assert.result gcc-3.0.1 debug
: minimize [ expand gcc-3.0.1 debug <optimization>off ]
;
assert.result debug <optimization>on
: minimize [ expand debug <optimization>on ]
;
assert.result gcc-3.0
: minimize <toolset>gcc <toolset-gcc:version>3.0
;
assert.result gcc-3.0
: minimize <toolset-gcc:version>3.0 <toolset>gcc
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y/z/<a>b/c/<d>e/f
;
assert.result <x>y/z <a>b/c <d>e/f
: split <x>y\\z\\<a>b\\c\\<d>e\\f
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a/b/c/<d>e/f/g/<h>i/j/k
;
assert.result a b c <d>e/f/g <h>i/j/k
: split a\\b\\c\\<d>e\\f\\g\\<h>i\\j\\k
;
# test error checking
try ;
{
expand release <optimization>off <optimization>on ;
}
catch explicitly-specified values of non-free feature <optimization> conflict ;
try ;
{
validate-feature foobar ;
}
catch unknown feature ;
validate-value-string <toolset> gcc ;
validate-value-string <toolset> gcc-3.0.1 ;
try ;
{
validate-value-string <toolset> digital_mars ;
}
catch \"digital_mars\" is not a known value of <toolset> ;
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 <toolset> ;
try ;
{
implied-subfeature toolset not-a-version : gcc ;
}
catch \"not-a-version\" is not a known subfeature value of
feature <toolset> ;
# leave a clean copy of the features module behind
finish-test feature-test-temp ;
}

View File

@@ -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) ;

View File

@@ -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 ] ] ;

View File

@@ -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) ;
}

View File

@@ -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 <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>on ;
}
compose <variant>debug : <define>_DEBUG <optimization>off ;
compose <variant>release : <define>NDEBUG <optimization>on ;
import assert ;
import class : new ;
validate gcc gcc-3.0.1 : $(test-space) ;
validate <toolset>gcc <toolset>gcc-3.0.1 : $(test-space) ;
@@ -587,6 +588,7 @@ local rule __test__ ( )
assert.result <toolset>gcc,<toolset-gcc:version>3.0 <define>FOO
: split-conditional <toolset>gcc,<toolset-gcc:version>3.0:<define>FOO
;
feature.finish-test property-test-temp ;
}

View File

@@ -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 ;

View File

@@ -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,

View File

@@ -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 : * )
{

View File

@@ -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

View File

@@ -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) ;

View File

@@ -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 ;

View File

@@ -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 ;
}

View File

@@ -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 ;

View File

@@ -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 ] ]

View File

@@ -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)> ;

View File

@@ -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 <target-os> and <host-os>
@@ -147,11 +149,12 @@ variant release : <optimization>speed <debug-symbols>off <inlining>full <runtime
# not propagated, we can't just add it to 'release'. And we cannot make
# <define> 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 <define>NDEBUG ;
}
feature.action <optimization>speed : builtin.handle-ndebug ;
feature.action <optimization>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 <library> properties
# For each source/property-value, which is instance of searched-lib-target,
# add appropriate <find-shared-library> or <find-static-library> property.
@@ -668,6 +675,6 @@ declare-type : RSP : rsp ;
flags builtin.response-file FINDLIBS_ST <find-static-library> ;
flags builtin.response-file FINDLIBS_SA <find-shared-library> ;
flags builtin.response-file LIBRARY_PATH <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 ;

View File

@@ -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 *

View File

@@ -6,21 +6,18 @@
# This module defines a special generator, which handles targets with
# <file> 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 : : * : <file> ;
import feature type errors path ;
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;

View File

@@ -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 <location> :
@@ -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 ? )
{

View File

@@ -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) ;

View File

@@ -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 ;

View File

@@ -16,6 +16,7 @@ import regex ;
rule __test__
{
import assert ;
rule identity ( args * ) { return $(args) ; }
if ! ( --quiet in [ modules.peek : ARGV ] )

View File

@@ -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