📄 feature.jam
字号:
# eliminate features in implicit properties.
if implicit in [ attributes $(f) ]
{
p = $(v) ;
}
# locate all subproperties of $(x[1]) in the property set
local subproperties = [ select-subproperties $(fullp) : $(x) ] ;
if $(subproperties)
{
# reconstitute the joined property name
local sorted = [ sequence.insertion-sort $(subproperties) ] ;
result += $(p)-$(sorted:G="":J=-) ;
x = [ set.difference $(x[2-]) : $(subproperties) ] ;
}
else
{
# eliminate properties whose value is equal to feature's
# default and which are not symmetric and which do not
# contradict values implied by composite properties.
# since all component properties of composites in the set
# have been eliminated, any remaining property whose
# feature is the same as a component of a composite in the
# set must have a non-redundant value.
if $(fullp) != [ defaults $(f) ]
|| symmetric in [ attributes $(f) ]
|| $(fullp:G) in $(components:G)
{
result += $(p) ;
}
x = $(x[2-]) ;
}
}
return $(result) ;
}
# Combine all subproperties into their parent properties
#
# Requires: for every subproperty, there is a parent property. All
# features are explicitly expressed.
#
# This rule probably shouldn't be needed, but
# build-request.expand-no-defaults is being abused for unintended
# purposes and it needs help
rule compress-subproperties ( properties * )
{
local all-subs matched-subs result ;
for local p in $(properties)
{
if ! $(p:G)
{
assert.nonempty-variable p:G ; # expecting fully-gristed properties
}
if ! subfeature in $($(p:G).attributes)
{
local subs = [
sequence.insertion-sort
[ sequence.filter is-subproperty-of $(p) : $(properties) ]
] ;
matched-subs += $(subs) ;
local subvalues = -$(subs:G=:J=-) ;
subvalues ?= "" ;
result += $(p)$(subvalues) ;
}
else
{
all-subs += $(p) ;
}
}
assert.result true : set.equal $(all-subs) : $(matched-subs) ;
return $(result) ;
}
# given an ungristed string, finds the longest prefix which is a
# top-level feature name followed by a dash, and return a pair
# consisting of the parts before and after that dash. More
# interesting than a simple split because feature names can contain
# dashes.
local rule split-top-feature ( feature-plus )
{
local e = [ regex.split $(feature-plus) - ] ;
local f = $(e[1]) ;
local v ;
while $(e)
{
if <$(f)> in $(.all-top-features)
{
v = $(f) $(e[2-]:J=-) ;
}
e = $(e[2-]) ;
f = $(f)-$(e[1]) ;
}
return $(v) ;
}
# Given a set of properties, add default values for features not
# represented in the set.
# Note: if there's there's ordinary feature F1 and composite feature
# F2, which includes some value for F1, and both feature have default values,
# then the default value of F1 will be added, not the value in F2. This might
# not be right idea: consider
#
# feature variant : debug ... ;
# <variant>debug : .... <runtime-debugging>on
# feature <runtime-debugging> : off on ;
#
# Here, when adding default for an empty property set, we'll get
#
# <variant>debug <runtime_debugging>off
#
# and that's kind of strange.
rule add-defaults ( properties * )
{
for local v in $(properties:G=)
{
if $(v) in $(properties)
{
error add-defaults requires explicitly specified features,
but \"$(v)\" appears to be the value of an un-expanded implicit feature ;
}
}
# We don't add default for elements with ":" inside. This catches:
# 1. Conditional properties --- we don't want <variant>debug:<define>DEBUG
# to be takes as specified value for <variant>
# 2. Free properties with ":" in values. We don't care, since free properties
# don't have defaults.
local xproperties = [ MATCH "^([^:]+)$" : $(properties) ] ;
local missing-top = [ set.difference $(.all-top-features) : $(xproperties:G) ] ;
local more = [ defaults $(missing-top) ] ;
properties += $(more) ;
xproperties += $(more) ;
# Add defaults for subfeatures of features which are present
for local p in $(xproperties)
{
local s = $($(p:G).subfeatures) ;
local f = [ utility.ungrist $(p:G) ] ;
local missing-subs = [ set.difference <$(f)-$(s)> : $(properties:G) ] ;
properties += [ defaults [ select-subfeatures $(p) : $(missing-subs) ] ] ;
}
return $(properties) ;
}
# Given a property-set of the form
# v1/v2/...vN-1/<fN>vN/<fN+1>vN+1/...<fM>vM
#
# Returns
# v1 v2 ... vN-1 <fN>vN <fN+1>vN+1 ... <fM>vM
#
# Note that vN...vM may contain slashes. This is resilient to the
# substitution of backslashes for slashes, since Jam, unbidden,
# sometimes swaps slash direction on NT.
rule split ( property-set )
{
local pieces = [ regex.split $(property-set) [\\/] ] ;
local result ;
for local x in $(pieces)
{
if ( ! $(x:G) ) && $(result[-1]:G)
{
result = $(result[1--2]) $(result[-1])/$(x) ;
}
else
{
result += $(x) ;
}
}
return $(result) ;
}
# tests of module feature
local rule __test__ ( )
{
# use a fresh copy of the feature module
prepare-test feature-test-temp ;
# These are local rules and so must be explicitly reimported into
# the testing module
import feature : extend-feature validate-feature select-subfeatures ;
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 symmetric ;
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 ;
subfeature toolset gcc : platform : linux cygwin : optional ;
assert.result <toolset-gcc:version>
: select-subfeatures <toolset>gcc
: <toolset-gcc:version>
<toolset-msvc:version>
<toolset-version>
<stdlib>
;
subfeature stdlib : version : 3 4 : optional ;
assert.result <stdlib-version>
: select-subfeatures <stdlib>native
: <toolset-gcc:version>
<toolset-msvc:version>
<toolset-version>
<stdlib-version>
;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
: expand-subfeatures <toolset>gcc-3.0.1 ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1 <toolset-gcc:platform>linux
: expand-subfeatures <toolset>gcc-3.0.1-linux ;
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
: expand <toolset>gcc <toolset-gcc:version>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 ;
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>
;
feature dummy : dummy1 dummy2 ;
subfeature dummy : subdummy : x y z : optional ;
feature fu : fu1 fu2 : optional ;
subfeature fu : subfu : x y z : optional ;
subfeature fu : subfu2 : q r s ;
assert.result <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
<toolset>gcc <variant>debug <stdlib>native <dummy>dummy1 <toolset-gcc:version>2.95.2
: add-defaults <runtime-link>static <define>foobar
<optimization>on <toolset>gcc:<define>FOO
;
assert.result <runtime-link>static <define>foobar <optimization>on <toolset>gcc:<define>FOO
<fu>fu1 <toolset>gcc <variant>debug <stdlib>native <dummy>dummy1 <fu-subfu2>q
<toolset-gcc:version>2.95.2
: add-defaults <runtime-link>static <define>foobar
<optimization>on <toolset>gcc:<define>FOO <fu>fu1
;
set-default <runtime-link> : static ;
assert.result <runtime-link>static
: defaults <runtime-link>
;
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
<toolset> ;
try ;
{
implied-subfeature <toolset> not-a-version : gcc ;
}
catch \"not-a-version\" is not a known subfeature value of
<toolset>gcc ;
# leave a clean copy of the features module behind
finish-test feature-test-temp ;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -