📄 feature.jam
字号:
# Precondition checking local implicits = [ set.intersection $(p:G=) : $(p:G) ] ; if $(implicits) { errors.error minimize requires an expanded property set, but \"$(implicits[1])\" appears to be the value of an un-expanded implicit feature ; } # Remove properties implied by composite features. local components = $($(properties).components) ; local x = [ set.difference $(properties) : $(components) ] ; # Handle subfeatures and implicit features. x = [ move-subfeatures-to-the-end $(x) ] ; local result ; while $(x) { local p fullp = $(x[1]) ; local f = $(p:G) ; local v = $(p:G=) ; # 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, # 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 should not 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 ; local matched-subs ; local result ; for local p in $(properties) { if ! $(p:G) { # Expecting fully-gristed properties. assert.variable-not-empty p:G ; } 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 may 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 an ordinary feature F1 and a composite feature F2 which# includes some value for F1 and both feature have default values then the# default value of F1 will be added (as opposed to the value in F2). This might# not be the right idea, e.g. 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) { errors.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 needs to be 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.#rule __test__ ( ){ # Use a fresh copy of the feature module. prepare-test feature-test-temp ; import assert ; import errors : try catch ; # These are local rules and so must be explicitly reimported into the # testing module. import feature : extend-feature validate-feature select-subfeatures ; feature toolset : gcc : implicit ; feature define : : free ; feature runtime-link : dynamic static : symmetric ; feature optimization : on off ; feature variant : debug release profile : implicit composite symmetric ; feature stdlib : native stlport ; feature magic : : free ; compose <variant>debug : <define>_DEBUG <optimization>off ; compose <variant>release : <define>NDEBUG <optimization>on ; assert.result dynamic static : values <runtime-link> ; assert.result dynamic static : values runtime-link ; try ; { compose <variant>profile : <variant>profile ; } catch composite property <variant>profile cannot have itself as a component ; 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 ; assert.true is-subvalue toolset : gcc : version : 2.95.3 ; assert.false is-subvalue toolset : gcc : version : 1.1 ; assert.false is-subvalue toolset : msvc : version : 2.95.3 ; assert.false is-subvalue toolset : : version : yabba ; feature yabba ; subfeature yabba : version : dabba ; assert.true is-subvalue yabba : : version : dabba ; 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> ; # Make sure defaults is resilient to missing grist. 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 optional : attributes <fu> ; assert.result optional : attributes fu ; 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 + -