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

Refactorings.

* new/targets.jam
    (main-target.select-alternatives): New rule.
    (main-target.generate): Simplify, using the above.

* new/errors.jam
    (error): Do EXIT if --no-error-backtrace is given.

* tests/alternatives.py: New test.


[SVN r17673]
This commit is contained in:
Vladimir Prus
2003-02-27 14:25:26 +00:00
parent 3787441aa8
commit 9938a0fc41
10 changed files with 256 additions and 134 deletions

View File

@@ -138,6 +138,7 @@ rule error ( messages * : * )
}
}
}
EXIT ;
}
else
{

View File

@@ -262,6 +262,28 @@ rule main-target ( name : project )
self.direct-request.$(base:J=-) = $(property-set) ;
}
}
local rule select-alternatives ( property-set )
{
local viable ; # alternatives that may be used
local ranks ; # ranks for viable alternatives
for local v in $(self.alternatives)
{
# For now, alternative should be derived from 'basic-target'.
# We'll see if this restriction if reasonable.
assert.equal [ is-a $(v) : basic-target ] : true ;
local m = [ $(v).match-rank $(property-set) ] ;
if $(m)
{
viable += $(v) ;
ranks += $(m) ;
}
}
local best = [ sequence.select-highest-ranked $(viable) : $(ranks) ] ;
return $(best) ;
}
# Select an alternative for this main target, by finding all alternatives
@@ -277,83 +299,42 @@ rule main-target ( name : project )
property-set = $(ep) ;
}
# Try to generate all the alternatives.
local alternatives = [ new vector ] ;
for local v in $(self.alternatives)
{
local vtargets = [ $(v).generate $(property-set) ] ;
if $(vtargets) && $(vtargets[1]) != "@error"
{
$(alternatives).push-back [ new vector $(v) $(vtargets) ] ;
}
}
if [ $(alternatives).empty ]
local best-alternatives = [ select-alternatives $(property-set) ] ;
if ! $(best-alternatives)
{
# TODO: probably, should explain, for each alternative,
# why it can't be build.
print.wrapped-text
"warning: skipped build of" [ full-name ]
"with properties" [ $(property-set).raw ] ;
} else {
local result ;
if [ $(alternatives).size ] = 1
{
result = [ $(alternatives).get-at 1 ] ;
result = $(result[2-]) ;
"with properties" [ $(property-set).raw ] ;
}
else if $(best-alternatives[2])
{
# TODO: again, a better error message in in order.
errors.error "Ambiguous alternatives for main target" [ full-name ] ;
}
else
{
# Find the alternative with the longest set of non-free and
# non-indicental requirements and are in 'properties'
local r = [ $(alternatives).indices ] ;
# First compute the length of requirements sets
local req-length ;
for local p in $(r)
local result = [ $(best-alternatives).generate $(property-set) ] ;
# Mark all targets in result as roots
for local t in $(result)
{
local target = [ $(alternatives).at $(p) : 1 ] ;
# FIXME: in general, 'abstract-target' derivatives might not
# have 'requirements' method.
# assert.equal [ is-a $(target) : basic-target ] : true ;
local req = [ $(target).requirements ] ;
req = [ $(req).base ] ;
req-length += [ sequence.length
[ set.intersection $(req) : [ $(property-set).raw ] ] ] ;
$(t).root true ;
}
local best = [ sequence.select-highest-ranked $(r) : $(req-length) ] ;
if ! $(best[2])
{
local index = $(best[1]) ;
result = [ $(alternatives).get-at $(index) ] ;
result = $(result[2-]) ;
}
else
{
error "Ambiguous alternatives for main target" [ full-name ] ;
}
}
# Mark all targets in result as roots
for local t in $(result)
{
$(t).root true ;
}
# Process all vtargets that will be created if this main target
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(result) ] ;
local dg = [ new subvariant-dg $(__name__) : $(property-set) : $(all-targets) ] ;
for local v in $(all-targets)
{
$(v).dg $(dg) ;
}
# Process all vtargets that will be created if this main target
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(result) ] ;
local dg = [ new subvariant-dg $(__name__) : $(property-set) : $(all-targets) ] ;
for local v in $(all-targets)
{
$(v).dg $(dg) ;
}
# Now return virtual targets for the only alternative
return $(result) ;
# Now return virtual targets for the only alternative
return $(result) ;
}
}
}
@@ -461,8 +442,25 @@ rule basic-target ( name : project
{
errors.error "gristed element in sources for" [ full-name ] ;
}
# Returns a number which estimates this targets's suitability for
# building with the given 'property-set'. Among several alternatives
# for a main target, the one with greatest match-rank will be used
# to do actual generation
rule match-rank ( property-set )
{
# First check if our requirements can be satisfied.
local rproperties = [ $(property-set).refine $(self.requirements) ] ;
if $(rproperties[1]) != "@error"
{
# Returns the number of properties common to requirements
# and build request.
return [ sequence.length [ set.intersection
[ $(self.requirements).base ] :
[ $(property-set).raw ] ] ] ;
}
}
# Applies default-build if 'properties' are empty or
# have only single <toolset> element.
# Generates sources. Calls 'construct'

59
test/alternatives.py Normal file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/python
# Test main target alternatives.
from BoostBuild import Tester
t = Tester()
# Test that basic alternatives selection works.
t.write("project-root.jam", " ")
t.write("Jamfile", """
exe a : a_empty.cpp ;
exe a : a.cpp : <variant>release ;
""")
t.write("a_empty.cpp", "")
t.write("a.cpp", "int main() { return 0; }\n")
t.run_build_system("release")
t.expect_addition("bin/$toolset/release/a.exe")
# Test that only properties which are in build request
# matters when selection alternative. IOW, alternative
# with <variant>release is better than one with
# <variant>debug when building release version.
t.write("Jamfile", """
exe a : a_empty.cpp : <variant>debug ;
exe a : a.cpp : <variant>release ;
""")
t.rm("bin/$toolset/release/a.exe")
t.run_build_system("release")
t.expect_addition("bin/$toolset/release/a.exe")
# Test that free properties do not matter. We really don't
# want <cxxflags> property in build request to affect
# alternative selection.
t.write("Jamfile", """
exe a : a_empty.cpp : <variant>debug <define>FOO <include>BAR ;
exe a : a.cpp : <variant>release ;
""")
t.rm("bin/$toolset/release/a.exe")
t.run_build_system("release define=FOO")
t.expect_addition("bin/$toolset/release/a.exe")
# Test that abibuity is reported correctly
t.write("Jamfile", """
exe a : a_empty.cpp ;
exe a : a.cpp ;
""")
expected="""error: Ambiguous alternatives for main target ./a
"""
t.run_build_system("--no-error-backtrace", status=1, stdout=expected)
t.cleanup()

View File

@@ -40,6 +40,7 @@ t.copy("lib/Jamfile2", "lib/Jamfile")
expected="""error: Requirements for project at 'lib' conflict with parent's.
Explanation: link-incompatible properties <threading>single and <threading>multi
"""
t.run_build_system("--no-error-backtrace", stdout=expected, status=None)

View File

@@ -81,7 +81,9 @@ tests = [ "project_test1",
"build_dir",
"searched_lib",
"make_rule",
"alias"]
"alias",
"alternatives",
]
if os.name == 'posix':
tests.append("symlink")

View File

@@ -262,6 +262,28 @@ rule main-target ( name : project )
self.direct-request.$(base:J=-) = $(property-set) ;
}
}
local rule select-alternatives ( property-set )
{
local viable ; # alternatives that may be used
local ranks ; # ranks for viable alternatives
for local v in $(self.alternatives)
{
# For now, alternative should be derived from 'basic-target'.
# We'll see if this restriction if reasonable.
assert.equal [ is-a $(v) : basic-target ] : true ;
local m = [ $(v).match-rank $(property-set) ] ;
if $(m)
{
viable += $(v) ;
ranks += $(m) ;
}
}
local best = [ sequence.select-highest-ranked $(viable) : $(ranks) ] ;
return $(best) ;
}
# Select an alternative for this main target, by finding all alternatives
@@ -277,83 +299,42 @@ rule main-target ( name : project )
property-set = $(ep) ;
}
# Try to generate all the alternatives.
local alternatives = [ new vector ] ;
for local v in $(self.alternatives)
{
local vtargets = [ $(v).generate $(property-set) ] ;
if $(vtargets) && $(vtargets[1]) != "@error"
{
$(alternatives).push-back [ new vector $(v) $(vtargets) ] ;
}
}
if [ $(alternatives).empty ]
local best-alternatives = [ select-alternatives $(property-set) ] ;
if ! $(best-alternatives)
{
# TODO: probably, should explain, for each alternative,
# why it can't be build.
print.wrapped-text
"warning: skipped build of" [ full-name ]
"with properties" [ $(property-set).raw ] ;
} else {
local result ;
if [ $(alternatives).size ] = 1
{
result = [ $(alternatives).get-at 1 ] ;
result = $(result[2-]) ;
"with properties" [ $(property-set).raw ] ;
}
else if $(best-alternatives[2])
{
# TODO: again, a better error message in in order.
errors.error "Ambiguous alternatives for main target" [ full-name ] ;
}
else
{
# Find the alternative with the longest set of non-free and
# non-indicental requirements and are in 'properties'
local r = [ $(alternatives).indices ] ;
# First compute the length of requirements sets
local req-length ;
for local p in $(r)
local result = [ $(best-alternatives).generate $(property-set) ] ;
# Mark all targets in result as roots
for local t in $(result)
{
local target = [ $(alternatives).at $(p) : 1 ] ;
# FIXME: in general, 'abstract-target' derivatives might not
# have 'requirements' method.
# assert.equal [ is-a $(target) : basic-target ] : true ;
local req = [ $(target).requirements ] ;
req = [ $(req).base ] ;
req-length += [ sequence.length
[ set.intersection $(req) : [ $(property-set).raw ] ] ] ;
$(t).root true ;
}
local best = [ sequence.select-highest-ranked $(r) : $(req-length) ] ;
if ! $(best[2])
{
local index = $(best[1]) ;
result = [ $(alternatives).get-at $(index) ] ;
result = $(result[2-]) ;
}
else
{
error "Ambiguous alternatives for main target" [ full-name ] ;
}
}
# Mark all targets in result as roots
for local t in $(result)
{
$(t).root true ;
}
# Process all vtargets that will be created if this main target
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(result) ] ;
local dg = [ new subvariant-dg $(__name__) : $(property-set) : $(all-targets) ] ;
for local v in $(all-targets)
{
$(v).dg $(dg) ;
}
# Process all vtargets that will be created if this main target
# is created.
local all-targets =
[ sequence.transform virtual-target.traverse : $(result) ] ;
local dg = [ new subvariant-dg $(__name__) : $(property-set) : $(all-targets) ] ;
for local v in $(all-targets)
{
$(v).dg $(dg) ;
}
# Now return virtual targets for the only alternative
return $(result) ;
# Now return virtual targets for the only alternative
return $(result) ;
}
}
}
@@ -461,8 +442,25 @@ rule basic-target ( name : project
{
errors.error "gristed element in sources for" [ full-name ] ;
}
# Returns a number which estimates this targets's suitability for
# building with the given 'property-set'. Among several alternatives
# for a main target, the one with greatest match-rank will be used
# to do actual generation
rule match-rank ( property-set )
{
# First check if our requirements can be satisfied.
local rproperties = [ $(property-set).refine $(self.requirements) ] ;
if $(rproperties[1]) != "@error"
{
# Returns the number of properties common to requirements
# and build request.
return [ sequence.length [ set.intersection
[ $(self.requirements).base ] :
[ $(property-set).raw ] ] ] ;
}
}
# Applies default-build if 'properties' are empty or
# have only single <toolset> element.
# Generates sources. Calls 'construct'

View File

@@ -138,6 +138,7 @@ rule error ( messages * : * )
}
}
}
EXIT ;
}
else
{

59
v2/test/alternatives.py Normal file
View File

@@ -0,0 +1,59 @@
#!/usr/bin/python
# Test main target alternatives.
from BoostBuild import Tester
t = Tester()
# Test that basic alternatives selection works.
t.write("project-root.jam", " ")
t.write("Jamfile", """
exe a : a_empty.cpp ;
exe a : a.cpp : <variant>release ;
""")
t.write("a_empty.cpp", "")
t.write("a.cpp", "int main() { return 0; }\n")
t.run_build_system("release")
t.expect_addition("bin/$toolset/release/a.exe")
# Test that only properties which are in build request
# matters when selection alternative. IOW, alternative
# with <variant>release is better than one with
# <variant>debug when building release version.
t.write("Jamfile", """
exe a : a_empty.cpp : <variant>debug ;
exe a : a.cpp : <variant>release ;
""")
t.rm("bin/$toolset/release/a.exe")
t.run_build_system("release")
t.expect_addition("bin/$toolset/release/a.exe")
# Test that free properties do not matter. We really don't
# want <cxxflags> property in build request to affect
# alternative selection.
t.write("Jamfile", """
exe a : a_empty.cpp : <variant>debug <define>FOO <include>BAR ;
exe a : a.cpp : <variant>release ;
""")
t.rm("bin/$toolset/release/a.exe")
t.run_build_system("release define=FOO")
t.expect_addition("bin/$toolset/release/a.exe")
# Test that abibuity is reported correctly
t.write("Jamfile", """
exe a : a_empty.cpp ;
exe a : a.cpp ;
""")
expected="""error: Ambiguous alternatives for main target ./a
"""
t.run_build_system("--no-error-backtrace", status=1, stdout=expected)
t.cleanup()

View File

@@ -40,6 +40,7 @@ t.copy("lib/Jamfile2", "lib/Jamfile")
expected="""error: Requirements for project at 'lib' conflict with parent's.
Explanation: link-incompatible properties <threading>single and <threading>multi
"""
t.run_build_system("--no-error-backtrace", stdout=expected, status=None)

View File

@@ -81,7 +81,9 @@ tests = [ "project_test1",
"build_dir",
"searched_lib",
"make_rule",
"alias"]
"alias",
"alternatives",
]
if os.name == 'posix':
tests.append("symlink")