2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-17 01:32:12 +00:00

Implement feature relevance.

* New feature <relevant> which is automatically deduced in most cases.
* Features which are not relevant do not affect target paths and
  do not prevent merging of virtual targets.
* generators.jam: generator.run always returns usage-requirements
  to allow usage-requirements in non-top-level generators.  This
  is necessary because we're using usage-requirements to track
  relevance from flags.
* New rule toolset.uses-features to specify features that the rule
  checks manually, instead of using toolset.flags.  In the future,
  we should consider restricting the properties actually passed,
  to detect errors.
* Adjust tests to handle the new paths (verified by inspection).
* Add temporary option --ignore-relevance to consider all features relevant
  to aid migration.
* New rule property.evaluate-conditional-relevance which helps tracking
  relevance in <conditional>.
* Widely scattered changes to use the new interfaces.
This commit is contained in:
Steven Watanabe
2018-01-13 09:13:49 -07:00
parent ae4e151967
commit ee613a6a28
50 changed files with 674 additions and 122 deletions

View File

@@ -856,6 +856,60 @@ path-constant DATA : data/a.txt ;
</listitem>
</varlistentry>
<varlistentry id="bbv2.reference.features.relevant"><term><literal>relevant</literal></term>
<listitem>
<indexterm><primary>features</primary><secondary>relevance</secondary></indexterm>
<indexterm><primary>relevant</primary></indexterm>
<para>
<emphasis role="bold">Allowed values:</emphasis> the name of any feature.
</para>
<para>
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.
</para>
<para>
A feature will be considered relevant if any of the following are true
<itemizedlist>
<listitem>It is referenced by <literal>toolset.flags</literal> or <literal>toolset.uses-features</literal></listitem>
<listitem>It is used by the requirements of a generator</listitem>
<listitem>It is a subfeature of a relevant feature</listitem>
<listitem>It has a subfeature which is relevant</listitem>
<listitem>It is a composite feature, and any composed feature is relevant</listitem>
<listitem>It affects target alternative selection for a main target</listitem>
<listitem>It is a propagated feature and is relevant for any dependency</listitem>
<listitem>It is relevant for any dependency created by the same main target</listitem>
<listitem>It is used in the condition of a conditional property and the corresponding value is relevant</listitem>
<listitem>It is explicitly named as relevent</listitem>
</itemizedlist>
</para>
<para>Relevant features cannot be automatically deduced in the following cases:</para>
<itemizedlist>
<listitem>Indirect conditionals. Solution: return properties of the form
<literal>&lt;relevant&gt;result-feature:&lt;relevant&gt;condition-feature</literal>
<note><para>This isn't really a <link linkend="bbv2.reference.variants.propcond">conditional</link>,
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</para></note></listitem>
<listitem>
<para>Action rules that read properties. Solution: add <literal>toolset.uses-features</literal>
to tell Boost.Build that the feature is actually used.</para>
</listitem>
<listitem>
<para>Generators and targets that manipulate property-sets directly.
Solution: set <literal>&lt;relevant&gt;</literal> manually.</para>
</listitem>
</itemizedlist>
</listitem>
</varlistentry>
</variablelist>
</section>
@@ -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 <link linkend="bbv2.reference.features.relevant">relevant</link>
non-free, non-incidental properties. For example,
given a property set containing:
<code>&lt;toolset&gt;gcc &lt;toolset-gcc:version&gt;4.6.1 &lt;variant&gt;debug
&lt;warnings&gt;all &lt;define&gt;_DEBUG &lt;include&gt;/usr/local/include

View File

@@ -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 <conditional>@$(instance).check ;
return <conditional>@$(instance).check
[ property.evaluate-conditional-relevance
$(true-properties) $(false-properties)
: [ configure.get-relevant-features ] <link> ] ;
}

View File

@@ -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 <conditional>@$(instance).check ;
return <conditional>@$(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 <conditional>@$(instance).check ;
return <conditional>@$(instance).check
[ property.evaluate-conditional-relevance
[ $(instance).all-properties ]
: [ configure.get-relevant-features ] ] ;
}

View File

@@ -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 "^(.*):<relevant>(.*)$" : $(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.
#

View File

@@ -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>$(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 ] ;
}
}

View File

@@ -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> ] ;
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) = <conditional>
if ( [ MATCH (:) : $(p:G=) ] && ! ( free in [ feature.attributes $(p:G) ] ) ) || $(p:G) = <conditional>
{
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.

View File

@@ -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 <relevant> 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 += <relevant>$(value):<relevant>$(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 += <relevant>$(value):<relevant>$(condition) ;
}
}
return [ sequence.unique $(result) ] ;
}
rule expand-subfeatures-in-conditions ( properties * )
{
local result ;

View File

@@ -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 <relevant>$(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 <relevant> ]
[ $(rproperties).get <relevant> ] ] ;
gur = [ property-set.create
[ property.change [ $(gur).raw ] : <relevant> ]
<relevant>$(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 <relevant> properties
local relevant ;
for local r in [ $(xusage-requirements).get <relevant> ]
{
local check = [ MATCH "(.*):<relevant>(.*)" : $(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> ]
<relevant>$(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) ] ;
}

View File

@@ -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 <relevant>$(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.

View File

@@ -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) ;

View File

@@ -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 <bison.prefix> ;
_ = " " ;
actions bison
{
bison $(PREFIX_OPT) -d -o $(<[1]) $(>)
bison -p$(_)$(PREFIX) -d -o $(<[1]) $(>)
}

View File

@@ -274,6 +274,7 @@ rule translate-path ( path )
}
}
toolset.uses-features doxygen.headers-to-doxyfile : "<doxygen:param>" ;
# Generates a doxygen configuration file (doxyfile) given a set of C++ sources
# and a property list that may contain <doxygen:param> features.
@@ -321,6 +322,7 @@ rule headers-to-doxyfile ( target : sources * : properties * )
print.text $(text) : true ;
}
toolset.uses-features doxygen.run : <doxygen.rmdir> "<doxygen:param>" ;
# Run Doxygen. See doxygen-action for a description of the strange properties of
# this rule.
@@ -406,6 +408,7 @@ rule collect ( target : source : properties * )
: <xsl:param>doxygen.xml.path=$(native-path) ;
}
toolset.uses-features doxygen.xml-to-boostbook : <prefix> <reftitle> ;
# Translate Doxygen XML into BoostBook.
#

View File

@@ -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 ;

View File

@@ -25,5 +25,5 @@ rule detect ( properties * )
local ps = [ property-set.create $(properties) ] ;
local api = [ $(ps).get <threadapi> ] ;
if ! $(api) { api = [ get-default $(ps) ] ; }
return <threadapi>$(api) ;
return <threadapi>$(api) <relevant>threadapi:<relevant>target-os ;
}

View File

@@ -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>$(pch-file) <cflags>-Winvalid-pch ]
$(pch-file)
[ $(pch-file[1]).add-raw <pch-file>$(pch-file[2-]) <cflags>-Winvalid-pch ]
$(pch-file[2-])
;
}

View File

@@ -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) ] ;
}
}

View File

@@ -54,8 +54,9 @@ class lib-generator : generator
}
property-set = [ $(property-set).add-raw <main-target-type>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 <relevant>link ] $(result[2-]) ;
}
}

View File

@@ -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 <xdll-path>$(extra-xdll-paths) ] ] ;
ur = [ $(ur).add $(result[1]) ] ;
}
return $(ur) $(result) ;
return $(ur) $(result[2-]) ;
}
rule extra-usage-requirements ( created-targets * : property-set )

View File

@@ -38,7 +38,7 @@ class searched-lib-generator : generator
local search = [ feature.get-values <search> : $(properties) ] ;
local a = [ new null-action $(property-set) ] ;
local a = [ new null-action [ $(property-set).add-raw <relevant>link ] ] ;
local lib-name = [ feature.get-values <name> : $(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 : <name>png ;
# the 'z' target should be returned, so that apps linking to 'png'
# will link to 'z', too.
return [ property-set.create <xdll-path>$(search) ]
return [ property-set.create <xdll-path>$(search) <relevant>link ]
[ virtual-target.register $(t) ] $(sources) ;
}
}

View File

@@ -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 <flex.prefix> ;
actions lex
{

View File

@@ -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) ] ;
}
}

View File

@@ -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 <testing.arg> ;
toolset.uses-features mpi.capture-output :
<testing.launcher> <testing.execute> <dll-path> <xdll-path> <target-os>
<mpi:processes> ;
rule capture-output ( target : sources * : properties * )
{
# Use the standard capture-output rule to run the tests

View File

@@ -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 : <embed-manifest> <embed-manifest-file> ;
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-header)
<pch-file>$(pch-file) ] $(generated) ;
return [ $(generated[1]).add-raw <pch-header>$(pch-header)
<pch-file>$(pch-file) ] $(generated[2-]) ;
}
}
@@ -878,7 +879,7 @@ local rule set-setup-command ( targets * : properties * )
if ! $($(key))
{
properties = [ feature.expand $(properties) ] ;
properties = [ property.select <toolset> <toolset-msvc:version> <architecture> <address-model> <windows-api> : $(properties) ] ;
properties = [ property.select <toolset> <toolset-msvc:version> <architecture> <address-model> <windows-api> <relevant> : $(properties) ] ;
local ps = [ property-set.create $(properties) <msvc.setup-options>$(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 <debug-symbols> ] = "on"
{

View File

@@ -1243,6 +1243,10 @@ local rule pyd-pythonpath ( source )
toolset.flags python.capture-output ARGS <testing.arg> ;
toolset.flags python.capture-output INPUT_FILES <testing.input-file> ;
toolset.uses-features python.capture-output :
<testing.launcher> <testing.execute> <dll-path> <xdll-path> <target-os>
<pythonpath> ;
rule capture-output ( target : sources * : properties * )
{
# Setup up a proper DLL search path. Here, $(sources[1]) is a python module

View File

@@ -89,6 +89,9 @@ class stlport-target-class : basic-target
local requirements ;
requirements += <stdlib-stlport:version>$(self.version) ;
requirements += <relevant>runtime-debugging ;
requirements += <relevant>toolset ;
requirements += <relevant>runtime-link ;
self.requirements = [ property-set.create $(requirements) ] ;
}

View File

@@ -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 : <preserve-test-targets> ;
toolset.uses-features testing.expect-failure : <preserve-test-targets> ;
# The action rules called by generators.
@@ -456,6 +458,9 @@ toolset.flags testing.capture-output ARGS <testing.arg> ;
toolset.flags testing.capture-output INPUT_FILES <testing.input-file> ;
toolset.flags testing.capture-output LAUNCHER <testing.launcher> ;
toolset.uses-features testing.capture-output :
<testing.launcher> <testing.execute> <dll-path> <xdll-path> <target-os> ;
if --remove-test-targets in [ modules.peek : ARGV ]
{
feature.set-default preserve-test-targets : off ;

View File

@@ -151,6 +151,7 @@ IMPORT xsltproc : register-generator : : generators.register-xslt ;
rule flags ( rulename )
{
toolset.uses-features $(rulename) : <xsl:param> <catalog> : unchecked ;
toolset.flags $(rulename) XSL-PATH : <xsl:path> : unchecked ;
toolset.flags $(rulename) FLAGS : <flags> : unchecked ;
}

View File

@@ -214,8 +214,9 @@ generators.register-linker mock.link : LIB OBJ : EXE : <toolset>mock ;
generators.register-linker mock.link.dll : LIB OBJ : SHARED_LIB : <toolset>mock ;
generators.register-archiver mock.archive : OBJ : STATIC_LIB : <toolset>mock ;
toolset.flags mock.compile INCLUDES <include> ;
toolset.flags mock.compile DEFINES <define> ;
toolset.flags mock.compile OPTIONS <link>shared : -fPIC ;
toolset.flags mock.compile INCLUDES : <include> ;
toolset.flags mock.compile DEFINES : <define> ;
actions compile.c
{

View File

@@ -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")

View File

@@ -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():

View File

@@ -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()

View File

@@ -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()

142
test/feature_relevant.py Normal file
View File

@@ -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 <relevant> 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 : <xxxflags> ;
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 : <zzz.enabled>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 : <aaaflags> ;
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 <xxxflags> is relevant
feature f1 : n y : composite propagated ;
feature.compose <f1>y : <xxxflags>-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 <g1>y : <xxxflags>-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
<f1>y <f2>y <f3>y <f4>y <f5>y <f6>y <f7>y
<g1>y <g2>y <g3>y <g4>y <g5>y <g6>y <g7>y <zzz.enabled>on ;
rule icond6 ( properties * )
{
local result ;
if <f6>y in $(properties) || <g6>y in $(properties)
{
result += <xxxflags>-yes6 ;
}
return $(result)
<relevant>xxxflags:<relevant>f6
<relevant>xxxflags:<relevant>g6 ;
}
rule icond7 ( properties * )
{
local result ;
if <f7>y in $(properties) || <g7>y in $(properties)
{
result += <aaaflags>-yes7 ;
}
return $(result)
<relevant>aaaflags:<relevant>f7
<relevant>aaaflags:<relevant>g7 ;
}
zzz out : in.yyy
: <f2>y:<xxxflags>-no2 <g2>y:<xxxflags>-no2 <relevant>f4 <relevant>g4
<conditional>@icond6
:
: <f5>y:<aaaflags>-yes5 <g5>y:<aaaflags>-yes5 <conditional>@icond7
;
alias out : : <f3>n ;
alias out : : <g3>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()

View File

@@ -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()

View File

@@ -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()

View File

@@ -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)))

View File

@@ -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()

View File

@@ -28,8 +28,8 @@ make foo.bar : : creator : <test_feature>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

View File

@@ -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> <optimization> ;
toolset.flags yfc-link KNOWN-PROPERTIES : <toolset> <optimization> ;
rule yfc-compile ( target : sources * : property-set * )
{
PROPERTIES on $(target) = [ properties-as-path $(property-set) ] ;

View File

@@ -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> <optimization> ;
toolset.flags yfc-link KNOWN-PROPERTIES : <toolset> <optimization> ;
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 ;

View File

@@ -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)

View File

@@ -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()

View File

@@ -12,6 +12,8 @@ t = BoostBuild.Tester(use_test_config=False)
t.write("jamroot.jam", """
project : requirements <threading>multi <variant>debug:<link>static ;
# Force link to be relevant
project : requirements <link>shared:<define>TEST_DLL ;
build-project sub ;
build-project sub2 ;

View File

@@ -35,7 +35,7 @@ obj test : test.cpp : <implicit-dependency>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 : <implicit-dependency>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 : <implicit-dependency>header2.h <include>. ;
""")
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")

View File

@@ -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

View File

@@ -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:

View File

@@ -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()

View File

@@ -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()

View File

@@ -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"]

View File

@@ -222,6 +222,7 @@ tests = ["absolute_sources",
"expansion",
"explicit",
"feature_cxxflags",
"feature_relevant",
"generator_selection",
"generators_test",
"implicit_dependency",