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:
@@ -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
|
||||
|
||||
@@ -11,6 +11,8 @@ import property ;
|
||||
import generators ;
|
||||
import os ;
|
||||
import toolset : flags ;
|
||||
import feature ;
|
||||
import type ;
|
||||
|
||||
toolset.register borland ;
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
|
||||
384
new/class.jam
384
new/class.jam
@@ -80,10 +80,15 @@ local rule __init__ (
|
||||
# initialization function.
|
||||
)
|
||||
{
|
||||
|
||||
# pull the name of the class being initialized from the backtrace
|
||||
local bt = [ BACKTRACE 1 ] ;
|
||||
local class = [ MATCH ^(.*)[.]__init__$ : $(bt[4]) ] ;
|
||||
assert.nonempty-variable class ;
|
||||
if ! $(class)
|
||||
{
|
||||
import errors : error ;
|
||||
error couldn't extract class name from backtrace ;
|
||||
}
|
||||
|
||||
# set the __class__
|
||||
__class__ ?= $(class) ;
|
||||
@@ -106,7 +111,8 @@ local rule __init__ (
|
||||
{
|
||||
if ! $($(b).__init__.called)
|
||||
{
|
||||
errors.error $(class).$(class) failed to call base class constructor $(b).__init__ ;
|
||||
import errors : error ;
|
||||
error $(class).$(class) failed to call base class constructor $(b).__init__ ;
|
||||
}
|
||||
}
|
||||
# Make all the class' member rules available as qualified names
|
||||
@@ -220,14 +226,19 @@ rule instance ( name : class args * : * )
|
||||
rule new ( class args * : * )
|
||||
{
|
||||
.next-instance.$(class) ?= 1 ;
|
||||
local name = object($(class))@$(.next-instance.$(class)) ;
|
||||
instance $(name) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
||||
local id = object($(class))@$(.next-instance.$(class)) ;
|
||||
instance $(id) : $(class) $(args) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
||||
|
||||
# import the instance's methods, with qualification, into the
|
||||
# global namespace.
|
||||
local methods = [ RULENAMES $(id) ] ;
|
||||
IMPORT $(id) : $(methods) : : $(id).$(methods) ;
|
||||
|
||||
# bump the next unique object name
|
||||
.next-instance.$(class) = [ numbers.increment $(.next-instance.$(class)) ] ;
|
||||
|
||||
# Return the name of the new instance.
|
||||
return $(name) ;
|
||||
return $(id) ;
|
||||
}
|
||||
|
||||
rule bases ( class )
|
||||
@@ -300,215 +311,212 @@ local rule typecheck ( x )
|
||||
}
|
||||
}
|
||||
|
||||
rule __test__ ( )
|
||||
local rule __test__ ( )
|
||||
{
|
||||
module class.__test__
|
||||
import class : * ;
|
||||
import assert ;
|
||||
import errors : * ;
|
||||
|
||||
# This will be the construction function for a class called
|
||||
# 'myclass'
|
||||
local rule myclass ( x_ * : y_ * )
|
||||
{
|
||||
import class : * ;
|
||||
import assert ;
|
||||
import errors : * ;
|
||||
|
||||
# This will be the construction function for a class called
|
||||
# 'myclass'
|
||||
local rule myclass ( x_ * : y_ * )
|
||||
# set some instance variables
|
||||
x = $(x_) ;
|
||||
y = $(y_) ;
|
||||
|
||||
rule set-x ( newx * )
|
||||
{
|
||||
# set some instance variables
|
||||
x = $(x_) ;
|
||||
y = $(y_) ;
|
||||
|
||||
rule set-x ( newx * )
|
||||
{
|
||||
x = $(newx) ;
|
||||
}
|
||||
|
||||
rule get-x ( )
|
||||
x = $(newx) ;
|
||||
}
|
||||
|
||||
rule get-x ( )
|
||||
{
|
||||
return $(x) ;
|
||||
}
|
||||
|
||||
rule set-y ( newy * )
|
||||
{
|
||||
y = $(newy) ;
|
||||
}
|
||||
|
||||
rule get-y ( )
|
||||
{
|
||||
return $(y) ;
|
||||
}
|
||||
|
||||
rule f ( )
|
||||
{
|
||||
return [ g $(x) ] ;
|
||||
}
|
||||
|
||||
rule g ( args * )
|
||||
{
|
||||
if $(x) in $(y)
|
||||
{
|
||||
return $(x) ;
|
||||
}
|
||||
|
||||
rule set-y ( newy * )
|
||||
{
|
||||
y = $(newy) ;
|
||||
}
|
||||
|
||||
rule get-y ( )
|
||||
else if $(y) in $(x)
|
||||
{
|
||||
return $(y) ;
|
||||
}
|
||||
|
||||
rule f ( )
|
||||
else
|
||||
{
|
||||
return [ g $(x) ] ;
|
||||
}
|
||||
|
||||
rule g ( args * )
|
||||
{
|
||||
if $(x) in $(y)
|
||||
{
|
||||
return $(x) ;
|
||||
}
|
||||
else if $(y) in $(x)
|
||||
{
|
||||
return $(y) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
rule get-class ( )
|
||||
{
|
||||
return $(__class__) ;
|
||||
return ;
|
||||
}
|
||||
}
|
||||
class myclass ;
|
||||
|
||||
local rule derived1 ( z_ )
|
||||
|
||||
rule get-class ( )
|
||||
{
|
||||
myclass.__init__ $(z_) : X ;
|
||||
z = $(z_) ;
|
||||
|
||||
# override g
|
||||
rule g ( args * )
|
||||
{
|
||||
return derived1.g ;
|
||||
}
|
||||
|
||||
rule h ( )
|
||||
{
|
||||
return derived1.h ;
|
||||
}
|
||||
|
||||
rule get-z ( )
|
||||
{
|
||||
return $(z) ;
|
||||
}
|
||||
return $(__class__) ;
|
||||
}
|
||||
class derived1 : myclass ;
|
||||
|
||||
local rule derived2 ( )
|
||||
}
|
||||
class myclass ;
|
||||
|
||||
local rule derived1 ( z_ )
|
||||
{
|
||||
myclass.__init__ $(z_) : X ;
|
||||
z = $(z_) ;
|
||||
|
||||
# override g
|
||||
rule g ( args * )
|
||||
{
|
||||
myclass.__init__ 1 : 2 ;
|
||||
|
||||
# override g
|
||||
rule g ( args * )
|
||||
{
|
||||
return derived2.g ;
|
||||
}
|
||||
|
||||
rule get-x ( )
|
||||
{
|
||||
# Test the ability to call base class functions with qualification.
|
||||
return [ myclass.get-x ] ;
|
||||
}
|
||||
return derived1.g ;
|
||||
}
|
||||
class derived2 : myclass ;
|
||||
|
||||
local rule derived2a ( )
|
||||
|
||||
rule h ( )
|
||||
{
|
||||
derived2.__init__ ;
|
||||
return derived1.h ;
|
||||
}
|
||||
class derived2a : derived2 ;
|
||||
|
||||
local rule expect_derived2 ( [derived2] x ) { }
|
||||
|
||||
local rule bad_subclass ( )
|
||||
|
||||
rule get-z ( )
|
||||
{
|
||||
# fails to call base class __init__ function
|
||||
return $(z) ;
|
||||
}
|
||||
class bad_subclass : myclass ;
|
||||
|
||||
local a = [ new myclass 3 4 5 : 4 5 ] ;
|
||||
local b = [ new derived1 4 ] ;
|
||||
local c = [ new derived2 ] ;
|
||||
local d = [ new derived2 ] ;
|
||||
local e = [ new derived2a ] ;
|
||||
|
||||
expect_derived2 $(d) ;
|
||||
expect_derived2 $(e) ;
|
||||
|
||||
# argument checking is set up to call exit(1) directly on
|
||||
# failure, and we can't hijack that with try, so we'd better
|
||||
# not do this test by default. We could fix this by having
|
||||
# errors look up and invoke the EXIT rule instead; EXIT can be
|
||||
# hijacked ;-)
|
||||
if --fail-typecheck in [ modules.peek : ARGV ]
|
||||
}
|
||||
class derived1 : myclass ;
|
||||
|
||||
local rule derived2 ( )
|
||||
{
|
||||
myclass.__init__ 1 : 2 ;
|
||||
|
||||
# override g
|
||||
rule g ( args * )
|
||||
{
|
||||
try ;
|
||||
{
|
||||
expect_derived2 $(a) ;
|
||||
}
|
||||
catch
|
||||
"Expected an instance of derived2 but got" instead
|
||||
;
|
||||
return derived2.g ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
rule get-x ( )
|
||||
{
|
||||
# Test the ability to call base class functions with qualification.
|
||||
return [ myclass.get-x ] ;
|
||||
}
|
||||
}
|
||||
class derived2 : myclass ;
|
||||
|
||||
local rule derived2a ( )
|
||||
{
|
||||
derived2.__init__ ;
|
||||
}
|
||||
class derived2a : derived2 ;
|
||||
|
||||
local rule expect_derived2 ( [derived2] x ) { }
|
||||
|
||||
local rule bad_subclass ( )
|
||||
{
|
||||
# fails to call base class __init__ function
|
||||
}
|
||||
class bad_subclass : myclass ;
|
||||
|
||||
local a = [ new myclass 3 4 5 : 4 5 ] ;
|
||||
local b = [ new derived1 4 ] ;
|
||||
local c = [ new derived2 ] ;
|
||||
local d = [ new derived2 ] ;
|
||||
local e = [ new derived2a ] ;
|
||||
|
||||
expect_derived2 $(d) ;
|
||||
expect_derived2 $(e) ;
|
||||
|
||||
# argument checking is set up to call exit(1) directly on
|
||||
# failure, and we can't hijack that with try, so we'd better
|
||||
# not do this test by default. We could fix this by having
|
||||
# errors look up and invoke the EXIT rule instead; EXIT can be
|
||||
# hijacked (;-)
|
||||
if --fail-typecheck in [ modules.peek : ARGV ]
|
||||
{
|
||||
try ;
|
||||
{
|
||||
new bad_subclass ;
|
||||
expect_derived2 $(a) ;
|
||||
}
|
||||
catch
|
||||
bad_subclass.bad_subclass failed to call base class constructor myclass.__init__
|
||||
"Expected an instance of derived2 but got" instead
|
||||
;
|
||||
|
||||
try ;
|
||||
{
|
||||
class bad_subclass ;
|
||||
}
|
||||
catch bad_subclass has already been declared ;
|
||||
|
||||
assert.result 3 4 5 : $(a).get-x ;
|
||||
assert.result 4 5 : $(a).get-y ;
|
||||
assert.result 4 : $(b).get-x ;
|
||||
assert.result X : $(b).get-y ;
|
||||
assert.result 4 : $(b).get-z ;
|
||||
assert.result 1 : $(c).get-x ;
|
||||
assert.result 2 : $(c).get-y ;
|
||||
assert.result 4 5 : $(a).f ;
|
||||
assert.result derived1.g : $(b).f ;
|
||||
assert.result derived2.g : $(c).f ;
|
||||
assert.result derived2.g : $(d).f ;
|
||||
|
||||
# Check that the __class__ attribute is getting properly set.
|
||||
assert.result myclass : $(a).get-class ;
|
||||
assert.result derived1 : $(b).get-class ;
|
||||
|
||||
$(a).set-x a.x ;
|
||||
$(b).set-x b.x ;
|
||||
$(c).set-x c.x ;
|
||||
$(d).set-x d.x ;
|
||||
assert.result a.x : $(a).get-x ;
|
||||
assert.result b.x : $(b).get-x ;
|
||||
assert.result c.x : $(c).get-x ;
|
||||
assert.result d.x : $(d).get-x ;
|
||||
|
||||
rule derived3 ( )
|
||||
{
|
||||
}
|
||||
class derived3 : derived1 derived2 ;
|
||||
|
||||
assert.result : bases myclass ;
|
||||
assert.result myclass : bases derived1 ;
|
||||
assert.result myclass : bases derived2 ;
|
||||
assert.result derived1 derived2 : bases derived3 ;
|
||||
|
||||
assert.true is-derived derived1 : myclass ;
|
||||
assert.true is-derived derived2 : myclass ;
|
||||
assert.true is-derived derived3 : derived1 ;
|
||||
assert.true is-derived derived3 : derived2 ;
|
||||
assert.true is-derived derived3 : derived1 derived2 myclass ;
|
||||
assert.true is-derived derived3 : myclass ;
|
||||
|
||||
assert.false is-derived myclass : derived1 ;
|
||||
|
||||
assert.true is-instance $(a) ;
|
||||
assert.false is-instance bar ;
|
||||
|
||||
assert.true is-a $(a) : myclass ;
|
||||
assert.true is-a $(c) : derived2 ;
|
||||
assert.true is-a $(d) : myclass ;
|
||||
assert.false is-a literal : myclass ;
|
||||
}
|
||||
|
||||
|
||||
try ;
|
||||
{
|
||||
new bad_subclass ;
|
||||
}
|
||||
catch
|
||||
bad_subclass.bad_subclass failed to call base class constructor myclass.__init__
|
||||
;
|
||||
|
||||
try ;
|
||||
{
|
||||
class bad_subclass ;
|
||||
}
|
||||
catch bad_subclass has already been declared ;
|
||||
|
||||
assert.result 3 4 5 : $(a).get-x ;
|
||||
assert.result 4 5 : $(a).get-y ;
|
||||
assert.result 4 : $(b).get-x ;
|
||||
assert.result X : $(b).get-y ;
|
||||
assert.result 4 : $(b).get-z ;
|
||||
assert.result 1 : $(c).get-x ;
|
||||
assert.result 2 : $(c).get-y ;
|
||||
assert.result 4 5 : $(a).f ;
|
||||
assert.result derived1.g : $(b).f ;
|
||||
assert.result derived2.g : $(c).f ;
|
||||
assert.result derived2.g : $(d).f ;
|
||||
|
||||
# Check that the __class__ attribute is getting properly set.
|
||||
assert.result myclass : $(a).get-class ;
|
||||
assert.result derived1 : $(b).get-class ;
|
||||
|
||||
$(a).set-x a.x ;
|
||||
$(b).set-x b.x ;
|
||||
$(c).set-x c.x ;
|
||||
$(d).set-x d.x ;
|
||||
assert.result a.x : $(a).get-x ;
|
||||
assert.result b.x : $(b).get-x ;
|
||||
assert.result c.x : $(c).get-x ;
|
||||
assert.result d.x : $(d).get-x ;
|
||||
|
||||
rule derived3 ( )
|
||||
{
|
||||
}
|
||||
class derived3 : derived1 derived2 ;
|
||||
|
||||
assert.result : bases myclass ;
|
||||
assert.result myclass : bases derived1 ;
|
||||
assert.result myclass : bases derived2 ;
|
||||
assert.result derived1 derived2 : bases derived3 ;
|
||||
|
||||
assert.true is-derived derived1 : myclass ;
|
||||
assert.true is-derived derived2 : myclass ;
|
||||
assert.true is-derived derived3 : derived1 ;
|
||||
assert.true is-derived derived3 : derived2 ;
|
||||
assert.true is-derived derived3 : derived1 derived2 myclass ;
|
||||
assert.true is-derived derived3 : myclass ;
|
||||
|
||||
assert.false is-derived myclass : derived1 ;
|
||||
|
||||
assert.true is-instance $(a) ;
|
||||
assert.false is-instance bar ;
|
||||
|
||||
assert.true is-a $(a) : myclass ;
|
||||
assert.true is-a $(c) : derived2 ;
|
||||
assert.true is-a $(d) : myclass ;
|
||||
assert.false is-a literal : myclass ;
|
||||
}
|
||||
@@ -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 ;
|
||||
|
||||
507
new/feature.jam
507
new/feature.jam
@@ -5,34 +5,73 @@
|
||||
|
||||
import class : * ;
|
||||
|
||||
# A feature-space is a class to facilitate testing. We want to be able
|
||||
# to make and populate instances of a feature-space for testing
|
||||
# purposes without intruding on the default feature-space
|
||||
local rule feature-space ( )
|
||||
{
|
||||
import errors : error lol->list ;
|
||||
import sequence ;
|
||||
import regex ;
|
||||
import set ;
|
||||
import utility ;
|
||||
import modules ;
|
||||
|
||||
.all-attributes =
|
||||
local rule setup ( )
|
||||
{
|
||||
.all-attributes =
|
||||
|
||||
implicit
|
||||
executed
|
||||
composite
|
||||
optional
|
||||
symmetric
|
||||
free
|
||||
incidental
|
||||
path
|
||||
dependency
|
||||
propagated
|
||||
link-incompatible
|
||||
;
|
||||
implicit
|
||||
executed
|
||||
composite
|
||||
optional
|
||||
symmetric
|
||||
free
|
||||
incidental
|
||||
path
|
||||
dependency
|
||||
propagated
|
||||
link-incompatible
|
||||
;
|
||||
|
||||
.all-features = ;
|
||||
.all-implicit-values = ;
|
||||
}
|
||||
setup ;
|
||||
|
||||
# prepare a fresh space to test in by moving all global variable
|
||||
# settings into the given temporary module and erasing them here.
|
||||
rule prepare-test ( temp-module )
|
||||
{
|
||||
DELETE_MODULE $(temp-module) ;
|
||||
|
||||
# transfer globals to temp-module
|
||||
for local v in [ VARNAMES feature ]
|
||||
{
|
||||
if [ MATCH (\\.) : $(v) ]
|
||||
{
|
||||
modules.poke $(temp-module) : $(v) : $($(v)) ;
|
||||
$(v) = ;
|
||||
}
|
||||
}
|
||||
setup ;
|
||||
}
|
||||
|
||||
# clear out all global variables and recover all variables from the
|
||||
# given temporary module
|
||||
rule finish-test ( temp-module )
|
||||
{
|
||||
# clear globals
|
||||
for local v in [ VARNAMES feature ]
|
||||
{
|
||||
if [ MATCH (\\.) : $(v) ]
|
||||
{
|
||||
$(v) = ;
|
||||
}
|
||||
}
|
||||
|
||||
for local v in [ VARNAMES $(temp-module) ]
|
||||
{
|
||||
$(v) = [ modules.peek $(temp-module) : $(v) ] ;
|
||||
}
|
||||
DELETE_MODULE $(temp-module) ;
|
||||
}
|
||||
|
||||
.all-features = ;
|
||||
.all-implicit-values = ;
|
||||
|
||||
# Transform features by bracketing any elements which aren't already
|
||||
# bracketed by "<>"
|
||||
@@ -79,7 +118,7 @@ rule feature (
|
||||
{
|
||||
error $(error)
|
||||
: "in" feature declaration:
|
||||
: feature [ errors.lol->list $(1) : $(2) : $(3) ] ;
|
||||
: feature [ lol->list $(1) : $(2) : $(3) ] ;
|
||||
}
|
||||
|
||||
$(name).values ?= ;
|
||||
@@ -808,17 +847,8 @@ rule split ( property-set )
|
||||
# <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 ;
|
||||
}
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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 ] ]
|
||||
|
||||
@@ -16,6 +16,7 @@ import regex ;
|
||||
|
||||
rule __test__
|
||||
{
|
||||
import assert ;
|
||||
rule identity ( args * ) { return $(args) ; }
|
||||
|
||||
if ! ( --quiet in [ modules.peek : ARGV ] )
|
||||
|
||||
@@ -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 ] ;
|
||||
|
||||
@@ -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)> ;
|
||||
|
||||
|
||||
@@ -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 ] ] ;
|
||||
|
||||
@@ -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) ;
|
||||
}
|
||||
|
||||
110
new/property.jam
110
new/property.jam
@@ -8,7 +8,11 @@ import utility : ungrist ;
|
||||
import sequence : unique ;
|
||||
import errors : error ;
|
||||
import class : class ;
|
||||
|
||||
import feature ;
|
||||
import regex ;
|
||||
import sequence ;
|
||||
import set ;
|
||||
import path ;
|
||||
|
||||
# Refines 'properties' by overriding any elements for which a different
|
||||
# value is specified in 'requirements'. If the resulting property set
|
||||
@@ -17,10 +21,8 @@ import class : class ;
|
||||
# On success, returns properties. On error, returns a list which first
|
||||
# element is "@error" and the other elements compose the explanation
|
||||
# string.
|
||||
rule refine ( properties * : requirements * : feature-space ? )
|
||||
rule refine ( properties * : requirements * )
|
||||
{
|
||||
feature-space ?= feature ;
|
||||
|
||||
local result ;
|
||||
local error ;
|
||||
|
||||
@@ -38,7 +40,7 @@ rule refine ( properties * : requirements * : feature-space ? )
|
||||
for local p in $(properties)
|
||||
{
|
||||
# No processing for free properties
|
||||
if free in [ $(feature-space).attributes $(p:G) ]
|
||||
if free in [ feature.attributes $(p:G) ]
|
||||
{
|
||||
result += $(p) ;
|
||||
}
|
||||
@@ -50,7 +52,7 @@ rule refine ( properties * : requirements * : feature-space ? )
|
||||
local value = $(p:G=) ;
|
||||
if $(value) != $(required-value)
|
||||
{
|
||||
if link-incompatible in [ $(feature-space).attributes $(p:G) ]
|
||||
if link-incompatible in [ feature.attributes $(p:G) ]
|
||||
{
|
||||
error = @error link-incompatible properties $(p) and
|
||||
$(p:G)$(required-value) ;
|
||||
@@ -134,7 +136,7 @@ rule evaluate-conditionals ( properties * )
|
||||
# Helper for as-path, below. Orders properties with the implicit ones
|
||||
# first, and within the two sections in alphabetical order of feature
|
||||
# name.
|
||||
local rule path-order ( feature-space x y )
|
||||
local rule path-order ( x y )
|
||||
{
|
||||
if $(y:G) && ! $(x:G)
|
||||
{
|
||||
@@ -148,8 +150,8 @@ local rule path-order ( feature-space x y )
|
||||
{
|
||||
if ! $(x:G)
|
||||
{
|
||||
x = [ $(feature-space).expand-subfeatures $(x) ] ;
|
||||
y = [ $(feature-space).expand-subfeatures $(y) ] ;
|
||||
x = [ feature.expand-subfeatures $(x) ] ;
|
||||
y = [ feature.expand-subfeatures $(y) ] ;
|
||||
}
|
||||
|
||||
if $(x[1]) < $(y[1])
|
||||
@@ -160,19 +162,17 @@ local rule path-order ( feature-space x y )
|
||||
}
|
||||
|
||||
# Returns a path which represents the given expanded property set.
|
||||
rule as-path ( properties * : feature-space ? )
|
||||
rule as-path ( properties * )
|
||||
{
|
||||
feature-space ?= feature ;
|
||||
|
||||
local entry = .result.$(properties:J=-).$(feature-space) ;
|
||||
local entry = .result.$(properties:J=-) ;
|
||||
|
||||
if ! $($(entry))
|
||||
{
|
||||
# trim redundancy
|
||||
properties = [ $(feature-space).minimize $(properties) ] ;
|
||||
properties = [ feature.minimize $(properties) ] ;
|
||||
|
||||
# sort according to path-order
|
||||
properties = [ sequence.insertion-sort $(properties) : path-order $(feature-space) ] ;
|
||||
properties = [ sequence.insertion-sort $(properties) : path-order ] ;
|
||||
|
||||
local components ;
|
||||
for local p in $(properties)
|
||||
@@ -195,22 +195,21 @@ rule as-path ( properties * : feature-space ? )
|
||||
}
|
||||
|
||||
# Exit with error if property is not valid.
|
||||
local rule validate1 ( property : feature-space ? )
|
||||
local rule validate1 ( property )
|
||||
{
|
||||
feature-space ?= feature ;
|
||||
local msg ;
|
||||
if $(property:G)
|
||||
{
|
||||
local feature = [ ungrist $(property:G) ] ; # Ungrist for better error messages
|
||||
local value = $(property:G=) ;
|
||||
|
||||
if ! [ $(feature-space).valid $(feature) ]
|
||||
if ! [ feature.valid $(feature) ]
|
||||
{
|
||||
msg = "unknown feature '$(feature)'" ;
|
||||
}
|
||||
else if $(value) && ! free in [ $(feature-space).attributes $(feature) ]
|
||||
else if $(value) && ! free in [ feature.attributes $(feature) ]
|
||||
{
|
||||
$(feature-space).validate-value-string $(feature) $(value) ;
|
||||
feature.validate-value-string $(feature) $(value) ;
|
||||
}
|
||||
else if ! $(value)
|
||||
{
|
||||
@@ -219,8 +218,8 @@ local rule validate1 ( property : feature-space ? )
|
||||
}
|
||||
else
|
||||
{
|
||||
local feature = [ $(feature-space).implied-feature $(property) ] ;
|
||||
$(feature-space).validate-value-string $(feature) $(property) ;
|
||||
local feature = [ feature.implied-feature $(property) ] ;
|
||||
feature.validate-value-string $(feature) $(property) ;
|
||||
}
|
||||
if $(msg)
|
||||
{
|
||||
@@ -228,25 +227,24 @@ local rule validate1 ( property : feature-space ? )
|
||||
}
|
||||
}
|
||||
|
||||
rule validate ( properties * : feature-space ? )
|
||||
rule validate ( properties * )
|
||||
{
|
||||
for local p in $(properties)
|
||||
{
|
||||
validate1 $(p) : $(feature-space) ;
|
||||
validate1 $(p) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule validate-property-sets ( property-sets * : feature-space ? )
|
||||
rule validate-property-sets ( property-sets * )
|
||||
{
|
||||
for local s in $(property-sets)
|
||||
{
|
||||
validate [ feature.split $(s) ] : $(feature-space) ;
|
||||
validate [ feature.split $(s) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
# Makes a property set from 'specification', converting implicit values into
|
||||
# full properties.
|
||||
# TODO: Might want to use 'feature-space' here as well as in other rules.
|
||||
rule make ( specification * )
|
||||
{
|
||||
local result ;
|
||||
@@ -271,13 +269,12 @@ rule make ( specification * )
|
||||
|
||||
# Returns a property sets which include all the elements in 'properties' that
|
||||
# do not have attributes listed in 'attributes'.
|
||||
rule remove ( attributes + : properties * : feature-space ? )
|
||||
rule remove ( attributes + : properties * )
|
||||
{
|
||||
feature-space ?= feature ;
|
||||
local result ;
|
||||
for local e in $(properties)
|
||||
{
|
||||
if ! [ set.intersection $(attributes) : [ $(feature-space).attributes $(e:G) ] ]
|
||||
if ! [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
|
||||
{
|
||||
result += $(e) ;
|
||||
}
|
||||
@@ -287,13 +284,12 @@ rule remove ( attributes + : properties * : feature-space ? )
|
||||
|
||||
# Returns a property set which include all properties in 'properties' that have
|
||||
# any of 'attributes'.
|
||||
rule take ( attributes + : properties * : feature-space ? )
|
||||
rule take ( attributes + : properties * )
|
||||
{
|
||||
feature-space ?= feature ;
|
||||
local result ;
|
||||
for local e in $(properties)
|
||||
{
|
||||
if [ set.intersection $(attributes) : [ $(feature-space).attributes $(e:G) ] ]
|
||||
if [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
|
||||
{
|
||||
result += $(e) ;
|
||||
}
|
||||
@@ -392,6 +388,10 @@ rule translate-paths ( properties * : path )
|
||||
# mapping
|
||||
rule property-map ( )
|
||||
{
|
||||
import numbers ;
|
||||
import sequence ;
|
||||
import errors : error ;
|
||||
|
||||
self.next-flag = 1 ;
|
||||
|
||||
# Associate 'value' with 'properties'
|
||||
@@ -434,7 +434,7 @@ rule property-map ( )
|
||||
$(matches) : $(match-ranks) ] ;
|
||||
if $(best[2])
|
||||
{
|
||||
errors.error "Ambiguous key" ;
|
||||
error "Ambiguous key" ;
|
||||
}
|
||||
local original = $(self.value.$(best)) ;
|
||||
if $(value)
|
||||
@@ -450,29 +450,30 @@ class property-map ;
|
||||
|
||||
local rule __test__ ( )
|
||||
{
|
||||
import class : new ;
|
||||
import errors : try catch ;
|
||||
import feature ;
|
||||
import feature : feature subfeature compose ;
|
||||
|
||||
# local rules must be explicitly re-imported
|
||||
import property : path-order ;
|
||||
|
||||
feature.prepare-test property-test-temp ;
|
||||
|
||||
local test-space = [ new feature-space ] ;
|
||||
feature toolset : gcc : implicit ;
|
||||
subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4
|
||||
3.0 3.0.1 3.0.2 : optional ;
|
||||
feature define : : free ;
|
||||
feature runtime-link : dynamic static : symmetric link-incompatible ;
|
||||
feature optimization : on off ;
|
||||
feature variant : debug release : implicit composite ;
|
||||
feature rtti : on off : link-incompatible ;
|
||||
|
||||
module $(test-space)
|
||||
{
|
||||
import assert ;
|
||||
|
||||
feature toolset : gcc : implicit ;
|
||||
subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4
|
||||
3.0 3.0.1 3.0.2 : optional ;
|
||||
feature define : : free ;
|
||||
feature runtime-link : dynamic static : symmetric link-incompatible ;
|
||||
feature optimization : on off ;
|
||||
feature variant : debug release : implicit composite ;
|
||||
feature rtti : on off : link-incompatible ;
|
||||
|
||||
compose <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 ;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 ? )
|
||||
{
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 : * )
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -11,6 +11,8 @@ import property ;
|
||||
import generators ;
|
||||
import os ;
|
||||
import toolset : flags ;
|
||||
import feature ;
|
||||
import type ;
|
||||
|
||||
toolset.register borland ;
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -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 ] ] ;
|
||||
|
||||
@@ -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) ;
|
||||
}
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 : * )
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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 ;
|
||||
}
|
||||
@@ -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 ;
|
||||
|
||||
@@ -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 ] ]
|
||||
|
||||
@@ -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)> ;
|
||||
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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 ] ;
|
||||
|
||||
@@ -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 ? )
|
||||
{
|
||||
|
||||
@@ -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) ;
|
||||
|
||||
@@ -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 ;
|
||||
|
||||
@@ -16,6 +16,7 @@ import regex ;
|
||||
|
||||
rule __test__
|
||||
{
|
||||
import assert ;
|
||||
rule identity ( args * ) { return $(args) ; }
|
||||
|
||||
if ! ( --quiet in [ modules.peek : ARGV ] )
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user