|
|
|
|
|
|
|
|
|
import "class" : new ; |
|
import sequence ; |
|
import set ; |
|
import regex ; |
|
import feature ; |
|
import property ; |
|
import container ; |
|
import string ; |
|
|
|
|
|
|
|
|
|
local rule apply-to-property-set ( f property-set ) |
|
{ |
|
local properties = [ feature.split $(property-set) ] ; |
|
return [ string.join [ $(f) $(properties) ] : / ] ; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
rule expand-no-defaults ( property-sets * ) |
|
{ |
|
|
|
local expanded-property-sets = [ sequence.transform apply-to-property-set |
|
feature.expand-subfeatures : $(property-sets) ] ; |
|
|
|
|
|
local product = [ x-product $(expanded-property-sets) : $(feature-space) ] ; |
|
|
|
return $(product) ; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
local rule x-product-aux ( property-sets + ) |
|
{ |
|
local result ; |
|
local p = [ feature.split $(property-sets[1]) ] ; |
|
local f = [ set.difference $(p:G) : [ feature.free-features ] ] ; |
|
local seen ; |
|
|
|
if ! [ set.intersection $(f) : $(x-product-used) ] |
|
{ |
|
local x-product-seen ; |
|
{ |
|
|
|
local x-product-used = $(x-product-used) $(f) ; |
|
|
|
if $(property-sets[2]) |
|
{ |
|
local rest = [ x-product-aux $(property-sets[2-]) : $(feature-space) ] ; |
|
result = $(property-sets[1])/$(rest) ; |
|
} |
|
|
|
result ?= $(property-sets[1]) ; |
|
} |
|
|
|
|
|
|
|
if ! [ set.intersection $(f) : $(x-product-seen) ] |
|
{ |
|
property-sets = ; |
|
} |
|
|
|
seen = $(x-product-seen) ; |
|
} |
|
|
|
if $(property-sets[2]) |
|
{ |
|
result += [ x-product-aux $(property-sets[2-]) : $(feature-space) ] ; |
|
} |
|
|
|
|
|
|
|
x-product-seen += $(f) $(seen) ; |
|
return $(result) ; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
local rule x-product ( property-sets * ) |
|
{ |
|
if $(property-sets).non-empty |
|
{ |
|
|
|
|
|
local x-product-seen x-product-used ; |
|
return [ x-product-aux $(property-sets) : $(feature-space) ] ; |
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
local rule looks-like-implicit-value ( v ) |
|
{ |
|
if [ feature.is-implicit-value $(v) ] |
|
{ |
|
return true ; |
|
} |
|
else |
|
{ |
|
local split = [ regex.split $(v) - ] ; |
|
if [ feature.is-implicit-value $(split[1]) ] |
|
{ |
|
return true ; |
|
} |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rule from-command-line ( command-line * ) |
|
{ |
|
local targets ; |
|
local properties ; |
|
|
|
command-line = $(command-line[2-]) ; |
|
local skip-next = ; |
|
for local e in $(command-line) |
|
{ |
|
if $(skip-next) |
|
{ |
|
skip-next = ; |
|
} |
|
else if ! [ MATCH "^(-).*" : $(e) ] |
|
{ |
|
|
|
|
|
local fs = feature-space ; |
|
if [ MATCH "(.*=.*)" : $(e) ] |
|
|| [ looks-like-implicit-value $(e:D=) : $(feature-space) ] |
|
{ |
|
properties += [ convert-command-line-element $(e) : |
|
$(feature-space) ] ; |
|
} |
|
else |
|
{ |
|
targets += $(e) ; |
|
} |
|
} |
|
else if [ MATCH "^(-[-ldjfsto])$" : $(e) ] |
|
{ |
|
skip-next = true ; |
|
} |
|
} |
|
return [ new vector |
|
[ new vector $(targets) ] |
|
[ new vector $(properties) ] ] ; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
local rule convert-command-line-element ( e ) |
|
{ |
|
local result ; |
|
local parts = [ regex.split $(e) "/" ] ; |
|
while $(parts) |
|
{ |
|
local p = $(parts[1]) ; |
|
local m = [ MATCH "([^=]*)=(.*)" : $(p) ] ; |
|
local lresult ; |
|
local feature ; |
|
local values ; |
|
if $(m) |
|
{ |
|
feature = $(m[1]) ; |
|
values = [ regex.split $(m[2]) "," ] ; |
|
lresult = <$(feature)>$(values) ; |
|
} |
|
else |
|
{ |
|
lresult = [ regex.split $(p) "," ] ; |
|
} |
|
|
|
if $(feature) && free in [ feature.attributes $(feature) ] |
|
{ |
|
|
|
|
|
|
|
|
|
values = $(values:J=,) ; |
|
values = $(values) $(parts[2-]) ; |
|
values = $(values:J=/) ; |
|
lresult = <$(feature)>$(values) ; |
|
parts = ; |
|
} |
|
|
|
if ! [ MATCH (.*-.*) : $(p) ] |
|
{ |
|
|
|
|
|
for local p in $(lresult) |
|
{ |
|
property.validate $(p) : $(feature-space) ; |
|
} |
|
} |
|
|
|
if ! $(result) |
|
{ |
|
result = $(lresult) ; |
|
} |
|
else |
|
{ |
|
result = $(result)/$(lresult) ; |
|
} |
|
|
|
parts = $(parts[2-]) ; |
|
} |
|
|
|
return $(result) ; |
|
} |
|
|
|
|
|
rule __test__ ( ) |
|
{ |
|
import assert ; |
|
import feature ; |
|
|
|
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 ; |
|
|
|
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 ; |
|
|
|
|
|
assert.result |
|
: build-request.expand-no-defaults ; |
|
|
|
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 |
|
<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 ; |
|
{ |
|
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 ; |
|
} |
|
|