mirror of
https://github.com/boostorg/build.git
synced 2026-02-02 20:52:13 +00:00
Improve the algorithm for computing build properties.
[SVN r22542]
This commit is contained in:
@@ -63,6 +63,16 @@ class property-set
|
||||
{
|
||||
self.non-dependency += $(p) ;
|
||||
}
|
||||
|
||||
if [ MATCH (:) : $(p:G=) ]
|
||||
{
|
||||
self.conditional += $(p) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
self.non-conditional += $(p) ;
|
||||
}
|
||||
|
||||
|
||||
if propagated in $(att)
|
||||
{
|
||||
@@ -106,8 +116,17 @@ class property-set
|
||||
{
|
||||
return $(self.non-dependency) ;
|
||||
}
|
||||
|
||||
|
||||
rule conditional ( )
|
||||
{
|
||||
return $(self.conditional) ;
|
||||
}
|
||||
|
||||
rule non-conditional ( )
|
||||
{
|
||||
return $(self.non-conditional) ;
|
||||
}
|
||||
|
||||
# Returns incidental properties
|
||||
rule incidental ( )
|
||||
{
|
||||
@@ -131,6 +150,16 @@ class property-set
|
||||
return $(self.refined.$(ps)) ;
|
||||
}
|
||||
|
||||
rule expand ( )
|
||||
{
|
||||
if ! $(self.expanded)
|
||||
{
|
||||
self.expanded = [ property-set.create [ feature.expand $(self.raw) ] ] ;
|
||||
}
|
||||
return $(self.expanded) ;
|
||||
}
|
||||
|
||||
|
||||
rule expand-composites ( )
|
||||
{
|
||||
if ! $(self.composites)
|
||||
|
||||
@@ -343,6 +343,13 @@ class main-target : abstract-target
|
||||
# See the documentation for selection rules.
|
||||
local rule select-alternatives ( property-set )
|
||||
{
|
||||
# When selecting alternatives we have to consider defaults,
|
||||
# for example:
|
||||
# lib l : l.cpp : <variant>debug ;
|
||||
# lib l : l_opt.cpp : <variant>release ;
|
||||
# won't work unless we add default value <variant>debug.
|
||||
property-set = [ $(p).add-defaults ] ;
|
||||
|
||||
# The algorithm: we keep the current best viable alternative.
|
||||
# When we've got new best viable alternative, we compare it
|
||||
# with the current one.
|
||||
@@ -445,12 +452,13 @@ class main-target : abstract-target
|
||||
[ feature.compress-subproperties $(raw) ]
|
||||
$(defaults-to-apply)
|
||||
] ;
|
||||
|
||||
|
||||
if $(properties)
|
||||
{
|
||||
for local p in $(properties)
|
||||
{
|
||||
result += [ property-set.create [ feature.split $(p) ] ] ;
|
||||
result += [ property-set.create
|
||||
[ feature.expand [ feature.split $(p) ] ] ] ;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -473,13 +481,16 @@ class main-target : abstract-target
|
||||
rule generate ( property-set )
|
||||
{
|
||||
start-building $(__name__) ;
|
||||
|
||||
# We want composite properties in build request act as if
|
||||
# all the properties it expands too are explicitly specified.
|
||||
property-set = [ $(property-set).expand ] ;
|
||||
|
||||
local all-property-sets = [ apply-default-build $(property-set) ] ;
|
||||
local usage-requirements = [ property-set.empty ] ;
|
||||
local result ;
|
||||
for local p in $(all-property-sets)
|
||||
{
|
||||
p = [ $(p).expand-composites ] ;
|
||||
p = [ $(p).add-defaults ] ;
|
||||
local r = [ generate-really $(p) ] ;
|
||||
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
|
||||
result += $(r[2-]) ;
|
||||
@@ -494,7 +505,7 @@ class main-target : abstract-target
|
||||
# generated virtual target in other elements. It's possible
|
||||
# that no targets are generated.
|
||||
local rule generate-really ( property-set )
|
||||
{
|
||||
{
|
||||
local best-alternatives = [ select-alternatives $(property-set) ] ;
|
||||
if ! $(best-alternatives)
|
||||
{
|
||||
@@ -556,15 +567,6 @@ class file-reference : abstract-target
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Helper for 'find', below.
|
||||
local rule remove-trailing-slash ( string )
|
||||
{
|
||||
local stripped = [ MATCH (.*)/$ : $(string) ] ;
|
||||
stripped ?= $(string) ;
|
||||
return $(stripped) ;
|
||||
}
|
||||
|
||||
if "--quiet" in [ modules.peek : ARGV ]
|
||||
{
|
||||
.quiet = true ;
|
||||
@@ -703,6 +705,92 @@ rule generate-from-reference
|
||||
return [ $(target).generate $(rproperties) ] ;
|
||||
}
|
||||
|
||||
# Given build request and requirements, return properties
|
||||
# common to dependency build request and target build
|
||||
# properties
|
||||
rule common-properties ( build-request requirements )
|
||||
{
|
||||
# For optimization, we add free requirements directly,
|
||||
# without using complex algorithsm.
|
||||
# This gives the complex algorithm better chance of caching results.
|
||||
local free = [ $(requirements).free ] ;
|
||||
local non-free = [ property-set.create
|
||||
[ $(requirements).base ] [ $(requirements).incidental ] ] ;
|
||||
|
||||
local key = .rp.$(build-request)-$(non-free) ;
|
||||
if ! $($(key))
|
||||
{
|
||||
$(key) = [ common-properties2 $(build-request) $(non-free) ] ;
|
||||
}
|
||||
result = [ $($(key)).add-raw $(free) ] ;
|
||||
}
|
||||
|
||||
rule common-properties2 ( build-request requirements )
|
||||
{
|
||||
# This guaranteed that default properties are present
|
||||
# in result, unless they are overrided by some requirement.
|
||||
# FIXME: There is possibility that we've added <foo>bar, which is composite
|
||||
# and expands to <foo2>bar2, but default value of <foo2> is not bar2,
|
||||
# in which case it's not clear what to do.
|
||||
#
|
||||
build-request = [ $(build-request).add-defaults ] ;
|
||||
# Featured added by 'add-default' can be composite and expand
|
||||
# to features without default values -- so they are not added yet.
|
||||
# It could be clearer/faster to expand only newly added properties
|
||||
# but that's not critical.
|
||||
build-request = [ $(build-request).expand ] ;
|
||||
|
||||
# Apply non-conditional requirements.
|
||||
# There's a slight bug here: it's possible that conditional
|
||||
# requirement change a value set by non-conditional requirements. This
|
||||
# should be error, but we don't detect it yet.
|
||||
local raw = [ $(build-request).raw ] ;
|
||||
raw = [ property.refine $(raw) :
|
||||
[ feature.expand [ $(requirements).non-conditional ] ] ] ;
|
||||
|
||||
# We've collected properties that surely must be present in common
|
||||
# properties. We now try to figure out what other properties
|
||||
# should be added in order to satisfy rules (4)-(6) from the docs.
|
||||
|
||||
local conditionals = [ $(requirements).conditional ] ;
|
||||
local count = $(conditionals) and-once-more ;
|
||||
local prev ;
|
||||
|
||||
local current = $(raw) ;
|
||||
|
||||
local ok ;
|
||||
while $(count)
|
||||
{
|
||||
# Evaluate conditionals in context of current properties
|
||||
local e = [ property.evaluate-conditionals-in-context $(conditionals)
|
||||
: $(current) ] ;
|
||||
# ECHO "Got now: " $(e) ;
|
||||
if $(e) = $(prev)
|
||||
{
|
||||
# If we got the same result, we've found final properties.
|
||||
count = ;
|
||||
ok = true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
# Oops, results of evaluation of conditionals has changes
|
||||
# Also 'current' contains leftover from previous evaluation.
|
||||
# Recompute 'current' using initial properties and conditional
|
||||
# requirements.
|
||||
prev = $(e) ;
|
||||
current = [ property.refine $(raw) : [ feature.expand $(e) ] ] ;
|
||||
}
|
||||
count = $(count[2-]) ;
|
||||
}
|
||||
if ! $(ok)
|
||||
{
|
||||
errors.error "Can't evaluate conditional properties " $(conditionals) ;
|
||||
}
|
||||
|
||||
|
||||
return [ property-set.create $(current) ] ;
|
||||
}
|
||||
|
||||
# Implements the most standard way of constructing main target
|
||||
# alternative from sources. Allows sources to be either file or
|
||||
# other main target and handles generation of those dependency
|
||||
@@ -714,6 +802,7 @@ class basic-target : abstract-target
|
||||
import property-set ;
|
||||
import set sequence errors ;
|
||||
import "class" : new ;
|
||||
import property feature ;
|
||||
|
||||
rule __init__ ( name : project
|
||||
: sources * : requirements * :
|
||||
@@ -772,17 +861,8 @@ class basic-target : abstract-target
|
||||
rule match ( property-set )
|
||||
{
|
||||
local condition = [ $(self.requirements).base ] ;
|
||||
local condition2 ;
|
||||
# Weed out conditional properties.
|
||||
for local c in $(condition)
|
||||
{
|
||||
if [ MATCH ^([^:]*)\$ : $(c:G=) ]
|
||||
{
|
||||
condition2 += $(c) ;
|
||||
}
|
||||
}
|
||||
condition = $(condition2) ;
|
||||
|
||||
condition = [ MATCH ^([^:]*)\$ : $(condition) ] ;
|
||||
if $(condition) in [ $(property-set).raw ]
|
||||
{
|
||||
return $(condition) ;
|
||||
@@ -793,21 +873,6 @@ class basic-target : abstract-target
|
||||
}
|
||||
}
|
||||
|
||||
# Determine and return properties which should be used for
|
||||
# building when given 'build-request'. This includes refining
|
||||
# build request with requirements, evaluating conditionals,
|
||||
# generating depenendecies and running actions for features.
|
||||
local rule refined-properties ( build-request )
|
||||
{
|
||||
local erequirements = [ $(self.requirements).evaluate-conditionals
|
||||
$(build-request) ] ;
|
||||
erequirements = [ $(erequirements).expand-composites ] ;
|
||||
|
||||
local rproperties = [ $(build-request).refine $(erequirements) ] ;
|
||||
|
||||
return $(rproperties) ;
|
||||
}
|
||||
|
||||
#
|
||||
# Allows the user to tag the name of the target, according to properties.
|
||||
#
|
||||
@@ -861,7 +926,9 @@ class basic-target : abstract-target
|
||||
{
|
||||
if ! $(self.generated.$(property-set))
|
||||
{
|
||||
local rproperties = [ refined-properties $(property-set) ] ;
|
||||
local rproperties = [ targets.common-properties $(property-set)
|
||||
$(self.requirements) ] ;
|
||||
|
||||
if $(rproperties[1]) != "@error"
|
||||
{
|
||||
local source-targets ;
|
||||
|
||||
@@ -96,7 +96,7 @@ class stlport-target-class : basic-target
|
||||
# manually.
|
||||
|
||||
property-set = [ property-set.create [ difference
|
||||
[ $(property-set).raw ] : <library>/stlport//stlport ] ] ;
|
||||
[ $(property-set).raw ] : <library>/stlport//stlport <stdlib>stlport ] ] ;
|
||||
return [ basic-target.generate $(property-set) ] ;
|
||||
}
|
||||
|
||||
|
||||
72
test/expansion.py
Normal file
72
test/expansion.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) Vladimir Prus 2003. Permission to copy, use, modify, sell and
|
||||
# distribute this software is granted provided this copyright notice appears in
|
||||
# all copies. This software is provided "as is" without express or implied
|
||||
# warranty, and with no claim as to its suitability for any purpose.
|
||||
|
||||
# This file is template for Boost.Build tests. It creates a simple
|
||||
# project that builds one exe from one source, and checks that the exe
|
||||
# is really created.
|
||||
from BoostBuild import Tester, List
|
||||
|
||||
|
||||
t = Tester()
|
||||
|
||||
t.write("a.cpp", """
|
||||
#ifdef CF_IS_OFF
|
||||
int main() { return 0; }
|
||||
#endif
|
||||
|
||||
""")
|
||||
|
||||
t.write("b.cpp", """
|
||||
#ifdef CF_1
|
||||
int main() { return 0; }
|
||||
#endif
|
||||
|
||||
""")
|
||||
|
||||
t.write("c.cpp", """
|
||||
#ifdef FOO
|
||||
int main() { return 0; }
|
||||
#endif
|
||||
|
||||
""")
|
||||
|
||||
|
||||
t.write("Jamfile", """
|
||||
# See if default value of composite feature 'cf'
|
||||
# will be expanded to <define>CF_IS_OFF
|
||||
exe a : a.cpp ;
|
||||
|
||||
# See if subfeature in requirements in expanded.
|
||||
exe b : b.cpp : <cf>on-1 ;
|
||||
|
||||
# See if conditional requirements are recursively expanded.
|
||||
exe c : c.cpp : <toolset>$toolset:<variant>release <variant>release:<define>FOO ;
|
||||
""")
|
||||
|
||||
t.write("project-root.jam", """
|
||||
import feature ;
|
||||
|
||||
feature.feature cf : off on : composite incidental ;
|
||||
|
||||
feature.compose <cf>off : <define>CF_IS_OFF ;
|
||||
|
||||
feature.subfeature cf on : version : 1 2 : composite optional incidental ;
|
||||
|
||||
feature.compose <cf-on:version>1 : <define>CF_1 ;
|
||||
|
||||
""")
|
||||
|
||||
t.expand_toolset("Jamfile")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition(["bin/$toolset/debug/a.exe",
|
||||
"bin/$toolset/debug/b.exe",
|
||||
"bin/$toolset/release/c.exe",
|
||||
])
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -122,6 +122,7 @@ tests = [ "project_test1",
|
||||
"unit_test",
|
||||
"standalone",
|
||||
"library_order",
|
||||
"expansion",
|
||||
#"ordered_properties",
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user