diff --git a/doc/src/reference.xml b/doc/src/reference.xml
index 8c45dfb05..59a03483b 100644
--- a/doc/src/reference.xml
+++ b/doc/src/reference.xml
@@ -856,6 +856,60 @@ path-constant DATA : data/a.txt ;
+ relevant
+
+
+ featuresrelevance
+ relevant
+
+
+ Allowed values: the name of any feature.
+
+
+
+ This feature is used to indicate which other features are relevant for
+ a given target. It is usually not necessary to manage it explicitly,
+ as Boost.Build can deduce it in most cases. Features which are not
+ relevant will not affect target paths, and will not cause conflicts.
+
+
+
+ A feature will be considered relevant if any of the following are true
+
+ It is referenced by toolset.flags or toolset.uses-features
+ It is used by the requirements of a generator
+ It is a subfeature of a relevant feature
+ It has a subfeature which is relevant
+ It is a composite feature, and any composed feature is relevant
+ It affects target alternative selection for a main target
+ It is a propagated feature and is relevant for any dependency
+ It is relevant for any dependency created by the same main target
+ It is used in the condition of a conditional property and the corresponding value is relevant
+ It is explicitly named as relevent
+
+
+
+ Relevant features cannot be automatically deduced in the following cases:
+
+ Indirect conditionals. Solution: return properties of the form
+ <relevant>result-feature:<relevant>condition-feature
+ This isn't really a conditional,
+ although for most purposes it functions like one. In particular, it does not support
+ multiple comma-separated elements in the condition, and it does work correctly even
+ in contexts where conditional properties are not allowed
+
+ Action rules that read properties. Solution: add toolset.uses-features
+ to tell Boost.Build that the feature is actually used.
+
+
+ Generators and targets that manipulate property-sets directly.
+ Solution: set <relevant> manually.
+
+
+
+
+
+
@@ -2539,7 +2593,8 @@ exe a : a.cpp
the directory bin unless this is overridden by the build-dir project
attribute. Under bin is a path that depends on the properties
used to build each target. This path is uniquely determined by
- all non-free, non-incidental properties. For example,
+ all relevant
+ non-free, non-incidental properties. For example,
given a property set containing:
<toolset>gcc <toolset-gcc:version>4.6.1 <variant>debug
<warnings>all <define>_DEBUG <include>/usr/local/include
diff --git a/src/build/ac.jam b/src/build/ac.jam
index 846965a03..718765649 100644
--- a/src/build/ac.jam
+++ b/src/build/ac.jam
@@ -316,5 +316,8 @@ rule check-library ( target : true-properties * : false-properties * )
{
local instance = [ class.new check-library-worker $(target) :
$(true-properties) : $(false-properties) ] ;
- return @$(instance).check ;
+ return @$(instance).check
+ [ property.evaluate-conditional-relevance
+ $(true-properties) $(false-properties)
+ : [ configure.get-relevant-features ] ] ;
}
diff --git a/src/build/configure.jam b/src/build/configure.jam
index 3f3f97034..b5d85c456 100644
--- a/src/build/configure.jam
+++ b/src/build/configure.jam
@@ -507,6 +507,11 @@ class configure-choose-worker
}
}
}
+ rule all-properties ( )
+ {
+ local i = 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ;
+ return $(self.props.$(i)) ;
+ }
rule check ( properties * )
{
local i = [ configure.find-builds $(self.message) : $(properties)
@@ -542,7 +547,10 @@ rule check-target-builds ( target message ? : true-properties * :
{
local instance = [ new check-target-builds-worker $(target) $(message) :
$(true-properties) : $(false-properties) ] ;
- return @$(instance).check ;
+ return @$(instance).check
+ [ property.evaluate-conditional-relevance
+ $(true-properties) $(false-properties)
+ : [ configure.get-relevant-features ] ] ;
}
# Usage:
@@ -556,7 +564,10 @@ rule choose ( message : * )
: $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9)
: $(10) : $(11) : $(12) : $(13) : $(14) : $(15) : $(16)
: $(17) : $(18) : $(19) ] ;
- return @$(instance).check ;
+ return @$(instance).check
+ [ property.evaluate-conditional-relevance
+ [ $(instance).all-properties ]
+ : [ configure.get-relevant-features ] ] ;
}
diff --git a/src/build/feature.jam b/src/build/feature.jam
index c4f681867..d833d70e4 100644
--- a/src/build/feature.jam
+++ b/src/build/feature.jam
@@ -662,6 +662,10 @@ rule subfeature (
local f = [ utility.ungrist $(feature) ] ;
feature $(f)-$(subfeature-name) : $(subvalues) : $(attributes) subfeature ;
+ # Features and subfeatures are always relevent as a group
+ .feature-dependencies.$(f) += $(f)-$(subfeature-name) ;
+ .feature-dependencies.$(f)-$(subfeature-name) += $(f) ;
+
# Now make sure the subfeature values are known.
extend-subfeature $(feature) $(value-string) : $(subfeature) : $(subvalues) ;
}
@@ -692,6 +696,10 @@ rule compose ( composite-property : component-properties * )
errors.error composite property "$(composite-property)" cannot have itself as a component ;
}
$(composite-property).components = $(component-properties) ;
+
+ # A composite feature is relevant if any composed feature is relevant
+ local component-features = [ sequence.transform utility.ungrist : $(component-properties:G) ] ;
+ .feature-dependencies.$(component-features) += [ utility.ungrist $(feature) ] ;
}
@@ -1161,6 +1169,41 @@ rule split ( property-set )
return $(result) ;
}
+# Returns all the features that also must be relevant when these features are relevant
+rule expand-relevant ( features * )
+{
+ local conditional ;
+ local result ;
+ for f in $(features)
+ {
+ # This looks like a conditional, even though it isn't really.
+ # (Free features can never be used in conditionals)
+ local split = [ MATCH "^(.*):(.*)$" : $(f) ] ;
+ if $(split)
+ {
+ local-dependencies.$(split[1]) += $(split[2]) ;
+ conditional += local-dependencies.$(split[1]) ;
+ }
+ else
+ {
+ result += $(f) ;
+ }
+ }
+ local queue = $(result) ;
+ while $(queue)
+ {
+ local added = [ set.difference
+ $(.feature-dependencies.$(queue))
+ $(local-dependencies.$(queue))
+ : $(result) ] ;
+ result += $(added) ;
+ queue = $(added) ;
+ }
+ # Clean up local map
+ $(conditional) = ;
+ return $(result) ;
+}
+
# Tests of module feature.
#
diff --git a/src/build/generators.jam b/src/build/generators.jam
index c26db7257..d00f5242c 100644
--- a/src/build/generators.jam
+++ b/src/build/generators.jam
@@ -167,8 +167,10 @@ class generator
import utility ;
import path ;
import property ;
+ import property-set ;
import sequence ;
import set ;
+ import toolset ;
import type ;
import virtual-target ;
@@ -236,6 +238,10 @@ class generator
# Note that 'transform' here, is the same as 'for_each'.
sequence.transform type.validate : $(self.source-types) ;
sequence.transform type.validate : $(self.target-types) ;
+
+ local relevant-for-generator =
+ [ sequence.transform utility.ungrist : $(requirements:G) ] ;
+ self.relevant-features = [ property-set.create $(relevant-for-generator) ] ;
}
################# End of constructor #################
@@ -406,10 +412,10 @@ class generator
}
local result ;
- if $(consumed)
+ if $(consumed[2])
{
- result = [ construct-result $(consumed) : $(project) $(name) :
- $(property-set) ] ;
+ result = [ construct-result $(consumed[2-]) : $(project) $(name) :
+ [ $(property-set).add $(consumed[1]) ] ] ;
}
if $(result)
@@ -421,7 +427,11 @@ class generator
generators.dout [ indent ] " FAILURE" ;
}
generators.dout ;
- return $(result) ;
+ if $(result)
+ {
+ # Make sure that we propagate usage-requirements up the stack.
+ return [ $(result[1]).add $(consumed[1]) ] $(result[2-]) ;
+ }
}
# Constructs the dependency graph to be returned by this generator.
@@ -443,6 +453,11 @@ class generator
)
{
local result ;
+
+ local relevant = [ toolset.relevant $(self.rule-name) ] ;
+ relevant = [ $(relevant).add $(self.relevant-features) ] ;
+ property-set = [ $(property-set).add $(relevant) ] ;
+
# If this is a 1->1 transformation, apply it to all consumed targets in
# order.
if ! $(self.source-types[2]) && ! $(self.composing)
@@ -458,7 +473,10 @@ class generator
result += [ generated-targets $(consumed) : $(property-set) :
$(project) $(name) ] ;
}
- return $(result) ;
+ if $(result)
+ {
+ return $(relevant) $(result) ;
+ }
}
# Determine target name from fullname (maybe including path components)
@@ -576,6 +594,7 @@ class generator
{
local _consumed ;
local missing-types ;
+ local usage-requirements ;
if $(sources[2])
{
@@ -588,6 +607,7 @@ class generator
local temp = [ consume-directly $(sources) ] ;
if $(temp[1])
{
+ usage-requirements = [ property-set.empty ] ;
_consumed = $(temp[1]) ;
}
missing-types = $(temp[2-]) ;
@@ -613,7 +633,7 @@ class generator
# everything to the required type. There is no need to rerun it on
# targets of different types.
- # NOTE: ignoring usage requirements.
+ usage-requirements = $(transformed[1]) ;
for local t in $(transformed[2-])
{
if [ $(t).type ] in $(missing-types)
@@ -623,7 +643,7 @@ class generator
}
}
- return [ sequence.unique $(_consumed) ] ;
+ return $(usage-requirements) [ sequence.unique $(_consumed) ] ;
}
# Converts several files to consumable types. Called for composing
@@ -638,10 +658,11 @@ class generator
if ! $(self.source-types)
{
# Anything is acceptible
- return $(sources) ;
+ return [ property-set.empty ] $(sources) ;
}
else
{
+ local usage-requirements = [ property-set.empty ] ;
local acceptible-types = [ sequence.unique
[ sequence.transform type.all-derived : $(self.source-types) ] ] ;
for local source in $(sources)
@@ -661,13 +682,17 @@ class generator
{
generators.dout [ indent ] " failed to convert " $(source) ;
}
+ else
+ {
+ usage-requirements = [ $(usage-requirements).add $(transformed[1]) ] ;
+ }
}
else
{
result += $(source) ;
}
}
- return [ sequence.unique $(result) : stable ] ;
+ return $(usage-requirements) [ sequence.unique $(result) : stable ] ;
}
}
diff --git a/src/build/property-set.jam b/src/build/property-set.jam
index feb4fb42e..194b3e0bc 100644
--- a/src/build/property-set.jam
+++ b/src/build/property-set.jam
@@ -34,6 +34,7 @@ class property-set
{
import errors ;
import feature ;
+ import modules ;
import path ;
import property ;
import property-set ;
@@ -86,6 +87,26 @@ class property-set
return $(self.free) ;
}
+ # Returns relevant base properties
+ rule base-relevant ( )
+ {
+ if ! $(self.relevant-initialized)
+ {
+ init-relevant ;
+ }
+ return $(self.base-relevant) ;
+ }
+
+ # Returns all relevant properties
+ rule relevant
+ {
+ if ! $(self.relevant-initialized)
+ {
+ init-relevant ;
+ }
+ return $(self.relevant) ;
+ }
+
# Returns dependency properties.
#
rule dependency ( )
@@ -215,7 +236,7 @@ class property-set
{
if ! $(self.as-path)
{
- self.as-path = [ property.as-path [ base ] ] ;
+ self.as-path = [ property.as-path [ base-relevant ] ] ;
}
return $(self.as-path) ;
}
@@ -345,6 +366,30 @@ class property-set
self.base-initialized = true ;
}
+ rule init-relevant ( )
+ {
+ local relevant-features = [ get ] ;
+ relevant-features = [ feature.expand-relevant $(relevant-features) ] ;
+ relevant-features = <$(relevant-features)> ;
+ ignore-relevance = [ modules.peek property-set : .ignore-relevance ] ;
+ for local p in $(self.raw)
+ {
+ if $(ignore-relevance) || $(p:G) in $(relevant-features)
+ {
+ local att = [ feature.attributes $(p:G) ] ;
+ if ! ( incidental in $(att) )
+ {
+ self.relevant += $(p) ;
+ if ! ( free in $(att) )
+ {
+ self.base-relevant += $(p) ;
+ }
+ }
+ }
+ }
+ self.relevant-initialized = true ;
+ }
+
rule init-dependency ( )
{
for local p in $(self.raw)
@@ -369,7 +414,7 @@ class property-set
# characters as well, e.g. free or indirect properties. Indirect
# properties for example contain a full Jamfile path in their value
# which on Windows file systems contains ':' as the drive separator.
- if [ MATCH (:) : $(p:G=) ] || $(p:G) =
+ if ( [ MATCH (:) : $(p:G=) ] && ! ( free in [ feature.attributes $(p:G) ] ) ) || $(p:G) =
{
self.conditional += $(p) ;
}
@@ -382,6 +427,13 @@ class property-set
}
}
+# This is a temporary measure to help users work around
+# any problems. Remove it once we've verified that
+# everything works.
+if --ignore-relevance in [ modules.peek : ARGV ]
+{
+ .ignore-relevance = true ;
+}
# Creates a new 'property-set' instance for the given raw properties or returns
# an already existing ones.
diff --git a/src/build/property.jam b/src/build/property.jam
index 4be08eeb7..c172bd253 100644
--- a/src/build/property.jam
+++ b/src/build/property.jam
@@ -70,7 +70,7 @@ rule evaluate-conditionals-in-context ( properties * : context * )
local indirect ;
for local p in $(properties)
{
- if [ MATCH (:<) : $(p) ]
+ if [ MATCH (:<) : $(p) ] && ! free in [ feature.attributes $(p:G) ]
{
conditionals += $(p) ;
}
@@ -155,6 +155,36 @@ rule evaluate-conditionals-in-context ( properties * : context * )
}
+# Returns properties indicating how the conditionals in
+# properties affect feature relevance. If the optional argument cond
+# is passed, it is treated as extra conditions for all properties.
+#
+rule evaluate-conditional-relevance ( properties * : cond * )
+{
+ cond = [ sequence.transform utility.ungrist : $(cond:G) ] ;
+ local result ;
+ for local p in $(properties)
+ {
+ # Separate condition and property.
+ local s = [ MATCH ^(.*):(<.*) : $(p) ] ;
+ if ! $(s) || free in [ feature.attributes $(p:G) ]
+ {
+ local value = [ utility.ungrist $(p:G) ] ;
+ result += $(value):$(cond) ;
+ }
+ else
+ {
+ local condition = [ regex.split $(s[1]) "," ] ;
+ condition = [ MATCH ^!?(.*) : $(condition) ] ;
+ condition = [ sequence.transform utility.ungrist : $(condition:G) ] $(cond) ;
+ local value = [ utility.ungrist $(s[2]:G) ] ;
+ result += $(value):$(condition) ;
+ }
+ }
+ return [ sequence.unique $(result) ] ;
+}
+
+
rule expand-subfeatures-in-conditions ( properties * )
{
local result ;
diff --git a/src/build/targets.jam b/src/build/targets.jam
index 0964b0d86..6ffc082a4 100644
--- a/src/build/targets.jam
+++ b/src/build/targets.jam
@@ -191,6 +191,7 @@ class project-target : abstract-target
import property-set ;
import set ;
import sequence ;
+ import toolset ;
import "class" : new ;
rule __init__ ( name : project-module parent-project ?
@@ -584,6 +585,8 @@ class project-target : abstract-target
IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules)
;
EXPORT $(this-module) : $(user-rules) ;
+
+ toolset.inherit-flags $(this-module) : $(parent-module) ;
}
}
@@ -621,10 +624,11 @@ class main-target : abstract-target
{
import assert ;
import feature ;
- import print ;
import property-set ;
import sequence ;
+ import set ;
import targets : start-building end-building ;
+ import utility ;
rule __init__ ( name : project )
{
@@ -719,6 +723,43 @@ class main-target : abstract-target
}
}
+ # Features are relevant here if they could affect alternative
+ # selection. That is, base, non-conditional properties that
+ # are not identical in all target alternatives.
+ rule relevant-features ( )
+ {
+ if $(self.alternatives[2-])
+ {
+ if $(self.relevant-features)
+ {
+ return $(self.relevant-features) ;
+ }
+ local all-properties ;
+ for t in $(self.alternatives)
+ {
+ local ps = [ $(t).requirements ] ;
+ ps = [ property-set.create [ $(ps).non-conditional ] ] ;
+ all-properties += [ $(ps).base ] ;
+ }
+ all-properties = [ sequence.unique $(all-properties) ] ;
+ local result ;
+ for t in $(self.alternatives)
+ {
+ local ps = [ $(t).requirements ] ;
+ ps = [ property-set.create [ $(ps).non-conditional ] ] ;
+ local properties = [ set.difference $(all-properties) : [ $(ps).base ] ] ;
+ result += $(properties:G) ;
+ }
+ result = [ sequence.transform utility.ungrist : [ sequence.unique $(result) ] ] ;
+ self.relevant-features = [ property-set.create $(result) ] ;
+ return $(self.relevant-features) ;
+ }
+ else
+ {
+ return [ property-set.empty ] ;
+ }
+ }
+
rule apply-default-build ( property-set )
{
return [ targets.apply-default-build $(property-set) :
@@ -735,11 +776,12 @@ class main-target : abstract-target
start-building $(__name__) ;
local all-property-sets = [ apply-default-build $(property-set) ] ;
+ local relevant = [ relevant-features ] ;
local usage-requirements = [ property-set.empty ] ;
local result ;
for local p in $(all-property-sets)
{
- local r = [ generate-really $(p) ] ;
+ local r = [ generate-really [ $(p).add $(relevant) ] ] ;
if $(r)
{
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
@@ -1317,6 +1359,15 @@ class basic-target : abstract-target
local gur = $(result[1]) ;
result = $(result[2-]) ;
+ # Relevant is automatically applied to usage requirements
+ # and only applies for propagated features
+ local relevant = [ propagated-relevant
+ [ $(gur).get ]
+ [ $(rproperties).get ] ] ;
+ gur = [ property-set.create
+ [ property.change [ $(gur).raw ] : ]
+ $(relevant) ] ;
+
if $(self.always)
{
for local t in $(result)
@@ -1409,6 +1460,22 @@ class basic-target : abstract-target
[ $(self.usage-requirements).evaluate-conditionals
$(rproperties) ] ;
+ # Filter out non-propagated properties
+ local relevant ;
+ for local r in [ $(xusage-requirements).get ]
+ {
+ local check = [ MATCH "(.*):(.*)" : $(r) ] ;
+ if $(check) { check = $(check[2]) ; }
+ else { check = $(r) ; }
+ if propagated in [ feature.attributes <$(check)> ]
+ {
+ relevant += $(r) ;
+ }
+ }
+ xusage-requirements = [ property-set.create
+ [ property.change [ $(xusage-requirements).raw ] : ]
+ $(relevant) ] ;
+
# We generate all dependency properties and add them, as well as their
# usage requirements, to the result.
local extra ;
@@ -1448,6 +1515,19 @@ class basic-target : abstract-target
return [ $(result).add [ property-set.create $(raw) ] ] ;
}
+ local rule propagated-relevant ( values * )
+ {
+ local result ;
+ for local v in [ feature.expand-relevant $(values) ]
+ {
+ if propagated in [ feature.attributes <$(v)> ]
+ {
+ result += $(v) ;
+ }
+ }
+ return $(result) ;
+ }
+
# Creates new subvariant instances for 'targets'.
# 'root-targets' - virtual targets to be returned to dependants
# 'all-targets' - virtual targets created while building this main target
@@ -1594,7 +1674,8 @@ rule main-target-requirements (
import errors ;
errors.error "Conflicting requirements for target:" $(requirements) ;
}
- return [ $(requirements).add [ toolset.requirements ] ] ;
+ local result = [ $(requirements).add [ toolset.requirements ] ] ;
+ return [ $(result).add-raw [ property.evaluate-conditional-relevance [ $(result).raw ] ] ] ;
}
@@ -1617,7 +1698,10 @@ rule main-target-usage-requirements (
$(specification)
: [ $(project).project-module ] [ $(project).get location ] ] ;
- return [ $(project-usage-requirements).add $(usage-requirements) ] ;
+ local result = [ $(project-usage-requirements).add $(usage-requirements) ] ;
+ local relevant =
+ [ property.evaluate-conditional-relevance [ $(result).raw ] ] ;
+ return [ $(result).add-raw $(relevant) ] ;
}
diff --git a/src/build/toolset.jam b/src/build/toolset.jam
index a942cd906..d5b326488 100644
--- a/src/build/toolset.jam
+++ b/src/build/toolset.jam
@@ -19,6 +19,7 @@ import set ;
import property-set ;
import order ;
import "class" : new ;
+import utility ;
.flag-no = 1 ;
@@ -76,6 +77,36 @@ rule pop-checking-for-flags-module ( )
}
+# Specifies features that are referenced by the action rule.
+# This is necessary in order to detect that these features
+# are relevant.
+#
+rule uses-features ( rule-or-module : features * : unchecked ? )
+{
+ local caller = [ CALLER_MODULE ] ;
+ if ! [ MATCH ".*([.]).*" : $(rule-or-module) ]
+ && [ MATCH "(Jamfile<.*)" : $(caller) ]
+ {
+ # Unqualified rule name, used inside Jamfile. Most likely used with
+ # 'make' or 'notfile' rules. This prevents setting flags on the entire
+ # Jamfile module (this will be considered as rule), but who cares?
+ # Probably, 'flags' rule should be split into 'flags' and
+ # 'flags-on-module'.
+ rule-or-module = $(caller).$(rule-or-module) ;
+ }
+ else
+ {
+ local module_ = [ MATCH "([^.]*).*" : $(rule-or-module) ] ;
+ if $(unchecked) != unchecked
+ && $(.flags-module-checking[1]) != unchecked
+ && $(module_) != $(caller)
+ {
+ errors.error "Module $(caller) attempted to set flags for module $(module_)" ;
+ }
+ }
+ .uses-features.$(rule-or-module) += $(features) ;
+}
+
# Specifies the flags (variables) that must be set on targets under certain
# conditions, described by arguments.
#
@@ -399,6 +430,34 @@ rule relevant-features ( rule-or-module )
}
}
+# Returns a list of all the features which were
+# passed to uses-features.
+local rule used-features ( rule-or-module )
+{
+ if ! $(.used-features.$(rule-or-module))
+ {
+ local result = $(.uses-features.$(rule-or-module)) ;
+
+ # Strip away last dot separated part and recurse.
+ local next = [ MATCH ^(.+)\\.([^\\.])* : $(rule-or-module) ] ;
+ if $(next)
+ {
+ result += [ used-features $(next[1]) ] ;
+ }
+ result = [ sequence.unique $(result) ] ;
+ if $(result[1]) = ""
+ {
+ result = $(result) ;
+ }
+ .used-features.$(rule-or-module) = $(result) ;
+ return $(result) ;
+ }
+ else
+ {
+ return $(.used-features.$(rule-or-module)) ;
+ }
+}
+
rule filter-property-set ( rule-or-module : property-set )
{
local key = .filtered.property-set.$(rule-or-module).$(property-set) ;
@@ -454,6 +513,23 @@ rule set-target-variables ( rule-or-module targets + : property-set )
}
+# Returns a property-set indicating which features are relevant
+# for the given rule.
+#
+rule relevant ( rule-name )
+{
+ if ! $(.relevant-features-ps.$(rule-name))
+ {
+ local features = [ sequence.transform utility.ungrist :
+ [ relevant-features $(rule-name) ]
+ [ used-features $(rule-name) ] ] ;
+ .relevant-features-ps.$(rule-name) =
+ [ property-set.create $(features) ] ;
+ }
+ return $(.relevant-features-ps.$(rule-name)) ;
+}
+
+
# Make toolset 'toolset', defined in a module of the same name, inherit from
# 'base'.
# 1. The 'init' rule from 'base' is imported into 'toolset' with full name.
diff --git a/src/build/virtual-target.jam b/src/build/virtual-target.jam
index 2d139bd7f..cb8128362 100644
--- a/src/build/virtual-target.jam
+++ b/src/build/virtual-target.jam
@@ -999,10 +999,8 @@ rule register ( target )
{
local ps1 = [ $(a1).properties ] ;
local ps2 = [ $(a2).properties ] ;
- local p1 = [ $(ps1).base ] [ $(ps1).free ] [ set.difference
- [ $(ps1).dependency ] : [ $(ps1).incidental ] ] ;
- local p2 = [ $(ps2).base ] [ $(ps2).free ] [ set.difference
- [ $(ps2).dependency ] : [ $(ps2).incidental ] ] ;
+ local p1 = [ $(ps1).relevant ] ;
+ local p2 = [ $(ps2).relevant ] ;
if $(p1) = $(p2)
{
result = $(t) ;
diff --git a/src/tools/bison.jam b/src/tools/bison.jam
index 0689d4bd8..96b86a327 100644
--- a/src/tools/bison.jam
+++ b/src/tools/bison.jam
@@ -4,8 +4,8 @@
import generators ;
import feature ;
+import toolset : flags ;
import type ;
-import property ;
feature.feature bison.prefix : : free ;
type.register Y : y ;
@@ -17,16 +17,10 @@ rule init ( )
{
}
-rule bison ( dst dst_header : src : properties * )
-{
- local r = [ property.select bison.prefix : $(properties) ] ;
- if $(r)
- {
- PREFIX_OPT on $(<) = -p $(r:G=) ;
- }
-}
+flags bison.bison PREFIX ;
+_ = " " ;
actions bison
{
- bison $(PREFIX_OPT) -d -o $(<[1]) $(>)
+ bison -p$(_)$(PREFIX) -d -o $(<[1]) $(>)
}
diff --git a/src/tools/doxygen.jam b/src/tools/doxygen.jam
index 0594e5363..19de6d0ec 100644
--- a/src/tools/doxygen.jam
+++ b/src/tools/doxygen.jam
@@ -274,6 +274,7 @@ rule translate-path ( path )
}
}
+toolset.uses-features doxygen.headers-to-doxyfile : "" ;
# Generates a doxygen configuration file (doxyfile) given a set of C++ sources
# and a property list that may contain features.
@@ -321,6 +322,7 @@ rule headers-to-doxyfile ( target : sources * : properties * )
print.text $(text) : true ;
}
+toolset.uses-features doxygen.run : "" ;
# Run Doxygen. See doxygen-action for a description of the strange properties of
# this rule.
@@ -406,6 +408,7 @@ rule collect ( target : source : properties * )
: doxygen.xml.path=$(native-path) ;
}
+toolset.uses-features doxygen.xml-to-boostbook : ;
# Translate Doxygen XML into BoostBook.
#
diff --git a/src/tools/features/relevant-feature.jam b/src/tools/features/relevant-feature.jam
new file mode 100644
index 000000000..f55bd7f4c
--- /dev/null
+++ b/src/tools/features/relevant-feature.jam
@@ -0,0 +1,10 @@
+# Copyright 2017 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+# Identifies relevant features.
+
+import feature ;
+
+feature.feature relevant : : incidental free ;
diff --git a/src/tools/features/threadapi-feature.jam b/src/tools/features/threadapi-feature.jam
index 1a2b0923d..0f9d42fa5 100644
--- a/src/tools/features/threadapi-feature.jam
+++ b/src/tools/features/threadapi-feature.jam
@@ -25,5 +25,5 @@ rule detect ( properties * )
local ps = [ property-set.create $(properties) ] ;
local api = [ $(ps).get ] ;
if ! $(api) { api = [ get-default $(ps) ] ; }
- return $(api) ;
+ return $(api) threadapi:target-os ;
}
diff --git a/src/tools/gcc.jam b/src/tools/gcc.jam
index 6ba56967e..e9e40aa5a 100644
--- a/src/tools/gcc.jam
+++ b/src/tools/gcc.jam
@@ -550,8 +550,8 @@ class gcc-pch-generator : pch-generator
# Return result of base class and pch-file property as
# usage-requirements.
return
- [ property-set.create $(pch-file) -Winvalid-pch ]
- $(pch-file)
+ [ $(pch-file[1]).add-raw $(pch-file[2-]) -Winvalid-pch ]
+ $(pch-file[2-])
;
}
diff --git a/src/tools/generators/archive-generator.jam b/src/tools/generators/archive-generator.jam
index 88ef16559..57a46bf92 100644
--- a/src/tools/generators/archive-generator.jam
+++ b/src/tools/generators/archive-generator.jam
@@ -11,6 +11,7 @@ import generators ;
#
class archive-generator : generator
{
+ import generators ;
import property-set ;
rule __init__ ( id composing ? : source-types + : target-types +
@@ -56,9 +57,7 @@ class archive-generator : generator
}
}
- usage-requirements = [ property-set.create $(usage-requirements) ] ;
-
- return $(usage-requirements) $(result) ;
+ return [ generators.add-usage-requirements $(result) : $(usage-requirements) ] ;
}
}
diff --git a/src/tools/generators/lib-generator.jam b/src/tools/generators/lib-generator.jam
index f520b6102..e4ba23e2c 100644
--- a/src/tools/generators/lib-generator.jam
+++ b/src/tools/generators/lib-generator.jam
@@ -54,8 +54,9 @@ class lib-generator : generator
}
property-set = [ $(property-set).add-raw LIB ] ;
# Construct the target.
- return [ generators.construct $(project) $(name) : $(actual-type)
+ local result = [ generators.construct $(project) $(name) : $(actual-type)
: $(property-set) : $(sources) ] ;
+ return [ $(result[1]).add-raw link ] $(result[2-]) ;
}
}
diff --git a/src/tools/generators/linking-generator.jam b/src/tools/generators/linking-generator.jam
index 0c9d38f3e..2d905faf6 100644
--- a/src/tools/generators/linking-generator.jam
+++ b/src/tools/generators/linking-generator.jam
@@ -83,11 +83,12 @@ class linking-generator : generator
local ur ;
if $(result)
{
- ur = [ extra-usage-requirements $(result) : $(property-set) ] ;
+ ur = [ extra-usage-requirements $(result[2-]) : $(property-set) ] ;
ur = [ $(ur).add
[ property-set.create $(extra-xdll-paths) ] ] ;
+ ur = [ $(ur).add $(result[1]) ] ;
}
- return $(ur) $(result) ;
+ return $(ur) $(result[2-]) ;
}
rule extra-usage-requirements ( created-targets * : property-set )
diff --git a/src/tools/generators/searched-lib-generator.jam b/src/tools/generators/searched-lib-generator.jam
index 174d137e3..dc451970d 100644
--- a/src/tools/generators/searched-lib-generator.jam
+++ b/src/tools/generators/searched-lib-generator.jam
@@ -38,7 +38,7 @@ class searched-lib-generator : generator
local search = [ feature.get-values : $(properties) ] ;
- local a = [ new null-action $(property-set) ] ;
+ local a = [ new null-action [ $(property-set).add-raw link ] ] ;
local lib-name = [ feature.get-values : $(properties) ] ;
lib-name ?= $(name) ;
local t = [ new searched-lib-target $(lib-name) : $(project)
@@ -47,7 +47,7 @@ class searched-lib-generator : generator
# lib png : z : png ;
# the 'z' target should be returned, so that apps linking to 'png'
# will link to 'z', too.
- return [ property-set.create $(search) ]
+ return [ property-set.create $(search) link ]
[ virtual-target.register $(t) ] $(sources) ;
}
}
diff --git a/src/tools/lex.jam b/src/tools/lex.jam
index 75d641318..e85d1d1ad 100644
--- a/src/tools/lex.jam
+++ b/src/tools/lex.jam
@@ -5,8 +5,7 @@
import type ;
import generators ;
import feature ;
-import property ;
-
+import toolset : flags ;
feature.feature flex.prefix : : free ;
type.register LEX : l ;
@@ -18,14 +17,7 @@ rule init ( )
{
}
-rule lex ( target : source : properties * )
-{
- local r = [ property.select flex.prefix : $(properties) ] ;
- if $(r)
- {
- PREFIX on $(<) = $(r:G=) ;
- }
-}
+flags lex.lex PREFIX ;
actions lex
{
diff --git a/src/tools/make.jam b/src/tools/make.jam
index 40b59faf3..7c9a7ca68 100644
--- a/src/tools/make.jam
+++ b/src/tools/make.jam
@@ -17,6 +17,8 @@ import targets ;
class make-target-class : basic-target
{
import "class" : new ;
+ import indirect ;
+ import toolset ;
import type ;
import virtual-target ;
@@ -34,10 +36,11 @@ class make-target-class : basic-target
# below.
local m = [ MATCH ^@(.*) : $(action-name) ] ;
- local a = [ new action $(source-targets) : $(m[1]) : $(property-set) ] ;
+ local relevant = [ toolset.relevant [ indirect.get-rule $(m[1]) ] ] ;
+ local a = [ new action $(source-targets) : $(m[1]) : [ $(property-set).add $(relevant) ] ] ;
local t = [ new file-target $(self.name) exact : [ type.type
$(self.name) ] : $(self.project) : $(a) ] ;
- return [ property-set.empty ] [ virtual-target.register $(t) ] ;
+ return $(relevant) [ virtual-target.register $(t) ] ;
}
}
diff --git a/src/tools/mpi.jam b/src/tools/mpi.jam
index 1ccc54133..a4d29340e 100644
--- a/src/tools/mpi.jam
+++ b/src/tools/mpi.jam
@@ -595,6 +595,10 @@ feature mpi:processes : : free incidental ;
# apply to mpi.capture output at the moment.
# Redo this explicitly.
toolset.flags mpi.capture-output ARGS ;
+toolset.uses-features mpi.capture-output :
+
+ ;
+
rule capture-output ( target : sources * : properties * )
{
# Use the standard capture-output rule to run the tests
diff --git a/src/tools/msvc.jam b/src/tools/msvc.jam
index f096e64f4..9365a7e12 100644
--- a/src/tools/msvc.jam
+++ b/src/tools/msvc.jam
@@ -527,6 +527,7 @@ actions compile.rc
$(.SETUP) $(.RC) -l 0x409 -U$(UNDEFS) -D$(DEFINES) -I"$(INCLUDES:W)" -fo "$(<:W)" "$(>:W)"
}
+toolset.uses-features msvc.link : ;
rule link ( targets + : sources * : properties * )
{
@@ -706,7 +707,7 @@ class msvc-pch-generator : pch-generator
: $(pch-header) ] ;
local pch-file ;
- for local g in $(generated)
+ for local g in $(generated[2-])
{
if [ type.is-derived [ $(g).type ] PCH ]
{
@@ -714,8 +715,8 @@ class msvc-pch-generator : pch-generator
}
}
- return [ property-set.create $(pch-header)
- $(pch-file) ] $(generated) ;
+ return [ $(generated[1]).add-raw $(pch-header)
+ $(pch-file) ] $(generated[2-]) ;
}
}
@@ -878,7 +879,7 @@ local rule set-setup-command ( targets * : properties * )
if ! $($(key))
{
properties = [ feature.expand $(properties) ] ;
- properties = [ property.select : $(properties) ] ;
+ properties = [ property.select : $(properties) ] ;
local ps = [ property-set.create $(properties) $(setup-options) ] ;
local original = [ virtual-target.from-file $(setup-script) : [ path.pwd ] : $(.project) ] ;
local action = [ new non-scanning-action $(original) : msvc.adjust-setup-command : $(ps) ] ;
@@ -1422,8 +1423,8 @@ class msvc-linking-generator : linking-generator
if $(result)
{
- local name-main = [ $(result[0]).name ] ;
- local action = [ $(result[0]).action ] ;
+ local name-main = [ $(result[1]).name ] ;
+ local action = [ $(result[1]).action ] ;
if [ $(property-set).get ] = "on"
{
diff --git a/src/tools/python.jam b/src/tools/python.jam
index c9f6f4c25..0459f8575 100644
--- a/src/tools/python.jam
+++ b/src/tools/python.jam
@@ -1243,6 +1243,10 @@ local rule pyd-pythonpath ( source )
toolset.flags python.capture-output ARGS ;
toolset.flags python.capture-output INPUT_FILES ;
+toolset.uses-features python.capture-output :
+
+ ;
+
rule capture-output ( target : sources * : properties * )
{
# Setup up a proper DLL search path. Here, $(sources[1]) is a python module
diff --git a/src/tools/stlport.jam b/src/tools/stlport.jam
index ed0947ca5..4a08c8c9b 100644
--- a/src/tools/stlport.jam
+++ b/src/tools/stlport.jam
@@ -89,6 +89,9 @@ class stlport-target-class : basic-target
local requirements ;
requirements += $(self.version) ;
+ requirements += runtime-debugging ;
+ requirements += toolset ;
+ requirements += runtime-link ;
self.requirements = [ property-set.create $(requirements) ] ;
}
diff --git a/src/tools/testing.jam b/src/tools/testing.jam
index c7383cd03..a36258ed3 100644
--- a/src/tools/testing.jam
+++ b/src/tools/testing.jam
@@ -331,6 +331,8 @@ generators.register-standard testing.capture-output : EXE : RUN_OUTPUT ;
# http://article.gmane.org/gmane.comp.lib.boost.build/6353).
generators.register-standard testing.unit-test : EXE : UNIT_TEST ;
+toolset.uses-features testing.expect-success : ;
+toolset.uses-features testing.expect-failure : ;
# The action rules called by generators.
@@ -456,6 +458,9 @@ toolset.flags testing.capture-output ARGS ;
toolset.flags testing.capture-output INPUT_FILES ;
toolset.flags testing.capture-output LAUNCHER ;
+toolset.uses-features testing.capture-output :
+ ;
+
if --remove-test-targets in [ modules.peek : ARGV ]
{
feature.set-default preserve-test-targets : off ;
diff --git a/src/tools/xsltproc.jam b/src/tools/xsltproc.jam
index b08089b92..f6bf1af98 100644
--- a/src/tools/xsltproc.jam
+++ b/src/tools/xsltproc.jam
@@ -151,6 +151,7 @@ IMPORT xsltproc : register-generator : : generators.register-xslt ;
rule flags ( rulename )
{
+ toolset.uses-features $(rulename) : : unchecked ;
toolset.flags $(rulename) XSL-PATH : : unchecked ;
toolset.flags $(rulename) FLAGS : : unchecked ;
}
diff --git a/test/MockToolset.py b/test/MockToolset.py
index aa280b83a..bc02bf8f5 100755
--- a/test/MockToolset.py
+++ b/test/MockToolset.py
@@ -214,8 +214,9 @@ generators.register-linker mock.link : LIB OBJ : EXE : mock ;
generators.register-linker mock.link.dll : LIB OBJ : SHARED_LIB : mock ;
generators.register-archiver mock.archive : OBJ : STATIC_LIB : mock ;
-toolset.flags mock.compile INCLUDES ;
-toolset.flags mock.compile DEFINES ;
+toolset.flags mock.compile OPTIONS shared : -fPIC ;
+toolset.flags mock.compile INCLUDES : ;
+toolset.flags mock.compile DEFINES : ;
actions compile.c
{
diff --git a/test/TestToolset.py b/test/TestToolset.py
index 98bc7c82b..8915e78cc 100644
--- a/test/TestToolset.py
+++ b/test/TestToolset.py
@@ -60,7 +60,7 @@ def expand_properties(properties):
result += ["target-os=" + default_target_os]
return result
-def compute_path(properties):
+def compute_path(properties, target_type):
path = ""
if "variant=release" in properties:
path += "/release"
@@ -74,9 +74,9 @@ def compute_path(properties):
path += "/cxxstd-latest-iso"
if "link=static" in properties:
path += "/link-static"
- if "runtime-link=static" in properties:
+ if "runtime-link=static" in properties and target_type in ["exe"]:
path += "/runtime-link-static"
- if "strip=on" in properties:
+ if "strip=on" in properties and target_type in ["dll", "exe", "obj2"]:
path += "/strip-on"
if get_target_os(properties) != default_target_os:
path += "/target-os-" + get_target_os(properties)
@@ -96,16 +96,17 @@ def test_toolset(toolset, version, property_sets):
for properties in property_sets:
t.set_toolset(toolset + "-" + version, get_target_os(properties))
properties = adjust_properties(properties)
- path = toolset.split("-")[0] + "-*" + version + compute_path(properties)
+ def path(t):
+ return toolset.split("-")[0] + "-*" + version + compute_path(properties, t)
os.environ["B2_PROPERTIES"] = " ".join(expand_properties(properties))
t.run_build_system(["--user-config="] + properties)
- t.expect_addition("bin/%s/lib.obj" % (path))
+ t.expect_addition("bin/%s/lib.obj" % (path("obj")))
if "link=static" not in properties:
- t.expect_addition("bin/%s/l1.dll" % (path))
+ t.expect_addition("bin/%s/l1.dll" % (path("dll")))
else:
- t.expect_addition("bin/%s/l1.lib" % (path))
- t.expect_addition("bin/%s/main.obj" % (path))
- t.expect_addition("bin/%s/test.exe" % (path))
+ t.expect_addition("bin/%s/l1.lib" % (path("lib")))
+ t.expect_addition("bin/%s/main.obj" % (path("obj2")))
+ t.expect_addition("bin/%s/test.exe" % (path("exe")))
t.expect_nothing_more()
t.rm("bin")
diff --git a/test/command_line_properties.py b/test/command_line_properties.py
index a69bf1282..ebb186ea4 100644
--- a/test/command_line_properties.py
+++ b/test/command_line_properties.py
@@ -63,8 +63,8 @@ def test_free():
actions run { echo $(OPTIONS) > $(<) }
''')
t.run_build_system(['f1=x,/:-'])
- t.expect_content("bin/*/output1.txt", "x,/:-")
- t.expect_content("bin/*/output2.txt", "x,/:-")
+ t.expect_content("bin*/output1.txt", "x,/:-")
+ t.expect_content("bin*/output2.txt", "x,/:-")
t.cleanup()
def test_subfeature():
diff --git a/test/custom_generator.py b/test/custom_generator.py
index f98a46878..00860f643 100644
--- a/test/custom_generator.py
+++ b/test/custom_generator.py
@@ -61,6 +61,6 @@ t.write("r.rcc", """
""")
t.run_build_system()
-t.expect_content("bin/$toolset/debug*/r.obj", "rc-object")
+t.expect_content("bin/r.obj", "rc-object")
t.cleanup()
diff --git a/test/example_make.py b/test/example_make.py
index e65158ec2..d72423cb2 100644
--- a/test/example_make.py
+++ b/test/example_make.py
@@ -13,5 +13,5 @@ import sys
t = BoostBuild.Tester(['example.python.interpreter=%s' % sys.executable])
t.set_tree("../example/make")
t.run_build_system()
-t.expect_addition(["bin/$toolset/debug*/main.cpp"])
+t.expect_addition(["bin/main.cpp"])
t.cleanup()
diff --git a/test/feature_relevant.py b/test/feature_relevant.py
new file mode 100644
index 000000000..4e7a0c451
--- /dev/null
+++ b/test/feature_relevant.py
@@ -0,0 +1,142 @@
+#!/usr/bin/python
+
+# Copyright 2018 Steven Watanabe
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or copy at
+# http://www.boost.org/LICENSE_1_0.txt)
+
+# Tests the feature
+
+import BoostBuild
+
+t = BoostBuild.Tester(use_test_config=False)
+
+t.write("xxx.jam", """
+import type ;
+import feature : feature ;
+import toolset : flags ;
+import generators ;
+type.register XXX : xxx ;
+type.register YYY : yyy ;
+feature xxxflags : : free ;
+generators.register-standard xxx.run : YYY : XXX ;
+# xxxflags is relevant because it is used by flags
+flags xxx.run OPTIONS : ;
+actions run
+{
+ echo okay > $(<)
+}
+""")
+
+t.write("zzz.jam", """
+import xxx ;
+import type ;
+import feature : feature ;
+import generators ;
+type.register ZZZ : zzz ;
+feature zzz.enabled : off on : propagated ;
+# zzz.enabled is relevant because it is used in the generator's
+# requirements
+generators.register-standard zzz.run : XXX : ZZZ : on ;
+actions run
+{
+ echo okay > $(<)
+}
+""")
+
+t.write("aaa.jam", """
+import zzz ;
+import type ;
+import feature : feature ;
+import generators ;
+import toolset : flags ;
+type.register AAA : aaa ;
+feature aaaflags : : free ;
+generators.register-standard aaa.run : ZZZ : AAA ;
+flags aaa.run OPTIONS : ;
+actions run
+{
+ echo okay > $(<)
+}
+""")
+
+t.write("Jamroot.jam", """
+import xxx ;
+import zzz ;
+import aaa ;
+import feature : feature ;
+
+# f1 is relevant, because it is composite and is relevant
+feature f1 : n y : composite propagated ;
+feature.compose y : -no1 ;
+# f2 is relevant, because it is used in a conditional
+feature f2 : n y : propagated ;
+# f3 is relevant, because it is used to choose the target alternative
+feature f3 : n y : propagated ;
+# f4 is relevant, because it is marked as such explicitly
+feature f4 : n y : propagated ;
+# f5 is relevant because of the conditional usage-requirements
+feature f5 : n y : propagated ;
+# f6 is relevant because the indirect conditional indicates so
+feature f6 : n y : propagated ;
+# f7 is relevant because the icond7 says so
+feature f7 : n y : propagated ;
+
+# The same as f[n], except not propagated
+feature g1 : n y : composite ;
+feature.compose y : -no1 ;
+feature g2 : n y ;
+feature g3 : n y ;
+feature g4 : n y ;
+feature g5 : n y ;
+feature g6 : n y ;
+feature g7 : n y ;
+
+project : default-build
+ y y y y y y y
+ y y y y y y y on ;
+
+rule icond6 ( properties * )
+{
+ local result ;
+ if y in $(properties) || y in $(properties)
+ {
+ result += -yes6 ;
+ }
+ return $(result)
+ xxxflags:f6
+ xxxflags:g6 ;
+}
+
+rule icond7 ( properties * )
+{
+ local result ;
+ if y in $(properties) || y in $(properties)
+ {
+ result += -yes7 ;
+ }
+ return $(result)
+ aaaflags:f7
+ aaaflags:g7 ;
+}
+
+zzz out : in.yyy
+ : y:-no2 y:-no2 f4 g4
+ @icond6
+ :
+ : y:-yes5 y:-yes5 @icond7
+ ;
+alias out : : n ;
+alias out : : n ;
+# Features that are relevant for out are also relevant for check-propagate
+aaa check-propagate : out ;
+""")
+
+t.write("in.yyy", "")
+
+t.run_build_system()
+t.expect_addition("bin/f1-y/f2-y/f3-y/f4-y/f6-y/g1-y/g2-y/g3-y/g4-y/g6-y/out.xxx")
+t.expect_addition("bin/f1-y/f2-y/f3-y/f4-y/f6-y/g1-y/g2-y/g3-y/g4-y/g6-y/zzz.enabled-on/out.zzz")
+t.expect_addition("bin/f1-y/f2-y/f3-y/f4-y/f5-y/f6-y/f7-y/zzz.enabled-on/check-propagate.aaa")
+
+t.cleanup()
diff --git a/test/gcc_runtime.py b/test/gcc_runtime.py
index 28b6410a5..76c95e1af 100644
--- a/test/gcc_runtime.py
+++ b/test/gcc_runtime.py
@@ -20,9 +20,8 @@ t.expect_output_lines("warning: On gcc, DLLs can not be built with "
t.expect_nothing_more()
t.run_build_system(["link=static", "runtime-link=static"])
-binFolder = "bin/$toolset/debug*/link-static/runtime-link-static"
-t.expect_addition("%s/hello.obj" % binFolder)
-t.expect_addition("%s/hello.lib" % binFolder)
+t.expect_addition("bin/$toolset/debug*/link-static/hello.obj")
+t.expect_addition("bin/$toolset/debug*/link-static/hello.lib")
t.expect_nothing_more()
t.cleanup()
diff --git a/test/generator_selection.py b/test/generator_selection.py
index 64f9cc7b3..1ecca7100 100755
--- a/test/generator_selection.py
+++ b/test/generator_selection.py
@@ -87,9 +87,9 @@ my-obj other-obj : source.extension ;
t.run_build_system()
t.expect_output_lines("Generating a CPP file...")
- t.expect_addition("bin/$toolset/debug*/dummy.my_obj")
- t.expect_addition("Other/bin/$toolset/debug*/other-obj.cpp")
- t.expect_addition("Other/bin/$toolset/debug*/other-obj.my_obj")
+ t.expect_addition("bin/dummy.my_obj")
+ t.expect_addition("Other/bin/other-obj.cpp")
+ t.expect_addition("Other/bin/other-obj.my_obj")
t.expect_nothing_more()
t.cleanup()
@@ -139,8 +139,8 @@ yyy other : source.xxx2 ;
""")
t.run_build_system()
- t.expect_addition("bin/$toolset/debug*/dummy.yyy")
- t.expect_addition("Other/bin/$toolset/debug*/other.yyy")
+ t.expect_addition("bin/dummy.yyy")
+ t.expect_addition("Other/bin/other.yyy")
t.expect_nothing_more()
t.cleanup()
diff --git a/test/generators_test.py b/test/generators_test.py
index 7d0997404..a29a3a538 100644
--- a/test/generators_test.py
+++ b/test/generators_test.py
@@ -215,17 +215,17 @@ nm-exe e : e.cpp ;
""")
t.run_build_system()
- t.expect_addition("bin/$toolset/debug*/" * BoostBuild.List("a.my_exe "
+ t.expect_addition("bin/" * BoostBuild.List("a.my_exe "
"a.my_obj b.my_obj c.tui_h c.cpp c.my_obj d_parser.whl d_lexer.dlp "
"d_parser.cpp d_lexer.cpp d_lexer.my_obj d_parser.lr0 d_parser.h "
"d_parser.my_obj d_parser_symbols.h x.c x.my_obj y.x1 y.x2 y.cpp "
"y.my_obj e.marked_cpp e.positions e.target_cpp e.my_obj e.my_exe "
"f.my_exe obj_1.my_obj obj_2.my_obj"))
- t.expect_addition("lib/bin/$toolset/debug*/" * BoostBuild.List("c.my_obj "
+ t.expect_addition("lib/bin/" * BoostBuild.List("c.my_obj "
"auxilliary.my_lib"))
t.expect_nothing_more()
- folder = "bin/$toolset/debug*"
+ folder = "bin"
t.expect_content_lines("%s/obj_1.my_obj" % folder, " Sources: 'z.cpp'")
t.expect_content_lines("%s/obj_2.my_obj" % folder, " Sources: 'z.cpp'")
t.expect_content_lines("%s/a.my_obj" % folder, " Sources: 'a.cpp'")
@@ -311,7 +311,7 @@ ddd _xxx : _xxx._a ;
def suffix(rename):
if rename: return "_x"
return ""
- name = "bin/$toolset/debug*/_xxx"
+ name = "bin/_xxx"
e = t.expect_addition
e("%s%s._b1" % (name, suffix(rename1)))
e("%s%s._b2" % (name, suffix(rename2)))
diff --git a/test/inline.py b/test/inline.py
index d0ce91ae8..03d91a5d0 100644
--- a/test/inline.py
+++ b/test/inline.py
@@ -21,12 +21,11 @@ int main() {}
t.write("helper.cpp", "void helper() {}\n")
t.run_build_system()
-t.expect_addition("bin/$toolset/debug/link-static*/a__helper.lib")
-t.rm("bin/$toolset/debug/link-static/a__helper.lib")
-t.rm("bin/$toolset/debug/link-static/*/a__helper.lib")
+t.expect_addition("bin/$toolset/debug*/a__helper.lib")
+t.rm("bin/$toolset/debug*/a__helper.lib")
t.run_build_system(["a__helper"])
-t.expect_addition("bin/$toolset/debug/link-static*/a__helper.lib")
+t.expect_addition("bin/$toolset/debug*/a__helper.lib")
t.rm("bin")
@@ -41,8 +40,8 @@ exe a2 : a.cpp [ lib helper : helper.cpp ] ;
t.run_build_system()
t.expect_addition("bin/$toolset/debug/link-static*/a.exe")
-t.expect_addition("bin/$toolset/debug/link-static*/a__helper.lib")
-t.expect_addition("bin/$toolset/debug/link-static*/a2__helper.lib")
+t.expect_addition("bin/$toolset/debug*/a__helper.lib")
+t.expect_addition("bin/$toolset/debug*/a2__helper.lib")
# Check that the 'alias' target does not change the name of inline targets, and
@@ -58,6 +57,6 @@ t.run_build_system()
t.expect_nothing_more()
t.run_build_system(["a"])
-t.expect_addition("bin/$toolset/debug/link-static*/helper.lib")
+t.expect_addition("bin/$toolset/debug*/helper.lib")
t.cleanup()
diff --git a/test/make_rule.py b/test/make_rule.py
index 4a2e09ad9..ab994376e 100644
--- a/test/make_rule.py
+++ b/test/make_rule.py
@@ -28,8 +28,8 @@ make foo.bar : : creator : 12345678 ;
""")
t.run_build_system()
-t.expect_addition("bin/$toolset/debug*/foo.bar")
-t.fail_test(string.find(t.read("bin/$toolset/debug*/foo.bar"), "12345678") == -1)
+t.expect_addition("bin/foo.bar")
+t.fail_test(string.find(t.read("bin/foo.bar"), "12345678") == -1)
# Regression test. Make sure that if a main target is requested two times, and
diff --git a/test/project-test3/jamroot.jam b/test/project-test3/jamroot.jam
index 3d4dfa19a..d7cd490eb 100644
--- a/test/project-test3/jamroot.jam
+++ b/test/project-test3/jamroot.jam
@@ -6,6 +6,7 @@
import os ;
import gcc ;
import property ;
+import toolset ;
rule properties-as-path ( properties * )
{
@@ -21,6 +22,9 @@ rule properties-as-path ( properties * )
[ property.remove incidental : $(r) ] ] ;
}
+toolset.flags yfc-compile KNOWN-PROPERTIES : ;
+toolset.flags yfc-link KNOWN-PROPERTIES : ;
+
rule yfc-compile ( target : sources * : property-set * )
{
PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ;
diff --git a/test/project-test4/jamroot.jam b/test/project-test4/jamroot.jam
index fbbe0abf1..d8cf571ae 100644
--- a/test/project-test4/jamroot.jam
+++ b/test/project-test4/jamroot.jam
@@ -5,6 +5,7 @@
import os ;
import gcc ;
import property ;
+import toolset ;
rule properties-as-path ( properties * )
{
@@ -21,6 +22,10 @@ rule properties-as-path ( properties * )
}
+toolset.flags yfc-compile KNOWN-PROPERTIES : ;
+toolset.flags yfc-link KNOWN-PROPERTIES : ;
+
+
rule yfc-compile ( target : sources * : property-set * )
{
PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ;
@@ -60,4 +65,4 @@ if [ os.name ] = VMS
}
}
-IMPORT $(__name__) : yfc-compile yfc-link : : yfc-compile yfc-link ;
+#IMPORT $(__name__) : yfc-compile yfc-link : : yfc-compile yfc-link ;
diff --git a/test/project_id.py b/test/project_id.py
index 7f4070e07..6477f5957 100755
--- a/test/project_id.py
+++ b/test/project_id.py
@@ -98,7 +98,7 @@ project /project-a3 ;
""")
t.run_build_system()
- t.expect_addition("bin/$toolset/b%d._b" % x for x in range(1, 8))
+ t.expect_addition("bin/b%d._b" % x for x in range(1, 8))
t.expect_nothing_more()
t.cleanup()
@@ -280,7 +280,7 @@ bbb b-invalid-target : /foo//invalid ;
""")
t.run_build_system(["b1", "b2"])
- t.expect_addition("bin/$toolset/debug*/b%d._b" % x for x in range(1, 3))
+ t.expect_addition("bin/b%d._b" % x for x in range(1, 3))
t.expect_nothing_more()
t.run_build_system(["b-invalid"], status=1)
diff --git a/test/project_root_rule.py b/test/project_root_rule.py
index 956c8953b..503b3cad2 100644
--- a/test/project_root_rule.py
+++ b/test/project_root_rule.py
@@ -29,6 +29,6 @@ my-lib foo ;
t.run_build_system(subdir="sub")
-t.expect_addition("sub/bin/$toolset/debug/link-static*/foo.lib")
+t.expect_addition("sub/bin/$toolset/debug*/foo.lib")
t.cleanup()
diff --git a/test/remove_requirement.py b/test/remove_requirement.py
index 8009e0f64..6efd44116 100644
--- a/test/remove_requirement.py
+++ b/test/remove_requirement.py
@@ -12,6 +12,8 @@ t = BoostBuild.Tester(use_test_config=False)
t.write("jamroot.jam", """
project : requirements multi debug:static ;
+# Force link to be relevant
+project : requirements shared:TEST_DLL ;
build-project sub ;
build-project sub2 ;
diff --git a/test/rescan_header.py b/test/rescan_header.py
index 37b37c7d4..1257a223c 100755
--- a/test/rescan_header.py
+++ b/test/rescan_header.py
@@ -35,7 +35,7 @@ obj test : test.cpp : header3.h ;
""")
t.run_build_system(["-j2"])
-t.expect_addition("bin/$toolset/debug*/header3.h")
+t.expect_addition("bin/header3.h")
t.expect_addition("bin/$toolset/debug*/test.obj")
t.expect_nothing_more()
@@ -72,9 +72,9 @@ obj test : test.cpp :
""")
t.run_build_system(["-j2", "test"])
-t.expect_addition("bin/$toolset/debug*/header1.h")
-t.expect_addition("bin/$toolset/debug*/header2.h")
-t.expect_addition("bin/$toolset/debug*/header3.h")
+t.expect_addition("bin/header1.h")
+t.expect_addition("bin/header2.h")
+t.expect_addition("bin/header3.h")
t.expect_addition("bin/$toolset/debug*/test.obj")
t.expect_nothing_more()
@@ -122,9 +122,9 @@ obj test : test.cpp :
""")
t.run_build_system(["-j2", "test"])
-t.expect_addition("bin/$toolset/debug*/header1.h")
-t.expect_addition("bin/$toolset/debug*/header2.h")
-t.expect_addition("bin/$toolset/debug*/header3.h")
+t.expect_addition("bin/header1.h")
+t.expect_addition("bin/header2.h")
+t.expect_addition("bin/header3.h")
t.expect_addition("bin/$toolset/debug*/test.obj")
t.expect_nothing_more()
@@ -184,7 +184,7 @@ exe test : test2.cpp test1.cpp : header3.h ;
""")
t.run_build_system(["-j2", "test"])
-t.expect_addition("bin/$toolset/debug*/header3.h")
+t.expect_addition("bin/header3.h")
t.expect_addition("bin/$toolset/debug*/test1.obj")
t.expect_addition("bin/$toolset/debug*/test2.obj")
t.expect_addition("bin/$toolset/debug*/test.exe")
@@ -192,7 +192,7 @@ t.expect_nothing_more()
t.touch("header3.in")
t.run_build_system(["-j2", "test"])
-t.expect_touch("bin/$toolset/debug*/header3.h")
+t.expect_touch("bin/header3.h")
t.expect_touch("bin/$toolset/debug*/test1.obj")
t.expect_touch("bin/$toolset/debug*/test2.obj")
t.expect_touch("bin/$toolset/debug*/test.exe")
@@ -256,7 +256,7 @@ exe test : test2.cpp test1.cpp : header2.h . ;
""")
t.run_build_system(["-j2", "test"])
-t.expect_addition("bin/$toolset/debug*/header2.h")
+t.expect_addition("bin/header2.h")
t.expect_addition("bin/$toolset/debug*/test1.obj")
t.expect_addition("bin/$toolset/debug*/test2.obj")
t.expect_addition("bin/$toolset/debug*/test.exe")
diff --git a/test/source_order.py b/test/source_order.py
index d3cc2ab20..f21710a8c 100755
--- a/test/source_order.py
+++ b/test/source_order.py
@@ -74,8 +74,8 @@ t.write("file2.c", "")
t.write("file3.c", "")
t.run_build_system()
-t.expect_addition("bin/$toolset/debug*/check.order-test")
-t.expect_content("bin/$toolset/debug*/check.order-test", """\
+t.expect_addition("bin/check.order-test")
+t.expect_content("bin/check.order-test", """\
file2.c
file1.c
file3.c
diff --git a/test/space_in_path.py b/test/space_in_path.py
index f4c6c579a..7f0c041a3 100755
--- a/test/space_in_path.py
+++ b/test/space_in_path.py
@@ -36,7 +36,7 @@ os.environ["TMPDIR"] = tmpdir; # *nix
try:
t.run_build_system(["has space"])
- t.expect_addition("has space/bin/$toolset/debug*/test.txt")
+ t.expect_addition("has space/bin/test.txt")
t.expect_addition("has space/bin/$toolset/debug*/test.passed")
finally:
if oldtmp is not None:
diff --git a/test/static_and_shared_library.py b/test/static_and_shared_library.py
index da010a241..5b3a6b73a 100755
--- a/test/static_and_shared_library.py
+++ b/test/static_and_shared_library.py
@@ -31,7 +31,7 @@ t.expect_nothing_more()
reset()
t.run_build_system(["link=static"], subdir="lib")
-t.expect_addition("lib/bin/$toolset/debug/link-static*/" * BoostBuild.List(
+t.expect_addition("lib/bin/$toolset/debug*/" * BoostBuild.List(
"c.obj auxilliary1.lib auxilliary2.lib"))
t.expect_nothing_more()
diff --git a/test/suffix.py b/test/suffix.py
index b6946a48a..b31dd1730 100644
--- a/test/suffix.py
+++ b/test/suffix.py
@@ -73,6 +73,6 @@ second a : a.cpp ;
""")
t.run_build_system()
-t.expect_addition("bin/$toolset/debug*/a")
+t.expect_addition("bin/a")
t.cleanup()
diff --git a/test/tag.py b/test/tag.py
index 87f537c8c..adf2fce6f 100644
--- a/test/tag.py
+++ b/test/tag.py
@@ -91,11 +91,11 @@ __declspec (dllexport) void x () {}
BoostBuild.List("bin/$toolset/release*/a_rs.exe") +
BoostBuild.List("bin/$toolset/release*/b_rs.dll") +
BoostBuild.List("c/a_rs.exe") +
- BoostBuild.List("bin/$toolset/debug/link-static*/a_dt.exe") +
- BoostBuild.List("bin/$toolset/debug/link-static*/b_dt.lib") +
+ BoostBuild.List("bin/$toolset/debug*/a_dt.exe") +
+ BoostBuild.List("bin/$toolset/debug*/b_dt.lib") +
BoostBuild.List("c/a_dt.exe") +
- BoostBuild.List("bin/$toolset/release/link-static*/a_rt.exe") +
- BoostBuild.List("bin/$toolset/release/link-static*/b_rt.lib") +
+ BoostBuild.List("bin/$toolset/release*/a_rt.exe") +
+ BoostBuild.List("bin/$toolset/release*/b_rt.lib") +
BoostBuild.List("c/a_rt.exe"))
variants = ["debug", "release", "link=static,shared"]
diff --git a/test/test_all.py b/test/test_all.py
index 591b11aae..d443ef207 100644
--- a/test/test_all.py
+++ b/test/test_all.py
@@ -222,6 +222,7 @@ tests = ["absolute_sources",
"expansion",
"explicit",
"feature_cxxflags",
+ "feature_relevant",
"generator_selection",
"generators_test",
"implicit_dependency",