mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
Wholesale Boost.Build merge from the trunk
[SVN r49353]
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This file is part of Boost Build version 2. You can think of it as forming the
|
||||
# the main() routine. It is invoked by the bootstrapping code in bootstrap.jam.
|
||||
# main() routine. It is invoked by the bootstrapping code in bootstrap.jam.
|
||||
|
||||
import build-request ;
|
||||
import builtin ;
|
||||
@@ -22,6 +22,7 @@ import regex ;
|
||||
import sequence ;
|
||||
import targets ;
|
||||
import toolset ;
|
||||
import utility ;
|
||||
import version ;
|
||||
import virtual-target ;
|
||||
|
||||
@@ -90,8 +91,8 @@ rule command-line-free-features ( )
|
||||
|
||||
|
||||
# Returns the location of the build system. The primary use case is building
|
||||
# Boost where it's sometimes needed to get the location of other components
|
||||
# (e.g. BoostBook files) and it's convenient to use locations relative to the
|
||||
# Boost where it is sometimes needed to get the location of other components
|
||||
# (e.g. BoostBook files) and it is convenient to use locations relative to the
|
||||
# Boost Build path.
|
||||
#
|
||||
rule location ( )
|
||||
@@ -138,7 +139,7 @@ local rule actual-clean-targets ( )
|
||||
local targets-to-clean ;
|
||||
for local t in $(.results-of-main-targets)
|
||||
{
|
||||
# Don't include roots or sources.
|
||||
# Do not include roots or sources.
|
||||
targets-to-clean += [ virtual-target.traverse $(t) ] ;
|
||||
}
|
||||
targets-to-clean = [ sequence.unique $(targets-to-clean) ] ;
|
||||
@@ -169,8 +170,8 @@ local rule actual-clean-targets ( )
|
||||
|
||||
|
||||
# Given a target id, try to find and return the corresponding target. This is
|
||||
# only invoked when there's no Jamfile in ".". This code somewhat duplicates
|
||||
# code in project-target.find but we can't reuse that code without a
|
||||
# only invoked when there is no Jamfile in ".". This code somewhat duplicates
|
||||
# code in project-target.find but we can not reuse that code without a
|
||||
# project-targets instance.
|
||||
#
|
||||
local rule find-target ( target-id )
|
||||
@@ -305,7 +306,7 @@ local rule load-configuration-files
|
||||
if $(uq)
|
||||
{
|
||||
test-config = $(uq) ;
|
||||
}
|
||||
}
|
||||
if $(test-config)
|
||||
{
|
||||
local where =
|
||||
@@ -350,6 +351,9 @@ local rule load-configuration-files
|
||||
local user-config = [ MATCH ^--user-config=(.*)$ : $(.argv) ] ;
|
||||
user-config = $(user-config[-1]) ;
|
||||
user-config ?= [ os.environ BOOST_BUILD_USER_CONFIG ] ;
|
||||
# Special handling for the case when the OS does not strip the quotes
|
||||
# around the file name, as is the case when using Cygwin bash.
|
||||
user-config = [ utility.unquote $(user-config) ] ;
|
||||
local explicitly-requested = $(user-config) ;
|
||||
user-config ?= user-config.jam ;
|
||||
|
||||
@@ -366,7 +370,8 @@ local rule load-configuration-files
|
||||
|
||||
if $(.debug-config)
|
||||
{
|
||||
ECHO "notice: Loading explicitly specified user configuration file:" ;
|
||||
ECHO "notice: Loading explicitly specified user"
|
||||
"configuration file:" ;
|
||||
ECHO " $(user-config)" ;
|
||||
}
|
||||
|
||||
@@ -407,14 +412,14 @@ local rule process-explicit-toolset-requests
|
||||
|
||||
if $(.debug-config)
|
||||
{
|
||||
ECHO "notice: [cmdline-cfg] Detected command-line request for"
|
||||
ECHO notice: [cmdline-cfg] Detected command-line request for
|
||||
$(toolset-version): "toolset=" $(toolset) "version="
|
||||
$(version) ;
|
||||
}
|
||||
|
||||
# If the toolset isn't known, configure it now.
|
||||
# If the toolset is not known, configure it now.
|
||||
local known ;
|
||||
if $(toolset) in [ feature.values <toolset> ]
|
||||
if $(toolset) in [ feature.values <toolset> ]
|
||||
{
|
||||
known = true ;
|
||||
}
|
||||
@@ -423,6 +428,14 @@ local rule process-explicit-toolset-requests
|
||||
{
|
||||
known = ;
|
||||
}
|
||||
# TODO: we should do 'using $(toolset)' in case no version has been
|
||||
# specified and there are no versions defined for the given toolset to
|
||||
# allow the toolset to configure its default version. For this we need
|
||||
# to know how to detect whether a given toolset has any versions
|
||||
# defined. An alternative would be to do this whenever version is not
|
||||
# specified but that would require that toolsets correctly handle the
|
||||
# case when their default version is configured multiple times which
|
||||
# should be checked for all existing toolsets first.
|
||||
|
||||
if ! $(known)
|
||||
{
|
||||
@@ -443,13 +456,14 @@ local rule process-explicit-toolset-requests
|
||||
}
|
||||
|
||||
# Make sure we get an appropriate property into the build request in
|
||||
# case toolset was specified using the "--toolset=..." command-line
|
||||
# case toolset has been specified using the "--toolset=..." command-line
|
||||
# option form.
|
||||
if ! $(t) in $(.argv) && ! $(t) in $(feature-toolsets)
|
||||
{
|
||||
if $(.debug-config)
|
||||
{
|
||||
ECHO notice: [cmdline-cfg] adding toolset=$(t) "to build request." ;
|
||||
ECHO notice: [cmdline-cfg] adding toolset=$(t) to the build
|
||||
request. ;
|
||||
}
|
||||
extra-properties += toolset=$(t) ;
|
||||
}
|
||||
@@ -546,7 +560,7 @@ local rule should-clean-project ( project )
|
||||
ECHO "warning: No toolsets are configured." ;
|
||||
ECHO "warning: Configuring default toolset" \"$(default-toolset)\". ;
|
||||
ECHO "warning: If the default is wrong, your build may not work correctly." ;
|
||||
ECHO "warning: Use the \"--toolset=xxxxx\" option to override our guess." ;
|
||||
ECHO "warning: Use the \"toolset=xxxxx\" option to override our guess." ;
|
||||
ECHO "warning: For more configuration options, please consult" ;
|
||||
ECHO "warning: http://boost.org/boost-build2/doc/html/bbv2/advanced/configuration.html" ;
|
||||
|
||||
@@ -615,7 +629,7 @@ local rule should-clean-project ( project )
|
||||
local virtual-targets ;
|
||||
local actual-targets ;
|
||||
|
||||
|
||||
|
||||
# Process each target specified on the command-line and convert it into
|
||||
# internal Boost Build target objects. Detect special clean target. If no
|
||||
# main Boost Build targets were explictly requested use the current project
|
||||
@@ -641,7 +655,7 @@ local rule should-clean-project ( project )
|
||||
if ! $(t)
|
||||
{
|
||||
ECHO "notice: could not find main target" $(id) ;
|
||||
ECHO "notice: assuming it's a name of file to create." ;
|
||||
ECHO "notice: assuming it is a name of file to create." ;
|
||||
explicitly-requested-files += $(id) ;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -33,8 +33,8 @@ class alias-target-class : basic-target
|
||||
rule __init__ ( name : project : sources * : requirements *
|
||||
: default-build * : usage-requirements * )
|
||||
{
|
||||
basic-target.__init__ $(name) : $(project) : $(sources) : $(requirements)
|
||||
: $(default-build) : $(usage-requirements) ;
|
||||
basic-target.__init__ $(name) : $(project) : $(sources) :
|
||||
$(requirements) : $(default-build) : $(usage-requirements) ;
|
||||
}
|
||||
|
||||
rule construct ( name : source-targets * : property-set )
|
||||
@@ -45,16 +45,16 @@ class alias-target-class : basic-target
|
||||
rule compute-usage-requirements ( subvariant )
|
||||
{
|
||||
local base = [ basic-target.compute-usage-requirements $(subvariant) ] ;
|
||||
# Add source's usage requirement. If we don't do this, "alias" does not
|
||||
# look like a 100% alias.
|
||||
return [ $(base).add [ $(subvariant).sources-usage-requirements ] ] ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Declares the 'alias' target. It will build sources, and return them unaltered.
|
||||
# Declares the 'alias' target. It will process its sources virtual-targets by
|
||||
# returning them unaltered as its own constructed virtual-targets.
|
||||
#
|
||||
rule alias ( name : sources * : requirements * : default-build * : usage-requirements * )
|
||||
rule alias ( name : sources * : requirements * : default-build * :
|
||||
usage-requirements * )
|
||||
{
|
||||
local project = [ project.current ] ;
|
||||
|
||||
@@ -62,8 +62,10 @@ rule alias ( name : sources * : requirements * : default-build * : usage-require
|
||||
[ new alias-target-class $(name) : $(project)
|
||||
: [ targets.main-target-sources $(sources) : $(name) : no-renaming ]
|
||||
: [ targets.main-target-requirements $(requirements) : $(project) ]
|
||||
: [ targets.main-target-default-build $(default-build) : $(project) ]
|
||||
: [ targets.main-target-usage-requirements $(usage-requirements) : $(project) ]
|
||||
: [ targets.main-target-default-build $(default-build) : $(project)
|
||||
]
|
||||
: [ targets.main-target-usage-requirements $(usage-requirements) :
|
||||
$(project) ]
|
||||
] ;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ import string ;
|
||||
|
||||
|
||||
# Transform property-set by applying f to each component property.
|
||||
#
|
||||
local rule apply-to-property-set ( f property-set )
|
||||
{
|
||||
local properties = [ feature.split $(property-set) ] ;
|
||||
@@ -20,9 +21,10 @@ local rule apply-to-property-set ( f property-set )
|
||||
}
|
||||
|
||||
|
||||
# Expand the given build request by combining all property-sets which don't
|
||||
# Expand the given build request by combining all property-sets which do not
|
||||
# specify conflicting non-free features. Expects all the project files to
|
||||
# already be loaded.
|
||||
#
|
||||
rule expand-no-defaults ( property-sets * )
|
||||
{
|
||||
# First make all features and subfeatures explicit.
|
||||
@@ -38,6 +40,7 @@ rule expand-no-defaults ( property-sets * )
|
||||
|
||||
# Implementation of x-product, below. Expects all the project files to already
|
||||
# be loaded.
|
||||
#
|
||||
local rule x-product-aux ( property-sets + )
|
||||
{
|
||||
local result ;
|
||||
@@ -49,7 +52,7 @@ local rule x-product-aux ( property-sets + )
|
||||
{
|
||||
local x-product-seen ;
|
||||
{
|
||||
# Don't mix in any conflicting features.
|
||||
# Do not mix in any conflicting features.
|
||||
local x-product-used = $(x-product-used) $(f) ;
|
||||
|
||||
if $(property-sets[2])
|
||||
@@ -61,8 +64,8 @@ local rule x-product-aux ( property-sets + )
|
||||
result ?= $(property-sets[1]) ;
|
||||
}
|
||||
|
||||
# If we didn't encounter a conflicting feature lower down, don't recurse
|
||||
# again.
|
||||
# If we did not encounter a conflicting feature lower down, do not
|
||||
# recurse again.
|
||||
if ! [ set.intersection $(f) : $(x-product-seen) ]
|
||||
{
|
||||
property-sets = ;
|
||||
@@ -76,7 +79,7 @@ local rule x-product-aux ( property-sets + )
|
||||
result += [ x-product-aux $(property-sets[2-]) : $(feature-space) ] ;
|
||||
}
|
||||
|
||||
# Note that we've seen these features so that higher levels will recurse
|
||||
# Note that we have seen these features so that higher levels will recurse
|
||||
# again without them set.
|
||||
x-product-seen += $(f) $(seen) ;
|
||||
return $(result) ;
|
||||
@@ -86,6 +89,7 @@ local rule x-product-aux ( property-sets + )
|
||||
# Return the cross-product of all elements of property-sets, less any that would
|
||||
# contain conflicting values for single-valued features. Expects all the project
|
||||
# files to already be loaded.
|
||||
#
|
||||
local rule x-product ( property-sets * )
|
||||
{
|
||||
if $(property-sets).non-empty
|
||||
@@ -101,6 +105,7 @@ local rule x-product ( property-sets * )
|
||||
|
||||
# Returns true if either 'v' or the part of 'v' before the first '-' symbol is
|
||||
# an implicit value. Expects all the project files to already be loaded.
|
||||
#
|
||||
local rule looks-like-implicit-value ( v )
|
||||
{
|
||||
if [ feature.is-implicit-value $(v) ]
|
||||
@@ -123,6 +128,7 @@ local rule looks-like-implicit-value ( v )
|
||||
# "vector" means container.jam's "vector"). First is the set of targets
|
||||
# specified in the command line, and second is the set of requested build
|
||||
# properties. Expects all the project files to already be loaded.
|
||||
#
|
||||
rule from-command-line ( command-line * )
|
||||
{
|
||||
local targets ;
|
||||
@@ -144,8 +150,8 @@ rule from-command-line ( command-line * )
|
||||
if [ MATCH "(.*=.*)" : $(e) ]
|
||||
|| [ looks-like-implicit-value $(e:D=) : $(feature-space) ]
|
||||
{
|
||||
properties += [ convert-command-line-element $(e)
|
||||
: $(feature-space) ] ;
|
||||
properties += [ convert-command-line-element $(e) :
|
||||
$(feature-space) ] ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -165,25 +171,42 @@ rule from-command-line ( command-line * )
|
||||
|
||||
# Converts one element of command line build request specification into internal
|
||||
# form. Expects all the project files to already be loaded.
|
||||
#
|
||||
local rule convert-command-line-element ( e )
|
||||
{
|
||||
local result ;
|
||||
local parts = [ regex.split $(e) "/" ] ;
|
||||
for local p in $(parts)
|
||||
while $(parts)
|
||||
{
|
||||
local p = $(parts[1]) ;
|
||||
local m = [ MATCH "([^=]*)=(.*)" : $(p) ] ;
|
||||
local lresult ;
|
||||
local feature ;
|
||||
local values ;
|
||||
if $(m)
|
||||
{
|
||||
local feature = $(m[1]) ;
|
||||
local values = [ regex.split $(m[2]) "," ] ;
|
||||
feature = $(m[1]) ;
|
||||
values = [ regex.split $(m[2]) "," ] ;
|
||||
lresult = <$(feature)>$(values) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
lresult = [ regex.split $(p) "," ] ;
|
||||
}
|
||||
|
||||
|
||||
if $(feature) && free in [ feature.attributes $(feature) ]
|
||||
{
|
||||
# If we have free feature, then the value is everything
|
||||
# until the end of the command line token. Slashes in
|
||||
# the following string are not taked to mean separation
|
||||
# of properties. Commas are also not interpreted specially.
|
||||
values = $(values:J=,) ;
|
||||
values = $(values) $(parts[2-]) ;
|
||||
values = $(values:J=/) ;
|
||||
lresult = <$(feature)>$(values) ;
|
||||
parts = ;
|
||||
}
|
||||
|
||||
if ! [ MATCH (.*-.*) : $(p) ]
|
||||
{
|
||||
# property.validate cannot handle subfeatures, so we avoid the check
|
||||
@@ -202,6 +225,8 @@ local rule convert-command-line-element ( e )
|
||||
{
|
||||
result = $(result)/$(lresult) ;
|
||||
}
|
||||
|
||||
parts = $(parts[2-]) ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
|
||||
@@ -357,7 +357,8 @@ local rule expand-subfeatures-aux (
|
||||
local subvalue = $(subvalues[1]) ; # Pop the head off of subvalues.
|
||||
subvalues = $(subvalues[2-]) ;
|
||||
|
||||
local subfeature = [ find-implied-subfeature $(feature) $(subvalue) : $(value) ] ;
|
||||
local subfeature = [ find-implied-subfeature $(feature) $(subvalue) :
|
||||
$(value) ] ;
|
||||
|
||||
# If no subfeature was found reconstitute the value string and use that.
|
||||
if ! $(subfeature)
|
||||
@@ -433,8 +434,8 @@ local rule extend-feature ( feature : values * )
|
||||
}
|
||||
if ! $($(feature).values)
|
||||
{
|
||||
# This is the first value specified for this feature,
|
||||
# take it as default value
|
||||
# This is the first value specified for this feature so make it be the
|
||||
# default.
|
||||
$(feature).default = $(values[1]) ;
|
||||
}
|
||||
$(feature).values += $(values) ;
|
||||
@@ -584,7 +585,7 @@ rule extend ( feature-or-property subfeature ? : values * )
|
||||
}
|
||||
else
|
||||
{
|
||||
# If no subfeature was specified, we didn't expect to see a
|
||||
# If no subfeature was specified, we do not expect to see a
|
||||
# value-string.
|
||||
if $(value-string)
|
||||
{
|
||||
@@ -771,7 +772,8 @@ local rule is-subfeature-of ( parent-property f )
|
||||
{
|
||||
# The feature has the form <topfeature-topvalue:subfeature>, e.g.
|
||||
# <toolset-msvc:version>.
|
||||
local feature-value = [ split-top-feature $(specific-subfeature[1]) ] ;
|
||||
local feature-value = [ split-top-feature $(specific-subfeature[1])
|
||||
] ;
|
||||
if <$(feature-value[1])>$(feature-value[2]) = $(parent-property)
|
||||
{
|
||||
return true ;
|
||||
|
||||
@@ -36,12 +36,19 @@
|
||||
# that as early as possible. Specifically, this is done after invoking each
|
||||
# generator. TODO: An example is needed to document the rationale for trying
|
||||
# extra target conversion at that point.
|
||||
#
|
||||
# In order for the system to be able to use a specific generator instance 'when
|
||||
# needed', the instance needs to be registered with the system using
|
||||
# generators.register() or one of its related rules. Unregistered generators may
|
||||
# only be run explicitly and will not be considered by Boost.Build when when
|
||||
# converting between given target types.
|
||||
|
||||
import "class" : new ;
|
||||
import errors ;
|
||||
import property-set ;
|
||||
import sequence ;
|
||||
import set ;
|
||||
import type ;
|
||||
import utility ;
|
||||
import virtual-target ;
|
||||
|
||||
@@ -52,8 +59,76 @@ if "--debug-generators" in [ modules.peek : ARGV ]
|
||||
}
|
||||
|
||||
|
||||
# Updated cached viable source target type information as needed after a new
|
||||
# target type gets defined. This is needed because if a target type is a viable
|
||||
# source target type for some generator then all of the target type's derived
|
||||
# target types should automatically be considered as viable source target types
|
||||
# for the same generator as well. Does nothing if a non-derived target type is
|
||||
# passed to it.
|
||||
#
|
||||
rule update-cached-information-with-a-new-type ( type )
|
||||
{
|
||||
local base-type = [ type.base $(type) ] ;
|
||||
if $(base-type)
|
||||
{
|
||||
for local g in $(.vstg-cached-generators)
|
||||
{
|
||||
if $(base-type) in $(.vstg.$(g))
|
||||
{
|
||||
.vstg.$(g) += $(type) ;
|
||||
}
|
||||
}
|
||||
|
||||
for local t in $(.vst-cached-types)
|
||||
{
|
||||
if $(base-type) in $(.vst.$(t))
|
||||
{
|
||||
.vst.$(t) += $(type) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Clears cached viable source target type information except for target types
|
||||
# and generators with all source types listed as viable. Should be called when
|
||||
# something invalidates those cached values by possibly causing some new source
|
||||
# types to become viable.
|
||||
#
|
||||
local rule invalidate-extendable-viable-source-target-type-cache ( )
|
||||
{
|
||||
local generators-with-cached-source-types = $(.vstg-cached-generators) ;
|
||||
.vstg-cached-generators = ;
|
||||
for local g in $(generators-with-cached-source-types)
|
||||
{
|
||||
if $(.vstg.$(g)) = *
|
||||
{
|
||||
.vstg-cached-generators += $(g) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
.vstg.$(g) = ;
|
||||
}
|
||||
}
|
||||
|
||||
local types-with-cached-source-types = $(.vst-cached-types) ;
|
||||
.vst-cached-types = ;
|
||||
for local t in $(types-with-cached-source-types)
|
||||
{
|
||||
if $(.vst.$(t)) = *
|
||||
{
|
||||
.vst-cached-types += $(t) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
.vst.$(t) = ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Outputs a debug message if generators debugging is on. Each element of
|
||||
# 'message' is checked to see if it's class instance. If so, instead of the
|
||||
# 'message' is checked to see if it is a class instance. If so, instead of the
|
||||
# value, the result of 'str' call is output.
|
||||
#
|
||||
local rule generators.dout ( message * )
|
||||
@@ -83,18 +158,8 @@ local rule decrease-indent ( )
|
||||
}
|
||||
|
||||
|
||||
# Takes a vector of 'virtual-target' instances and makes a normalized
|
||||
# representation, which is the same for given set of targets, regardless of
|
||||
# their order.
|
||||
# Models a generator.
|
||||
#
|
||||
rule normalize-target-list ( targets )
|
||||
{
|
||||
local v = [ $(targets).get ] ;
|
||||
$(targets).set $(v[1]) [ sequence.insertion-sort $(v[2-]) : utility.less ] ;
|
||||
}
|
||||
|
||||
|
||||
# Creates a generator
|
||||
class generator
|
||||
{
|
||||
import generators : indent increase-indent decrease-indent generators.dout ;
|
||||
@@ -108,7 +173,8 @@ class generator
|
||||
import "class" : new ;
|
||||
import property ;
|
||||
|
||||
EXPORT class@generator : indent increase-indent decrease-indent generators.dout ;
|
||||
EXPORT class@generator : indent increase-indent decrease-indent
|
||||
generators.dout ;
|
||||
|
||||
rule __init__ (
|
||||
id # Identifies the generator - should be name
|
||||
@@ -146,9 +212,9 @@ class generator
|
||||
{
|
||||
# Create three parallel lists: one with the list of target types,
|
||||
# and two other with prefixes and postfixes to be added to target
|
||||
# name. We use parallel lists for prefix and postfix (as opposed
|
||||
# to mapping), because given target type might occur several times,
|
||||
# for example "H H(%_symbols)".
|
||||
# name. We use parallel lists for prefix and postfix (as opposed to
|
||||
# mapping), because given target type might occur several times, for
|
||||
# example "H H(%_symbols)".
|
||||
local m = [ MATCH ([^\\(]*)(\\((.*)%(.*)\\))? : $(e) ] ;
|
||||
self.target-types += $(m[1]) ;
|
||||
self.name-prefix += $(m[3]:E="") ;
|
||||
@@ -160,7 +226,7 @@ class generator
|
||||
sequence.transform type.validate : $(self.target-types) ;
|
||||
}
|
||||
|
||||
############## End of constructor #################
|
||||
################# End of constructor #################
|
||||
|
||||
rule id ( )
|
||||
{
|
||||
@@ -175,8 +241,8 @@ class generator
|
||||
}
|
||||
|
||||
# Returns the list of target types that this generator produces. It is
|
||||
# assumed to be always the same -- i.e. it cannot change depending list of
|
||||
# sources.
|
||||
# assumed to be always the same -- i.e. it can not change depending on some
|
||||
# provided list of sources.
|
||||
#
|
||||
rule target-types ( )
|
||||
{
|
||||
@@ -187,6 +253,7 @@ class generator
|
||||
# set must be present in build properties if this generator is to be used.
|
||||
# If result has grist-only element, that build properties must include some
|
||||
# value of that feature.
|
||||
#
|
||||
# XXX: remove this method?
|
||||
#
|
||||
rule requirements ( )
|
||||
@@ -199,7 +266,7 @@ class generator
|
||||
#
|
||||
rule match-rank ( property-set-to-match )
|
||||
{
|
||||
# See if generator's requirements are satisfied by 'properties'. Treat a
|
||||
# See if generator requirements are satisfied by 'properties'. Treat a
|
||||
# feature name in requirements (i.e. grist-only element), as matching
|
||||
# any value of the feature.
|
||||
local all-requirements = [ requirements ] ;
|
||||
@@ -218,8 +285,8 @@ class generator
|
||||
}
|
||||
|
||||
local properties-to-match = [ $(property-set-to-match).raw ] ;
|
||||
if $(property-requirements) in $(properties-to-match)
|
||||
&& $(feature-requirements) in $(properties-to-match:G)
|
||||
if $(property-requirements) in $(properties-to-match) &&
|
||||
$(feature-requirements) in $(properties-to-match:G)
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
@@ -235,14 +302,12 @@ class generator
|
||||
#
|
||||
rule clone ( new-id : new-toolset-properties + )
|
||||
{
|
||||
return [ new $(__class__) $(new-id) $(self.composing)
|
||||
: $(self.source-types)
|
||||
: $(self.target-types-and-names)
|
||||
# Note: this does not remove any subfeatures of <toolset>
|
||||
# which might cause problems
|
||||
: [ property.change $(self.requirements) : <toolset> ]
|
||||
$(new-toolset-properties)
|
||||
] ;
|
||||
return [ new $(__class__) $(new-id) $(self.composing) :
|
||||
$(self.source-types) : $(self.target-types-and-names) :
|
||||
# Note: this does not remove any subfeatures of <toolset> which
|
||||
# might cause problems.
|
||||
[ property.change $(self.requirements) : <toolset> ]
|
||||
$(new-toolset-properties) ] ;
|
||||
}
|
||||
|
||||
# Creates another generator that is the same as $(self), except that if
|
||||
@@ -265,23 +330,24 @@ class generator
|
||||
}
|
||||
}
|
||||
|
||||
return [ new $(__class__) $(self.id) $(self.composing)
|
||||
: $(self.source-types)
|
||||
: $(target-types)
|
||||
: $(self.requirements)
|
||||
] ;
|
||||
return [ new $(__class__) $(self.id) $(self.composing) :
|
||||
$(self.source-types) : $(target-types) : $(self.requirements) ] ;
|
||||
}
|
||||
|
||||
# Tries to invoke this generator on the given sources. Returns a list of
|
||||
# generated targets (instances of 'virtual-target'). Returning nothing from
|
||||
# run indicates that the generator was unable to create the target.
|
||||
# generated targets (instances of 'virtual-target') and optionally a set of
|
||||
# properties to be added to the usage-requirements for all the generated
|
||||
# targets. Returning nothing from run indicates that the generator was
|
||||
# unable to create the target.
|
||||
#
|
||||
rule run ( project # Project for which the targets are generated
|
||||
name ? # Determines the name of 'name' attribute for all
|
||||
# generated targets. See 'generated-targets' method.
|
||||
: property-set # Desired properties for generated targets.
|
||||
: sources + # Source targets.
|
||||
)
|
||||
rule run
|
||||
(
|
||||
project # Project for which the targets are generated.
|
||||
name ? # Used when determining the 'name' attribute for all
|
||||
# generated targets. See the 'generated-targets' method.
|
||||
: property-set # Desired properties for generated targets.
|
||||
: sources + # Source targets.
|
||||
)
|
||||
{
|
||||
generators.dout [ indent ] " ** generator" $(self.id) ;
|
||||
generators.dout [ indent ] " composing:" $(self.composing) ;
|
||||
@@ -291,7 +357,7 @@ class generator
|
||||
errors.error "Unsupported source/source-type combination" ;
|
||||
}
|
||||
|
||||
# We don't run composing generators if no name is specified. The reason
|
||||
# We do not run composing generators if no name is specified. The reason
|
||||
# is that composing generator combines several targets, which can have
|
||||
# different names, and it cannot decide which name to give for produced
|
||||
# target. Therefore, the name must be passed.
|
||||
@@ -300,7 +366,7 @@ class generator
|
||||
# the top-level of a transformation graph, or if their name is passed
|
||||
# explicitly. Thus, we dissallow composing generators in the middle. For
|
||||
# example, the transformation CPP -> OBJ -> STATIC_LIB -> RSP -> EXE
|
||||
# won't be allowed (the OBJ -> STATIC_LIB generator is composing)
|
||||
# will not be allowed as the OBJ -> STATIC_LIB generator is composing.
|
||||
if ! $(self.composing) || $(name)
|
||||
{
|
||||
run-really $(project) $(name) : $(property-set) : $(sources) ;
|
||||
@@ -311,7 +377,7 @@ class generator
|
||||
{
|
||||
# Targets that this generator will consume directly.
|
||||
local consumed = ;
|
||||
# Targets that can't be consumed and will be returned as-is.
|
||||
# Targets that can not be consumed and will be returned as-is.
|
||||
local bypassed = ;
|
||||
|
||||
if $(self.composing)
|
||||
@@ -328,8 +394,8 @@ class generator
|
||||
local result ;
|
||||
if $(consumed)
|
||||
{
|
||||
result = [ construct-result $(consumed) : $(project) $(name)
|
||||
: $(property-set) ] ;
|
||||
result = [ construct-result $(consumed) : $(project) $(name) :
|
||||
$(property-set) ] ;
|
||||
}
|
||||
|
||||
if $(result)
|
||||
@@ -346,14 +412,20 @@ class generator
|
||||
|
||||
# Constructs the dependency graph to be returned by this generator.
|
||||
#
|
||||
rule construct-result (
|
||||
consumed + # Already prepared list of consumable targets
|
||||
# If generator requires several source files will contain
|
||||
# exactly len $(self.source-types) targets with matching
|
||||
# types. Otherwise, might contain several targets with the
|
||||
# type of $(self.source-types[1]).
|
||||
rule construct-result
|
||||
(
|
||||
consumed + # Already prepared list of consumable targets.
|
||||
# Composing generators may receive multiple sources
|
||||
# all of which will have types matching those in
|
||||
# $(self.source-types). Non-composing generators with
|
||||
# multiple $(self.source-types) will receive exactly
|
||||
# len $(self.source-types) sources with types matching
|
||||
# those in $(self.source-types). And non-composing
|
||||
# generators with only a single source type may
|
||||
# receive multiple sources with all of them of the
|
||||
# type listed in $(self.source-types).
|
||||
: project name ?
|
||||
: property-set # Properties to be used for all actions create here.
|
||||
: property-set # Properties to be used for all actions created here.
|
||||
)
|
||||
{
|
||||
local result ;
|
||||
@@ -363,16 +435,14 @@ class generator
|
||||
{
|
||||
for local r in $(consumed)
|
||||
{
|
||||
result += [ generated-targets $(r) : $(property-set) : $(project) $(name) ] ; #(targets) ;
|
||||
result += [ generated-targets $(r) : $(property-set) :
|
||||
$(project) $(name) ] ;
|
||||
}
|
||||
}
|
||||
else
|
||||
else if $(consumed)
|
||||
{
|
||||
if $(consumed)
|
||||
{
|
||||
result += [ generated-targets $(consumed) : $(property-set)
|
||||
: $(project) $(name) ] ;
|
||||
}
|
||||
result += [ generated-targets $(consumed) : $(property-set) :
|
||||
$(project) $(name) ] ;
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -383,11 +453,11 @@ class generator
|
||||
{
|
||||
# The simple case if when a name of source has single dot. Then, we take
|
||||
# the part before dot. Several dots can be caused by:
|
||||
# - Using source file like a.host.cpp
|
||||
# - A type which suffix has a dot. Say, we can type 'host_cpp' with
|
||||
# - using source file like a.host.cpp, or
|
||||
# - a type whose suffix has a dot. Say, we can type 'host_cpp' with
|
||||
# extension 'host.cpp'.
|
||||
# In the first case, we want to take the part up to the last dot. In the
|
||||
# second case -- no sure, but for now take the part up to the last dot
|
||||
# second case -- not sure, but for now take the part up to the last dot
|
||||
# too.
|
||||
name = [ utility.basename [ $(sources[1]).name ] ] ;
|
||||
|
||||
@@ -410,11 +480,11 @@ class generator
|
||||
# will be the list of virtual-target, which has the same length as the
|
||||
# 'target-types' attribute and with corresponding types.
|
||||
#
|
||||
# When 'name' is empty, all source targets must have the same value of the
|
||||
# 'name' attribute, which will be used instead of the 'name' argument.
|
||||
# When 'name' is empty, all source targets must have the same 'name'
|
||||
# attribute value, which will be used instead of the 'name' argument.
|
||||
#
|
||||
# The value of 'name' attribute for each generated target will be equal to
|
||||
# the 'name' parameter if there's no name pattern for this type. Otherwise,
|
||||
# The 'name' attribute value for each generated target will be equal to
|
||||
# the 'name' parameter if there is no name pattern for this type. Otherwise,
|
||||
# the '%' symbol in the name pattern will be replaced with the 'name'
|
||||
# parameter to obtain the 'name' attribute.
|
||||
#
|
||||
@@ -424,8 +494,8 @@ class generator
|
||||
# determines the basename of a file.
|
||||
#
|
||||
# Note that this pattern mechanism has nothing to do with implicit patterns
|
||||
# in make. It is a way to produce target which name is different for name of
|
||||
# source.
|
||||
# in make. It is a way to produce a target whose name is different than the
|
||||
# name of its source.
|
||||
#
|
||||
rule generated-targets ( sources + : property-set : project name ? )
|
||||
{
|
||||
@@ -434,7 +504,7 @@ class generator
|
||||
name = [ determine-output-name $(sources) ] ;
|
||||
}
|
||||
|
||||
# Assign an action for each target
|
||||
# Assign an action for each target.
|
||||
local action = [ action-class ] ;
|
||||
local a = [ class.new $(action) $(sources) : $(self.id) :
|
||||
$(property-set) ] ;
|
||||
@@ -456,30 +526,33 @@ class generator
|
||||
return [ sequence.transform virtual-target.register : $(targets) ] ;
|
||||
}
|
||||
|
||||
# Attempts to convert 'source' to the types that this generator can handle.
|
||||
# The intention is to produce the set of targets can should be used when
|
||||
# generator is run.
|
||||
# Attempts to convert 'sources' to targets of types that this generator can
|
||||
# handle. The intention is to produce the set of targets that can be used
|
||||
# when the generator is run.
|
||||
#
|
||||
rule convert-to-consumable-types ( project name ? :
|
||||
property-set : sources +
|
||||
: only-one ? # Convert 'source' to only one of the source types. If
|
||||
# there's more that one possibility, report an error.
|
||||
: consumed-var # Name of the variable which recieves all targets which
|
||||
# can be consumed.
|
||||
bypassed-var # Name of the variable which recieves all targets which
|
||||
# cannot be consumed
|
||||
rule convert-to-consumable-types
|
||||
(
|
||||
project name ?
|
||||
: property-set
|
||||
: sources +
|
||||
: only-one ? # Convert 'source' to only one of the source types. If
|
||||
# there is more that one possibility, report an error.
|
||||
: consumed-var # Name of the variable which receives all targets which
|
||||
# can be consumed.
|
||||
bypassed-var # Name of the variable which receives all targets which
|
||||
# can not be consumed.
|
||||
)
|
||||
{
|
||||
# We're likely to be passed 'consumed' and 'bypassed' var names. Use "_"
|
||||
# to avoid name conflicts.
|
||||
# We are likely to be passed 'consumed' and 'bypassed' var names. Use
|
||||
# '_' to avoid name conflicts.
|
||||
local _consumed ;
|
||||
local _bypassed ;
|
||||
local missing-types ;
|
||||
|
||||
if $(sources[2])
|
||||
{
|
||||
# Don't know how to handle several sources yet. Just try to pass the
|
||||
# request to other generator
|
||||
# Do not know how to handle several sources yet. Just try to pass
|
||||
# the request to other generator.
|
||||
missing-types = $(self.source-types) ;
|
||||
}
|
||||
else
|
||||
@@ -502,11 +575,11 @@ class generator
|
||||
if $(missing-types)
|
||||
{
|
||||
local transformed = [ generators.construct-types $(project) $(name)
|
||||
: $(missing-types) : $(property-set) : $(sources) ] ;
|
||||
: $(missing-types) : $(property-set) : $(sources) ] ;
|
||||
|
||||
# Add targets of right type to 'consumed'. Add others to 'bypassed'.
|
||||
# The 'generators.construct' rule has done its best to convert
|
||||
# everything to the required type. There's no need to rerun it on
|
||||
# everything to the required type. There is no need to rerun it on
|
||||
# targets of different types.
|
||||
|
||||
# NOTE: ignoring usage requirements.
|
||||
@@ -533,12 +606,12 @@ class generator
|
||||
# from Y, X_2 will be added to 'bypassed'. Likewise, when creating X_2
|
||||
# from Y, X_1 will be added to 'bypassed', but they are also in
|
||||
# 'consumed'. We have to remove them from bypassed, so that generators
|
||||
# up the call stack don't try to convert them.
|
||||
# up the call stack do not try to convert them.
|
||||
|
||||
# In this particular case, X_1 instance in 'consumed' and X_1 instance
|
||||
# in 'bypassed' will be the same: because they have the same source and
|
||||
# action name, and 'virtual-target.register' won't allow two different
|
||||
# instances. Therefore, it's OK to use 'set.difference'.
|
||||
# action name, and 'virtual-target.register' will not allow two
|
||||
# different instances. Therefore, it is OK to use 'set.difference'.
|
||||
|
||||
_bypassed = [ set.difference $(_bypassed) : $(_consumed) ] ;
|
||||
|
||||
@@ -546,10 +619,11 @@ class generator
|
||||
$(bypassed-var) += $(_bypassed) ;
|
||||
}
|
||||
|
||||
# Converts several files to consumable types.
|
||||
# Converts several files to consumable types. Called for composing
|
||||
# generators only.
|
||||
#
|
||||
rule convert-multiple-sources-to-consumable-types
|
||||
( project : property-set : sources * : consumed-var bypassed-var )
|
||||
rule convert-multiple-sources-to-consumable-types ( project : property-set :
|
||||
sources * : consumed-var bypassed-var )
|
||||
{
|
||||
# We process each source one-by-one, trying to convert it to a usable
|
||||
# type.
|
||||
@@ -558,8 +632,8 @@ class generator
|
||||
local _c ;
|
||||
local _b ;
|
||||
# TODO: need to check for failure on each source.
|
||||
convert-to-consumable-types $(project) : $(property-set)
|
||||
: $(source) : true : _c _b ;
|
||||
convert-to-consumable-types $(project) : $(property-set) : $(source)
|
||||
: true : _c _b ;
|
||||
if ! $(_c)
|
||||
{
|
||||
generators.dout [ indent ] " failed to convert " $(source) ;
|
||||
@@ -579,15 +653,15 @@ class generator
|
||||
|
||||
for local st in $(source-types)
|
||||
{
|
||||
# The 'source' if of right type already)
|
||||
if $(real-source-type) = $(st) ||
|
||||
[ type.is-derived $(real-source-type) $(st) ]
|
||||
# The 'source' if of the right type already.
|
||||
if $(real-source-type) = $(st) || [ type.is-derived
|
||||
$(real-source-type) $(st) ]
|
||||
{
|
||||
$(consumed-var) += $(source) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
$(missing-types-var) += $(st) ;
|
||||
$(missing-types-var) += $(st) ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -602,33 +676,28 @@ class generator
|
||||
}
|
||||
|
||||
|
||||
.generators = ;
|
||||
|
||||
|
||||
# Registers a new generator instance 'g'.
|
||||
#
|
||||
rule register ( g )
|
||||
{
|
||||
.generators += $(g) ;
|
||||
|
||||
# A generator can produce several targets of the same type. We want unique
|
||||
# occurence of that generator in .generators.$(t) in that case, otherwise,
|
||||
# it will be tried twice and we'll get false ambiguity.
|
||||
# occurrence of that generator in .generators.$(t) in that case, otherwise,
|
||||
# it will be tried twice and we will get a false ambiguity.
|
||||
for local t in [ sequence.unique [ $(g).target-types ] ]
|
||||
{
|
||||
.generators.$(t) += $(g) ;
|
||||
}
|
||||
|
||||
# Update the set of generators for toolset
|
||||
# Update the set of generators for toolset.
|
||||
|
||||
# TODO: should we check that generator with this id is not already
|
||||
# registered. For example, the fop.jam module intentionally declared two
|
||||
# generators with the same id, so such check will break it.
|
||||
local id = [ $(g).id ] ;
|
||||
|
||||
# Some generators have multiple periods in their name, so the normal
|
||||
# $(id:S=) won't generate the right toolset name. E.g. if id =
|
||||
# = gcc.compile.c++, then .generators-for-toolset.$(id:S=) will append to
|
||||
# Some generators have multiple periods in their name, so a simple $(id:S=)
|
||||
# will not generate the right toolset name. E.g. if id = gcc.compile.c++,
|
||||
# then .generators-for-toolset.$(id:S=) will append to
|
||||
# .generators-for-toolset.gcc.compile, which is a separate value from
|
||||
# .generators-for-toolset.gcc. Correcting this makes generator inheritance
|
||||
# work properly. See also inherit-generators in the toolset module.
|
||||
@@ -638,35 +707,60 @@ rule register ( g )
|
||||
base = $(base:B) ;
|
||||
}
|
||||
.generators-for-toolset.$(base) += $(g) ;
|
||||
|
||||
|
||||
# After adding a new generator that can construct new target types, we need
|
||||
# to clear the related cached viable source target type information for
|
||||
# constructing a specific target type or using a specific generator. Cached
|
||||
# viable source target type lists affected by this are those containing any
|
||||
# of the target types constructed by the new generator or any of their base
|
||||
# target types.
|
||||
#
|
||||
# A more advanced alternative to clearing that cached viable source target
|
||||
# type information would be to expand it with additional source types or
|
||||
# even better - mark it as needing to be expanded on next use.
|
||||
#
|
||||
# Also see the http://thread.gmane.org/gmane.comp.lib.boost.build/19077
|
||||
# mailing list thread for an even more advanced idea of how we could convert
|
||||
# Boost Build's Jamfile processing, target selection and generator selection
|
||||
# into separate steps which would prevent these caches from ever being
|
||||
# invalidated.
|
||||
#
|
||||
# For now we just clear all the cached viable source target type information
|
||||
# that does not simply state 'all types' and may implement a more detailed
|
||||
# algorithm later on if it becomes needed.
|
||||
|
||||
invalidate-extendable-viable-source-target-type-cache ;
|
||||
}
|
||||
|
||||
|
||||
# Creates new instance of the 'generator' class and registers it. Returns the
|
||||
# created instance. Rationale: the instance is returned so that it's possible to
|
||||
# first register a generator and then call the 'run' method on that generator,
|
||||
# bypassing all generator selection.
|
||||
# Creates a new non-composing 'generator' class instance and registers it.
|
||||
# Returns the created instance. Rationale: the instance is returned so that it
|
||||
# is possible to first register a generator and then call its 'run' method,
|
||||
# bypassing the whole generator selection process.
|
||||
#
|
||||
rule register-standard ( id : source-types * : target-types + : requirements * )
|
||||
{
|
||||
local g = [ new generator $(id) : $(source-types) : $(target-types)
|
||||
: $(requirements) ] ;
|
||||
local g = [ new generator $(id) : $(source-types) : $(target-types) :
|
||||
$(requirements) ] ;
|
||||
register $(g) ;
|
||||
return $(g) ;
|
||||
}
|
||||
|
||||
|
||||
# Creates new instance of the 'composing-generator' class and registers it.
|
||||
# Creates a new composing 'generator' class instance and registers it.
|
||||
#
|
||||
rule register-composing ( id : source-types * : target-types + : requirements * )
|
||||
rule register-composing ( id : source-types * : target-types + : requirements *
|
||||
)
|
||||
{
|
||||
local g = [ new generator $(id) true : $(source-types) : $(target-types)
|
||||
: $(requirements) ] ;
|
||||
local g = [ new generator $(id) true : $(source-types) : $(target-types) :
|
||||
$(requirements) ] ;
|
||||
register $(g) ;
|
||||
return $(g) ;
|
||||
}
|
||||
|
||||
|
||||
# Returns all generators which belong to 'toolset', i.e. whose ids are
|
||||
# Returns all generators belonging to the given 'toolset', i.e. whose ids are
|
||||
# '$(toolset).<something>'.
|
||||
#
|
||||
rule generators-for-toolset ( toolset )
|
||||
@@ -677,11 +771,11 @@ rule generators-for-toolset ( toolset )
|
||||
|
||||
# Make generator 'overrider-id' be preferred to 'overridee-id'. If, when
|
||||
# searching for generators that could produce a target of a certain type, both
|
||||
# those generators are amoung viable generators, the overridden generator is
|
||||
# those generators are among viable generators, the overridden generator is
|
||||
# immediately discarded.
|
||||
#
|
||||
# The overridden generators are discarded immediately after computing the list
|
||||
# of viable generators, before running any of them.
|
||||
# of viable generators but before running any of them.
|
||||
#
|
||||
rule override ( overrider-id : overridee-id )
|
||||
{
|
||||
@@ -689,30 +783,34 @@ rule override ( overrider-id : overridee-id )
|
||||
}
|
||||
|
||||
|
||||
# Set if results of the current generators search are going to be cached. This
|
||||
# means no futher attempts to cache generators search should be made.
|
||||
.caching = ;
|
||||
|
||||
|
||||
# Returns a list of source type which can possibly be converted to 'target-type'
|
||||
# by some chain of generator invocation.
|
||||
#
|
||||
# More formally, takes all generators for 'target-type' and returns union of
|
||||
# source types for those generators and result of calling itself recirsively on
|
||||
# More formally, takes all generators for 'target-type' and returns a union of
|
||||
# source types for those generators and result of calling itself recursively on
|
||||
# source types.
|
||||
#
|
||||
# Returns '*' in case any type should be considered a viable source type for the
|
||||
# given type.
|
||||
#
|
||||
local rule viable-source-types-real ( target-type )
|
||||
{
|
||||
local generators ;
|
||||
|
||||
local t = [ type.all-bases $(target-type) ] ;
|
||||
|
||||
local result ;
|
||||
# 't' is the list of types which have not yet been processed.
|
||||
|
||||
# 't0' is the initial list of target types we need to process to get a list
|
||||
# of their viable source target types. New target types will not be added to
|
||||
# this list.
|
||||
local t0 = [ type.all-bases $(target-type) ] ;
|
||||
|
||||
# 't' is the list of target types which have not yet been processed to get a
|
||||
# list of their viable source target types. This list will get expanded as
|
||||
# we locate more target types to process.
|
||||
local t = $(t0) ;
|
||||
|
||||
while $(t)
|
||||
{
|
||||
# Find all generators for current type. Unlike 'find-viable-generators'
|
||||
# we don't care about property-set.
|
||||
# Find all generators for the current type. Unlike
|
||||
# 'find-viable-generators' we do not care about the property-set.
|
||||
local generators = $(.generators.$(t[1])) ;
|
||||
t = $(t[2-]) ;
|
||||
|
||||
@@ -723,11 +821,11 @@ local rule viable-source-types-real ( target-type )
|
||||
|
||||
if ! [ $(g).source-types ]
|
||||
{
|
||||
# Empty source types -- everything can be accepted
|
||||
# Empty source types -- everything can be accepted.
|
||||
result = * ;
|
||||
# This will terminate this loop.
|
||||
generators = ;
|
||||
# This will terminate outer loop.
|
||||
# This will terminate the outer loop.
|
||||
t = ;
|
||||
}
|
||||
|
||||
@@ -735,14 +833,25 @@ local rule viable-source-types-real ( target-type )
|
||||
{
|
||||
if ! $(source-type) in $(result)
|
||||
{
|
||||
# If generator accepts 'source-type' it
|
||||
# will happily accept any type derived from it
|
||||
local all = [ type.all-derived $(source-type) ] ;
|
||||
for local n in $(all)
|
||||
# If a generator accepts a 'source-type' it will also
|
||||
# happily accept any type derived from it.
|
||||
for local n in [ type.all-derived $(source-type) ]
|
||||
{
|
||||
if ! $(n) in $(result)
|
||||
{
|
||||
t += $(n) ;
|
||||
# Here there is no point in adding target types to
|
||||
# the list of types to process in case they are or
|
||||
# have already been on that list. We optimize this
|
||||
# check by realizing that we only need to avoid the
|
||||
# original target type's base types. Other target
|
||||
# types that are or have been on the list of target
|
||||
# types to process have been added to the 'result'
|
||||
# list as well and have thus already been eliminated
|
||||
# by the previous if.
|
||||
if ! $(n) in $(t0)
|
||||
{
|
||||
t += $(n) ;
|
||||
}
|
||||
result += $(n) ;
|
||||
}
|
||||
}
|
||||
@@ -751,7 +860,7 @@ local rule viable-source-types-real ( target-type )
|
||||
}
|
||||
}
|
||||
|
||||
return [ sequence.unique $(result) ] ;
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
|
||||
@@ -762,6 +871,7 @@ rule viable-source-types ( target-type )
|
||||
local key = .vst.$(target-type) ;
|
||||
if ! $($(key))
|
||||
{
|
||||
.vst-cached-types += $(target-type) ;
|
||||
local v = [ viable-source-types-real $(target-type) ] ;
|
||||
if ! $(v)
|
||||
{
|
||||
@@ -781,15 +891,18 @@ rule viable-source-types ( target-type )
|
||||
# 'generator', has some change of being eventually used (probably after
|
||||
# conversion by other generators).
|
||||
#
|
||||
# Returns '*' in case any type should be considered a viable source type for the
|
||||
# given generator.
|
||||
#
|
||||
rule viable-source-types-for-generator-real ( generator )
|
||||
{
|
||||
local source-types = [ $(generator).source-types ] ;
|
||||
if ! $(source-types)
|
||||
{
|
||||
# If generator does not specify any source types, it might be special
|
||||
# If generator does not specify any source types, it might be a special
|
||||
# generator like builtin.lib-generator which just relays to other
|
||||
# generators. Return '*' to indicate that any source type is possibly
|
||||
# OK, since we don't know for sure.
|
||||
# OK, since we do not know for sure.
|
||||
return * ;
|
||||
}
|
||||
else
|
||||
@@ -797,15 +910,18 @@ rule viable-source-types-for-generator-real ( generator )
|
||||
local result ;
|
||||
for local s in $(source-types)
|
||||
{
|
||||
result += [ type.all-derived $(s) ]
|
||||
[ generators.viable-source-types $(s) ] ;
|
||||
local viable-sources = [ generators.viable-source-types $(s) ] ;
|
||||
if $(viable-sources) = *
|
||||
{
|
||||
result = * ;
|
||||
source-types = ; # Terminate the loop.
|
||||
}
|
||||
else
|
||||
{
|
||||
result += [ type.all-derived $(s) ] $(viable-sources) ;
|
||||
}
|
||||
}
|
||||
result = [ sequence.unique $(result) ] ;
|
||||
if * in $(result)
|
||||
{
|
||||
result = * ;
|
||||
}
|
||||
return $(result) ;
|
||||
return [ sequence.unique $(result) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -817,6 +933,7 @@ local rule viable-source-types-for-generator ( generator )
|
||||
local key = .vstg.$(generator) ;
|
||||
if ! $($(key))
|
||||
{
|
||||
.vstg-cached-generators += $(generator) ;
|
||||
local v = [ viable-source-types-for-generator-real $(generator) ] ;
|
||||
if ! $(v)
|
||||
{
|
||||
@@ -874,8 +991,9 @@ local rule try-one-generator-really ( project name ? : generator : target-type
|
||||
}
|
||||
|
||||
|
||||
# Checks if generator invocation can be pruned, because it's guaranteed to fail.
|
||||
# If so, quickly returns empty list. Otherwise, calls try-one-generator-really.
|
||||
# Checks if generator invocation can be pruned, because it is guaranteed to
|
||||
# fail. If so, quickly returns an empty list. Otherwise, calls
|
||||
# try-one-generator-really.
|
||||
#
|
||||
local rule try-one-generator ( project name ? : generator : target-type
|
||||
: property-set : sources * )
|
||||
@@ -885,21 +1003,21 @@ local rule try-one-generator ( project name ? : generator : target-type
|
||||
{
|
||||
source-types += [ $(s).type ] ;
|
||||
}
|
||||
local viable-source-types =
|
||||
[ viable-source-types-for-generator $(generator) ] ;
|
||||
local viable-source-types = [ viable-source-types-for-generator $(generator)
|
||||
] ;
|
||||
|
||||
if $(source-types) && $(viable-source-types) != * &&
|
||||
! [ set.intersection $(source-types) : $(viable-source-types) ]
|
||||
! [ set.intersection $(source-types) : $(viable-source-types) ]
|
||||
{
|
||||
local id = [ $(generator).id ] ;
|
||||
generators.dout [ indent ] " ** generator '$(id)' pruned" ;
|
||||
#generators.dout [ indent ] "source-types" '$(source-types)' ;
|
||||
#generators.dout [ indent ] "viable-source-types" '$(viable-source-types)' ;
|
||||
}
|
||||
else {
|
||||
return [ try-one-generator-really $(project) $(name)
|
||||
: $(generator)
|
||||
: $(target-type) : $(property-set) : $(sources) ] ;
|
||||
else
|
||||
{
|
||||
return [ try-one-generator-really $(project) $(name) : $(generator) :
|
||||
$(target-type) : $(property-set) : $(sources) ] ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -913,7 +1031,7 @@ rule construct-types ( project name ? : target-types + : property-set
|
||||
for local t in $(target-types)
|
||||
{
|
||||
local r = [ construct $(project) $(name) : $(t) : $(property-set) :
|
||||
$(sources) ] ;
|
||||
$(sources) ] ;
|
||||
if $(r)
|
||||
{
|
||||
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
|
||||
@@ -955,13 +1073,13 @@ local rule ensure-type ( targets * )
|
||||
# Returns generators which can be used to construct target of specified type
|
||||
# with specified properties. Uses the following algorithm:
|
||||
# - iterates over requested target-type and all its bases (in the order returned
|
||||
# by type.all-bases.
|
||||
# by type.all-bases).
|
||||
# - for each type find all generators that generate that type and whose
|
||||
# requirements are satisfied by properties.
|
||||
# - if the set of generators is not empty, returns that set.
|
||||
#
|
||||
# Note: this algorithm explicitly ignores generators for base classes if there's
|
||||
# at least one generator for the requested target-type.
|
||||
# Note: this algorithm explicitly ignores generators for base classes if there
|
||||
# is at least one generator for the requested target-type.
|
||||
#
|
||||
local rule find-viable-generators-aux ( target-type : property-set )
|
||||
{
|
||||
@@ -988,11 +1106,11 @@ local rule find-viable-generators-aux ( target-type : property-set )
|
||||
|
||||
if $(t[1]) != $(target-type)
|
||||
{
|
||||
# We're here, when no generators for target-type are found, but
|
||||
# there are some generators for a base type. We'll try to use
|
||||
# them, but they will produce targets of base type, not of
|
||||
# 'target-type'. So, we clone the generators and modify the list
|
||||
# of target types.
|
||||
# We are here because there were no generators found for
|
||||
# target-type but there are some generators for its base type.
|
||||
# We will try to use them, but they will produce targets of
|
||||
# base type, not of 'target-type'. So, we clone the generators
|
||||
# and modify the list of target types.
|
||||
local generators2 ;
|
||||
for local g in $(generators)
|
||||
{
|
||||
@@ -1001,8 +1119,8 @@ local rule find-viable-generators-aux ( target-type : property-set )
|
||||
# should work. That list is only used when inheriting a
|
||||
# toolset, which should have been done before running
|
||||
# generators.
|
||||
generators2 += [
|
||||
$(g).clone-and-change-target-type $(t[1]) : $(target-type) ] ;
|
||||
generators2 += [ $(g).clone-and-change-target-type $(t[1]) :
|
||||
$(target-type) ] ;
|
||||
generators.register $(generators2[-1]) ;
|
||||
}
|
||||
generators = $(generators2) ;
|
||||
@@ -1059,7 +1177,7 @@ rule find-viable-generators ( target-type : property-set )
|
||||
|
||||
# Generators which override 'all'.
|
||||
local all-overrides ;
|
||||
# Generators which are overriden
|
||||
# Generators which are overriden.
|
||||
local overriden-ids ;
|
||||
for local g in $(viable-generators)
|
||||
{
|
||||
@@ -1094,10 +1212,11 @@ rule find-viable-generators ( target-type : property-set )
|
||||
# Attempts to construct a target by finding viable generators, running them and
|
||||
# selecting the dependency graph.
|
||||
#
|
||||
local rule construct-really (
|
||||
project name ? : target-type : property-set : sources * )
|
||||
local rule construct-really ( project name ? : target-type : property-set :
|
||||
sources * )
|
||||
{
|
||||
viable-generators = [ find-viable-generators $(target-type) : $(property-set) ] ;
|
||||
viable-generators = [ find-viable-generators $(target-type) :
|
||||
$(property-set) ] ;
|
||||
|
||||
generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ]
|
||||
" viable generators" ;
|
||||
@@ -1109,8 +1228,8 @@ local rule construct-really (
|
||||
# This variable will be restored on exit from this scope.
|
||||
local .active-generators = $(g) $(.active-generators) ;
|
||||
|
||||
local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type) :
|
||||
$(property-set) : $(sources) ] ;
|
||||
local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type)
|
||||
: $(property-set) : $(sources) ] ;
|
||||
|
||||
if $(r)
|
||||
{
|
||||
@@ -1152,8 +1271,8 @@ local rule construct-really (
|
||||
|
||||
|
||||
# Attempts to create a target of 'target-type' with 'properties' from 'sources'.
|
||||
# The 'sources' are treated as a collection of *possible* ingridients -- i.e. it
|
||||
# is not required to consume them all.
|
||||
# The 'sources' are treated as a collection of *possible* ingridients, i.e.
|
||||
# there is no obligation to consume them all.
|
||||
#
|
||||
# Returns a list of targets. When this invocation is first instance of
|
||||
# 'construct' in stack, returns only targets of requested 'target-type',
|
||||
@@ -1181,8 +1300,8 @@ rule construct ( project name ? : target-type : property-set * : sources * )
|
||||
generators.dout [ indent ] " properties:" [ $(property-set).raw ] ;
|
||||
}
|
||||
|
||||
local result = [ construct-really $(project) $(name)
|
||||
: $(target-type) : $(property-set) : $(sources) ] ;
|
||||
local result = [ construct-really $(project) $(name) : $(target-type) :
|
||||
$(property-set) : $(sources) ] ;
|
||||
|
||||
decrease-indent ;
|
||||
|
||||
|
||||
@@ -103,14 +103,13 @@ JAMROOT ?= project-root.jam [Jj]amroot [Jj]amroot.jam ;
|
||||
#
|
||||
rule load-parent ( location )
|
||||
{
|
||||
local found = [ path.glob-in-parents $(location) :
|
||||
$(JAMROOT) $(JAMFILE) ] ;
|
||||
local found = [ path.glob-in-parents $(location) : $(JAMROOT) $(JAMFILE) ] ;
|
||||
|
||||
if ! $(found)
|
||||
{
|
||||
ECHO "error: Could not find parent for project at '$(location)'" ;
|
||||
ECHO "error: Did not find Jamfile.jam or Jamroot.jam in any parent directory." ;
|
||||
EXIT ;
|
||||
ECHO error: Could not find parent for project at '$(location)' ;
|
||||
EXIT error: Did not find Jamfile.jam or Jamroot.jam in any parent
|
||||
directory. ;
|
||||
}
|
||||
|
||||
return [ load $(found[1]:D) ] ;
|
||||
@@ -153,8 +152,8 @@ rule find ( name : current-location )
|
||||
|
||||
if ! $(project-module)
|
||||
{
|
||||
local location = [ path.root
|
||||
[ path.make $(name) ] $(current-location) ] ;
|
||||
local location = [ path.root [ path.make $(name) ] $(current-location) ]
|
||||
;
|
||||
|
||||
# If no project is registered for the given location, try to load it.
|
||||
# First see if we have a Jamfile. If not, then see if we might have a
|
||||
@@ -220,8 +219,8 @@ rule find-jamfile (
|
||||
{
|
||||
if ! $(.parent-jamfile.$(dir))
|
||||
{
|
||||
.parent-jamfile.$(dir) =
|
||||
[ path.glob-in-parents $(dir) : $(JAMFILE) ] ;
|
||||
.parent-jamfile.$(dir) = [ path.glob-in-parents $(dir) : $(JAMFILE)
|
||||
] ;
|
||||
}
|
||||
jamfile-glob = $(.parent-jamfile.$(dir)) ;
|
||||
}
|
||||
@@ -237,7 +236,7 @@ rule find-jamfile (
|
||||
|
||||
local jamfile-to-load = $(jamfile-glob) ;
|
||||
# Multiple Jamfiles found in the same place. Warn about this and ensure we
|
||||
# use only one of them. As a temporary convenience measure, if there's
|
||||
# use only one of them. As a temporary convenience measure, if there is
|
||||
# Jamfile.v2 among found files, suppress the warning and use it.
|
||||
#
|
||||
if $(jamfile-to-load[2-])
|
||||
@@ -262,11 +261,10 @@ rule find-jamfile (
|
||||
#
|
||||
if ! $(no-errors) && ! $(jamfile-to-load)
|
||||
{
|
||||
errors.error
|
||||
"Unable to load Jamfile." :
|
||||
"Could not find a Jamfile in directory '$(dir)'". :
|
||||
"Attempted to find it with pattern '"$(JAMFILE:J=" ")"'." :
|
||||
"Please consult the documentation at 'http://www.boost.org'." ;
|
||||
errors.error Unable to load Jamfile.
|
||||
: Could not find a Jamfile in directory '$(dir)'.
|
||||
: Attempted to find it with pattern '"$(JAMFILE:J=" ")"'.
|
||||
: Please consult the documentation at 'http://www.boost.org'. ;
|
||||
}
|
||||
|
||||
return $(jamfile-to-load) ;
|
||||
@@ -319,13 +317,12 @@ local rule load-jamfile (
|
||||
# Now do some checks.
|
||||
if $(.current-project) != $(saved-project)
|
||||
{
|
||||
errors.error "The value of the .current-project variable"
|
||||
: "has magically changed after loading a Jamfile."
|
||||
: "This means some of the targets might be defined in the wrong project."
|
||||
: "after loading" $(jamfile-module)
|
||||
: "expected value" $(saved-project)
|
||||
: "actual value" $(.current-project)
|
||||
;
|
||||
errors.error "The value of the .current-project variable has magically"
|
||||
: "changed after loading a Jamfile. This means some of the targets"
|
||||
: "might be defined in the wrong project."
|
||||
: "after loading" $(jamfile-module)
|
||||
: "expected value" $(saved-project)
|
||||
: "actual value" $(.current-project) ;
|
||||
}
|
||||
|
||||
if $(.global-build-dir)
|
||||
@@ -578,10 +575,8 @@ class project-attributes
|
||||
|
||||
if $(result[1]) = "@error"
|
||||
{
|
||||
errors.error
|
||||
"Requirements for project at '$(self.location)'"
|
||||
"conflict with parent's." :
|
||||
"Explanation: " $(result[2-]) ;
|
||||
errors.error Requirements for project at '$(self.location)'
|
||||
conflict with parent's. : Explanation: $(result[2-]) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -601,7 +596,8 @@ class project-attributes
|
||||
local non-free = [ property.remove free : $(unconditional) ] ;
|
||||
if $(non-free)
|
||||
{
|
||||
errors.error "usage-requirements" $(specification) "have non-free properties" $(non-free) ;
|
||||
errors.error usage-requirements $(specification) have non-free
|
||||
properties $(non-free) ;
|
||||
}
|
||||
local t = [ property.translate-paths $(specification)
|
||||
: $(self.location) ] ;
|
||||
@@ -624,8 +620,8 @@ class project-attributes
|
||||
self.source-location = ;
|
||||
for local src-path in $(specification)
|
||||
{
|
||||
self.source-location += [ path.root
|
||||
[ path.make $(src-path) ] $(self.location) ] ;
|
||||
self.source-location += [ path.root [ path.make $(src-path) ]
|
||||
$(self.location) ] ;
|
||||
}
|
||||
}
|
||||
else if $(attribute) = "build-dir"
|
||||
@@ -633,11 +629,17 @@ class project-attributes
|
||||
self.build-dir = [ path.root
|
||||
[ path.make $(specification) ] $(self.location) ] ;
|
||||
}
|
||||
else if ! $(attribute) in "id" "default-build" "location"
|
||||
"source-location" "parent" "projects-to-build" "project-root"
|
||||
else if $(attribute) = "id"
|
||||
{
|
||||
errors.error "Invalid project attribute '$(attribute)' specified"
|
||||
"for project at '$(self.location)'" ;
|
||||
id = [ path.root $(specification) / ] ;
|
||||
project.register-id $(id) : $(self.project-module) ;
|
||||
self.id = $(id) ;
|
||||
}
|
||||
else if ! $(attribute) in "default-build" "location" "parent"
|
||||
"projects-to-build" "project-root" "source-location"
|
||||
{
|
||||
errors.error Invalid project attribute '$(attribute)' specified for
|
||||
project at '$(self.location)' ;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -738,11 +740,11 @@ rule use ( id : location )
|
||||
{
|
||||
# The project at 'location' either has no id or that id is not equal to
|
||||
# the 'id' parameter.
|
||||
if $($(id).jamfile-module)
|
||||
&& $($(id).jamfile-module) != $(project-module)
|
||||
if $($(id).jamfile-module) && ( $($(id).jamfile-module) !=
|
||||
$(project-module) )
|
||||
{
|
||||
errors.user-error
|
||||
"Attempt to redeclare already existing project id '$(id)'" ;
|
||||
errors.user-error Attempt to redeclare already existing project id
|
||||
'$(id)' ;
|
||||
}
|
||||
$(id).jamfile-module = $(project-module) ;
|
||||
}
|
||||
@@ -777,12 +779,13 @@ rule extension ( id : options * : * )
|
||||
|
||||
# Create the project data, and bring in the project rules into the
|
||||
# module.
|
||||
project.initialize $(__name__) :
|
||||
[ path.join [ project.attribute $(root-project) location ] ext $(1:L) ] ;
|
||||
project.initialize $(__name__) : [ path.join [ project.attribute
|
||||
$(root-project) location ] ext $(1:L) ] ;
|
||||
|
||||
# Create the project itself, i.e. the attributes. All extensions are
|
||||
# created in the "/ext" project space.
|
||||
project /ext/$(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
||||
project /ext/$(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) :
|
||||
$(9) ;
|
||||
local attributes = [ project.attributes $(__name__) ] ;
|
||||
|
||||
# Inherit from the root project of whomever is defining us.
|
||||
@@ -797,12 +800,12 @@ rule glob-internal ( project : wildcards + : excludes * : rule-name )
|
||||
local location = [ $(project).get source-location ] ;
|
||||
|
||||
local result ;
|
||||
local paths = [ path.$(rule-name) $(location)
|
||||
: [ sequence.transform path.make : $(wildcards) ]
|
||||
: [ sequence.transform path.make : $(excludes) ] ] ;
|
||||
local paths = [ path.$(rule-name) $(location) :
|
||||
[ sequence.transform path.make : $(wildcards) ] :
|
||||
[ sequence.transform path.make : $(excludes) ] ] ;
|
||||
if $(wildcards:D) || $(rule-name) != glob
|
||||
{
|
||||
# The paths we've found are relative to the current directory, but the
|
||||
# The paths we have found are relative to the current directory, but the
|
||||
# names specified in the sources list are assumed to be relative to the
|
||||
# source directory of the corresponding project. So, just make the names
|
||||
# absolute.
|
||||
@@ -873,8 +876,6 @@ module project-rules
|
||||
local attributes = [ project.attributes $(__name__) ] ;
|
||||
if $(id)
|
||||
{
|
||||
id = [ path.root $(id) / ] ;
|
||||
project.register-id $(id) : $(__name__) ;
|
||||
$(attributes).set id : $(id) ;
|
||||
}
|
||||
|
||||
@@ -902,19 +903,22 @@ module project-rules
|
||||
local location = [ $(attributes).get location ] ;
|
||||
# Project with an empty location is a 'standalone' project such as
|
||||
# user-config or qt. It has no build dir. If we try to set build dir
|
||||
# for user-config, we'll then try to inherit it, with either weird
|
||||
# or wrong consequences.
|
||||
# for user-config, we shall then try to inherit it, with either
|
||||
# weird or wrong consequences.
|
||||
if $(location) && $(location) = [ $(attributes).get project-root ]
|
||||
{
|
||||
# Re-read the project id, since it might have been changed in
|
||||
# the project's attributes.
|
||||
id = [ $(attributes).get id ] ;
|
||||
# This is Jamroot.
|
||||
if $(id)
|
||||
{
|
||||
if $(explicit-build-dir)
|
||||
&& [ path.is-rooted $(explicit-build-dir) ]
|
||||
if $(explicit-build-dir) &&
|
||||
[ path.is-rooted $(explicit-build-dir) ]
|
||||
{
|
||||
errors.user-error "Absolute directory specified via 'build-dir' project attribute"
|
||||
: "Don't know how to combine that with the --build-dir option."
|
||||
;
|
||||
errors.user-error Absolute directory specified via
|
||||
'build-dir' project attribute : Do not know how to
|
||||
combine that with the --build-dir option. ;
|
||||
}
|
||||
# Strip the leading slash from id.
|
||||
local rid = [ MATCH /(.*) : $(id) ] ;
|
||||
@@ -926,11 +930,12 @@ module project-rules
|
||||
}
|
||||
else
|
||||
{
|
||||
# Not Jamroot
|
||||
# Not Jamroot.
|
||||
if $(explicit-build-dir)
|
||||
{
|
||||
errors.user-error "When --build-dir is specified, the 'build-dir' project"
|
||||
: "attribute is allowed only for top-level 'project' invocations" ;
|
||||
errors.user-error When --build-dir is specified, the
|
||||
'build-dir' project : attribute is allowed only for
|
||||
top-level 'project' invocations ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -943,7 +948,7 @@ module project-rules
|
||||
rule constant (
|
||||
name # Variable name of the constant.
|
||||
: value + # Value of the constant.
|
||||
)
|
||||
)
|
||||
{
|
||||
import project ;
|
||||
local p = [ project.target $(__name__) ] ;
|
||||
@@ -1005,10 +1010,11 @@ module project-rules
|
||||
|
||||
if $(wildcards:D) || $(excludes:D)
|
||||
{
|
||||
errors.user-error "The patterns to 'glob-tree' may not include directory" ;
|
||||
errors.user-error The patterns to 'glob-tree' may not include
|
||||
directory ;
|
||||
}
|
||||
return [ project.glob-internal [ project.current ]
|
||||
: $(wildcards) : $(excludes) : glob-tree ] ;
|
||||
return [ project.glob-internal [ project.current ] : $(wildcards) :
|
||||
$(excludes) : glob-tree ] ;
|
||||
}
|
||||
|
||||
# Calculates conditional requirements for multiple requirements at once.
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
import "class" : new ;
|
||||
import feature ;
|
||||
import path ;
|
||||
import project ;
|
||||
import property ;
|
||||
import sequence ;
|
||||
import set ;
|
||||
@@ -250,8 +252,8 @@ class property-set
|
||||
{
|
||||
if ! $(self.target-path)
|
||||
{
|
||||
# The <location> feature can be used to explicitly
|
||||
# change the location of generated targetsv
|
||||
# The <location> feature can be used to explicitly change the
|
||||
# location of generated targets.
|
||||
local l = [ get <location> ] ;
|
||||
if $(l)
|
||||
{
|
||||
@@ -260,7 +262,7 @@ class property-set
|
||||
else
|
||||
{
|
||||
local p = [ as-path ] ;
|
||||
# Really, an ugly hack. Boost regression test system requires
|
||||
# A real ugly hack. Boost regression test system requires
|
||||
# specific target paths, and it seems that changing it to handle
|
||||
# other directory layout is really hard. For that reason, we
|
||||
# teach V2 to do the things regression system requires. The
|
||||
@@ -382,6 +384,10 @@ rule create-from-user-input ( raw-properties * : jamfile-module location )
|
||||
: $(location) ] ;
|
||||
specification = [ property.translate-indirect $(specification)
|
||||
: $(jamfile-module) ] ;
|
||||
local project-id = [ project.attribute $(jamfile-module) id ] ;
|
||||
project-id ?= [ path.root $(location) [ path.pwd ] ] ;
|
||||
specification = [ property.translate-dependencies
|
||||
$(specification) : $(project-id) : $(location) ] ;
|
||||
specification =
|
||||
[ property.expand-subfeatures-in-conditions $(specification) ] ;
|
||||
specification = [ property.make $(specification) ] ;
|
||||
|
||||
@@ -469,7 +469,8 @@ rule translate-paths ( properties * : path )
|
||||
# Assumes that all feature values that start with '@' are names of rules, used
|
||||
# in 'context-module'. Such rules can be either local to the module or global.
|
||||
# Converts such values into 'indirect-rule' format (see indirect.jam), so they
|
||||
# can be called from other modules.
|
||||
# can be called from other modules. Does nothing for such values that are
|
||||
# already in the 'indirect-rule' format.
|
||||
#
|
||||
rule translate-indirect ( specification * : context-module )
|
||||
{
|
||||
@@ -482,7 +483,7 @@ rule translate-indirect ( specification * : context-module )
|
||||
local v ;
|
||||
if [ MATCH "^([^%]*)%([^%]+)$" : $(m) ]
|
||||
{
|
||||
# Rule is already in indirect format.
|
||||
# Rule is already in the 'indirect-rule' format.
|
||||
v = $(m) ;
|
||||
}
|
||||
else
|
||||
@@ -512,6 +513,50 @@ rule translate-indirect ( specification * : context-module )
|
||||
}
|
||||
|
||||
|
||||
# Binds all dependency properties in a list relative to the given project.
|
||||
# Targets with absolute paths will be left unchanged and targets which have a
|
||||
# project specified will have the path to the project interpreted relative to
|
||||
# the specified location.
|
||||
#
|
||||
rule translate-dependencies ( specification * : project-id : location )
|
||||
{
|
||||
local result ;
|
||||
for local p in $(specification)
|
||||
{
|
||||
local split = [ split-conditional $(p) ] ;
|
||||
local condition = "" ;
|
||||
if $(split)
|
||||
{
|
||||
condition = $(split[1]): ;
|
||||
p = $(split[2]) ;
|
||||
}
|
||||
if dependency in [ feature.attributes $(p:G) ]
|
||||
{
|
||||
local split-target = [ regex.match (.*)//(.*) : $(p:G=) ] ;
|
||||
if $(split-target)
|
||||
{
|
||||
local rooted = [ path.root [ path.make $(split-target[1]) ]
|
||||
[ path.root $(location) [ path.pwd ] ] ] ;
|
||||
result += $(condition)$(p:G)$(rooted)//$(split-target[2]) ;
|
||||
}
|
||||
else if [ path.is-rooted $(p:G=) ]
|
||||
{
|
||||
result += $(condition)$(p) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
result += $(condition)$(p:G)$(project-id)//$(p:G=) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += $(condition)$(p) ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
|
||||
# Class maintaining a property set -> string mapping.
|
||||
#
|
||||
class property-map
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
# each Jamfile, and can be obtained by the 'target' rule in the Jamfile's module
|
||||
# (see project.jam).
|
||||
#
|
||||
# Project targets keep a list of 'main-target' instances. A main target is
|
||||
# what the user explicitly defines in a Jamfile. It is possible to have several
|
||||
# Project targets keep a list of 'main-target' instances. A main target is what
|
||||
# the user explicitly defines in a Jamfile. It is possible to have several
|
||||
# definitions for a main target, for example to have different lists of sources
|
||||
# for different platforms. So, main targets keep a list of alternatives.
|
||||
#
|
||||
@@ -89,8 +89,8 @@ class abstract-target
|
||||
import "class" ;
|
||||
import errors ;
|
||||
|
||||
rule __init__ ( name # name of the target in Jamfile
|
||||
: project-target # the project target to which this one belongs
|
||||
rule __init__ ( name # Name of the target in Jamfile.
|
||||
: project-target # The project target to which this one belongs.
|
||||
)
|
||||
{
|
||||
# Note: it might seem that we don't need either name or project at all.
|
||||
@@ -115,7 +115,7 @@ class abstract-target
|
||||
return $(self.project) ;
|
||||
}
|
||||
|
||||
# Return the location where the target was declared
|
||||
# Return the location where the target was declared.
|
||||
rule location ( )
|
||||
{
|
||||
return $(self.location) ;
|
||||
@@ -232,10 +232,8 @@ class project-target : abstract-target
|
||||
self.build-dir = [ get build-dir ] ;
|
||||
if ! $(self.build-dir)
|
||||
{
|
||||
self.build-dir = [ path.join
|
||||
[ $(self.project).get location ]
|
||||
bin
|
||||
] ;
|
||||
self.build-dir = [ path.join [ $(self.project).get location ]
|
||||
bin ] ;
|
||||
}
|
||||
}
|
||||
return $(self.build-dir) ;
|
||||
@@ -300,8 +298,8 @@ class project-target : abstract-target
|
||||
#
|
||||
rule mark-target-as-explicit ( target-name )
|
||||
{
|
||||
# Record the name of the target, not instance, since this
|
||||
# rule is called before main target instaces are created.
|
||||
# Record the name of the target, not instance, since this rule is called
|
||||
# before main target instances are created.
|
||||
self.explicit-targets += $(target-name) ;
|
||||
}
|
||||
|
||||
@@ -311,13 +309,13 @@ class project-target : abstract-target
|
||||
{
|
||||
if $(self.built-main-targets)
|
||||
{
|
||||
errors.error "add-alternative called when main targets are already created."
|
||||
: "in project" [ full-name ] ;
|
||||
errors.error add-alternative called when main targets are already
|
||||
created. : in project [ full-name ] ;
|
||||
}
|
||||
self.alternatives += $(target-instance) ;
|
||||
}
|
||||
|
||||
# Returns a 'main-target' class instance corresponding to the 'name'.
|
||||
# Returns a 'main-target' class instance corresponding to 'name'.
|
||||
#
|
||||
rule main-target ( name )
|
||||
{
|
||||
@@ -325,11 +323,10 @@ class project-target : abstract-target
|
||||
{
|
||||
build-main-targets ;
|
||||
}
|
||||
|
||||
return $(self.main-target.$(name)) ;
|
||||
}
|
||||
|
||||
# Tells if a main target with the specified name exists.
|
||||
# Returns whether a main target with the specified name exists.
|
||||
#
|
||||
rule has-main-target ( name )
|
||||
{
|
||||
@@ -344,13 +341,12 @@ class project-target : abstract-target
|
||||
}
|
||||
}
|
||||
|
||||
# Find and return the target with the specified id, treated relative to
|
||||
# self.
|
||||
# Worker function for the find rule not implementing any caching and simply
|
||||
# returning nothing in case the target can not be found.
|
||||
#
|
||||
rule find-really ( id )
|
||||
{
|
||||
local result ;
|
||||
local project = $(self.project) ;
|
||||
local current-location = [ get location ] ;
|
||||
|
||||
local split = [ MATCH (.*)//(.*) : $(id) ] ;
|
||||
@@ -360,8 +356,8 @@ class project-target : abstract-target
|
||||
local extra-error-message ;
|
||||
if $(project-part)
|
||||
{
|
||||
# There's explicit project part in id. Looks up the project and
|
||||
# passes the request to it.
|
||||
# There is an explicitly specified project part in id. Looks up the
|
||||
# project and passes the request to it.
|
||||
local pm = [ project.find $(project-part) : $(current-location) ] ;
|
||||
if $(pm)
|
||||
{
|
||||
@@ -370,37 +366,44 @@ class project-target : abstract-target
|
||||
}
|
||||
else
|
||||
{
|
||||
extra-error-message = "error: could not find project '$(project-part)'" ;
|
||||
# TODO: This extra error message will not get displayed most
|
||||
# likely due to some buggy refactoring. Refactor the code so the
|
||||
# message gets diplayed again.
|
||||
extra-error-message = error: could not find project
|
||||
'$(project-part)' ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# Interpret target-name as name of main target. Need to do this
|
||||
# before checking for file. Consider this:
|
||||
# before checking for file. Consider the following scenario with a
|
||||
# toolset not modifying its executable's names, e.g. gcc on
|
||||
# Unix-like platforms:
|
||||
#
|
||||
# exe test : test.cpp ;
|
||||
# install s : test : <location>. ;
|
||||
#
|
||||
# After first build we'll have target 'test' in Jamfile and file
|
||||
# 'test' on the disk. We need target to override the file.
|
||||
# After the first build we would have a target named 'test' in the
|
||||
# Jamfile and a file named 'test' on the disk. We need the target to
|
||||
# override the file.
|
||||
result = [ main-target $(id) ] ;
|
||||
|
||||
|
||||
# Interpret id as an existing file reference.
|
||||
if ! $(result)
|
||||
{
|
||||
result = [ new file-reference [ path.make $(id) ] : $(project) ] ;
|
||||
|
||||
result = [ new file-reference [ path.make $(id) ] :
|
||||
$(self.project) ] ;
|
||||
if ! [ $(result).exists ]
|
||||
{
|
||||
# File actually does not exist. Reset 'target' so that an
|
||||
# error is issued.
|
||||
result = ;
|
||||
}
|
||||
}
|
||||
|
||||
# Interpret id as project-id
|
||||
# Interpret id as project-id.
|
||||
if ! $(result)
|
||||
{
|
||||
local project-module = [ project.find $(id) : $(current-location) ] ;
|
||||
local project-module = [ project.find $(id) :
|
||||
$(current-location) ] ;
|
||||
if $(project-module)
|
||||
{
|
||||
result = [ project.target $(project-module) ] ;
|
||||
@@ -411,6 +414,11 @@ class project-target : abstract-target
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
# Find and return the target with the specified id, treated relative to
|
||||
# self. Id may specify either a target or a file name with the target taking
|
||||
# priority. May report an error or return nothing if the target is not found
|
||||
# depending on the 'no-error' parameter.
|
||||
#
|
||||
rule find ( id : no-error ? )
|
||||
{
|
||||
local v = $(.id.$(id)) ;
|
||||
@@ -490,7 +498,7 @@ class project-target : abstract-target
|
||||
self.constants += $(name) ;
|
||||
}
|
||||
self.constant.$(name) = $(value) ;
|
||||
# Inject the constant in the scope of project-root module.
|
||||
# Inject the constant in the scope of the Jamroot module.
|
||||
modules.poke $(self.project-module) : $(name) : $(value) ;
|
||||
}
|
||||
|
||||
@@ -771,7 +779,7 @@ class main-target : abstract-target
|
||||
}
|
||||
|
||||
|
||||
# Abstract target which refers to a source file. This is an artificial entity
|
||||
# Abstract target refering to a source file. This is an artificial entity
|
||||
# allowing sources to a target to be represented using a list of abstract target
|
||||
# instances.
|
||||
#
|
||||
@@ -788,11 +796,8 @@ class file-reference : abstract-target
|
||||
|
||||
rule generate ( properties )
|
||||
{
|
||||
location ;
|
||||
return [ property-set.empty ]
|
||||
[ virtual-target.from-file $(self.name)
|
||||
: $(self.file-location)
|
||||
: $(self.project) ] ;
|
||||
return [ property-set.empty ] [ virtual-target.from-file $(self.name) :
|
||||
[ location ] : $(self.project) ] ;
|
||||
}
|
||||
|
||||
# Returns true if the referred file really exists.
|
||||
@@ -909,7 +914,7 @@ rule common-properties ( build-request requirements )
|
||||
|
||||
# Given a 'context' -- a set of already present properties, and 'requirements',
|
||||
# decide which extra properties should be applied to 'context'. For conditional
|
||||
# requirements, this means evaluating condition. For indirect conditional
|
||||
# requirements, this means evaluating the condition. For indirect conditional
|
||||
# requirements, this means calling a rule. Ordinary requirements are always
|
||||
# applied.
|
||||
#
|
||||
@@ -945,7 +950,7 @@ rule evaluate-requirements ( requirements : context : what )
|
||||
|
||||
local conditionals = [ $(requirements).conditional ] ;
|
||||
# The 'count' variable has one element for each conditional feature and for
|
||||
# each occurence of '<indirect-conditional>' feature. It is used as a loop
|
||||
# each occurrence of '<indirect-conditional>' feature. It is used as a loop
|
||||
# counter: for each iteration of the loop before we remove one element and
|
||||
# the property set should stabilize before we are done. It is assumed that
|
||||
# #conditionals iterations should be enough for properties to propagate
|
||||
@@ -959,9 +964,10 @@ rule evaluate-requirements ( requirements : context : what )
|
||||
local current = $(raw) ;
|
||||
|
||||
# It is assumed that ordinary conditional requirements can not add
|
||||
# <indirect-conditional> properties, and that rules referred to by
|
||||
# <indirect-conditional> properties can not add new <indirect-conditional>
|
||||
# properties. So the list of indirect conditionals does not change.
|
||||
# <conditional> properties (a.k.a. indirect conditional properties), and
|
||||
# that rules referred to by <conditional> properties can not add new
|
||||
# <conditional> properties. So the list of indirect conditionals does not
|
||||
# change.
|
||||
local indirect = [ $(requirements).get <conditional> ] ;
|
||||
indirect = [ MATCH @(.*) : $(indirect) ] ;
|
||||
|
||||
@@ -980,7 +986,7 @@ rule evaluate-requirements ( requirements : context : what )
|
||||
|
||||
if $(e) = $(added-requirements)
|
||||
{
|
||||
# If we got the same result, we've found final properties.
|
||||
# If we got the same result, we have found the final properties.
|
||||
count = ;
|
||||
ok = true ;
|
||||
}
|
||||
@@ -1009,7 +1015,7 @@ rule evaluate-requirements ( requirements : context : what )
|
||||
}
|
||||
else
|
||||
{
|
||||
errors.error "Invalid value of the 'what' parameter" ;
|
||||
errors.error "Invalid value of the 'what' parameter." ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1074,7 +1080,8 @@ class basic-target : abstract-target
|
||||
|
||||
if $(sources:G)
|
||||
{
|
||||
errors.user-error "properties found in the 'sources' parameter for" [ full-name ] ;
|
||||
errors.user-error properties found in the 'sources' parameter for
|
||||
[ full-name ] ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1198,7 +1205,8 @@ class basic-target : abstract-target
|
||||
ECHO [ targets.indent ] "Common properties: " [ $(rproperties).raw ] ;
|
||||
}
|
||||
|
||||
if $(rproperties[1]) != "@error" && [ $(rproperties).get <build> ] != no
|
||||
if ( $(rproperties[1]) != "@error" ) && ( [ $(rproperties).get
|
||||
<build> ] != no )
|
||||
{
|
||||
local source-targets ;
|
||||
local properties = [ $(rproperties).non-dependency ] ;
|
||||
@@ -1401,11 +1409,11 @@ class typed-target : basic-target
|
||||
{
|
||||
import generators ;
|
||||
|
||||
rule __init__ ( name : project : type : sources * : requirements *
|
||||
: default-build * : usage-requirements * )
|
||||
rule __init__ ( name : project : type : sources * : requirements * :
|
||||
default-build * : usage-requirements * )
|
||||
{
|
||||
basic-target.__init__ $(name) : $(project) : $(sources)
|
||||
: $(requirements) : $(default-build) : $(usage-requirements) ;
|
||||
basic-target.__init__ $(name) : $(project) : $(sources) :
|
||||
$(requirements) : $(default-build) : $(usage-requirements) ;
|
||||
|
||||
self.type = $(type) ;
|
||||
}
|
||||
@@ -1508,10 +1516,10 @@ rule main-target-usage-requirements (
|
||||
{
|
||||
local project-usage-requirements = [ $(project).get usage-requirements ] ;
|
||||
|
||||
# We don't use 'refine-from-user-input' because:
|
||||
# - I'm not sure if removing of parent's usage requirements makes sense
|
||||
# - refining of usage requirements is not needed, since usage requirements
|
||||
# are always free.
|
||||
# We do not use 'refine-from-user-input' because:
|
||||
# - I am not sure if removing parent's usage requirements makes sense
|
||||
# - refining usage requirements is not needed, since usage requirements are
|
||||
# always free.
|
||||
local usage-requirements = [ property-set.create-from-user-input
|
||||
$(specification)
|
||||
: [ $(project).project-module ] [ $(project).get location ] ] ;
|
||||
|
||||
@@ -21,8 +21,8 @@ import set ;
|
||||
|
||||
.ignore-requirements = ;
|
||||
|
||||
# This is used only for testing, to make sure we don't get random extra elements
|
||||
# in paths.
|
||||
# This is used only for testing, to make sure we do not get random extra
|
||||
# elements in paths.
|
||||
if --ignore-toolset-requirements in [ modules.peek : ARGV ]
|
||||
{
|
||||
.ignore-requirements = 1 ;
|
||||
@@ -56,7 +56,7 @@ local rule normalize-condition ( property-sets * )
|
||||
|
||||
|
||||
# Specifies if the 'flags' rule should check that the invoking module is the
|
||||
# same as the module we're setting the flag for. 'v' can be either 'checked' or
|
||||
# same as the module we are setting the flag for. 'v' can be either 'checked' or
|
||||
# 'unchecked'. Subsequent call to 'pop-checking-for-flags-module' will restore
|
||||
# the setting that was in effect before calling this rule.
|
||||
#
|
||||
@@ -101,7 +101,7 @@ rule flags (
|
||||
# <architecture>ia64/<address-model>
|
||||
#
|
||||
# Where both features are optional. Without this syntax
|
||||
# we'd be forced to define "default" values.
|
||||
# we would be forced to define "default" values.
|
||||
|
||||
values * : # The value to add to variable. If <feature> is specified,
|
||||
# then the value of 'feature' will be added.
|
||||
@@ -138,7 +138,7 @@ rule flags (
|
||||
if $(condition) && ! $(condition:G=) && ! $(hack-hack)
|
||||
{
|
||||
# We have condition in the form '<feature>', that is, without value.
|
||||
# That's a previous syntax:
|
||||
# That is an older syntax:
|
||||
# flags gcc.link RPATH <dll-path> ;
|
||||
# for compatibility, convert it to
|
||||
# flags gcc.link RPATH : <dll-path> ;
|
||||
@@ -162,10 +162,10 @@ local rule add-flag ( rule-or-module : variable-name : condition * : values * )
|
||||
{
|
||||
.$(rule-or-module).flags += $(.flag-no) ;
|
||||
|
||||
# Store all flags for a module
|
||||
# Store all flags for a module.
|
||||
local module_ = [ MATCH "([^.]*).*" : $(rule-or-module) ] ;
|
||||
.module-flags.$(module_) += $(.flag-no) ;
|
||||
# Store flag-no -> rule-or-module mapping
|
||||
# Store flag-no -> rule-or-module mapping.
|
||||
.rule-or-module.$(.flag-no) = $(rule-or-module) ;
|
||||
|
||||
.$(rule-or-module).variable.$(.flag-no) += $(variable-name) ;
|
||||
@@ -177,7 +177,7 @@ local rule add-flag ( rule-or-module : variable-name : condition * : values * )
|
||||
|
||||
|
||||
# Returns the first element of 'property-sets' which is a subset of
|
||||
# 'properties', or an empty list if no such element exists.
|
||||
# 'properties' or an empty list if no such element exists.
|
||||
#
|
||||
rule find-property-subset ( property-sets * : properties * )
|
||||
{
|
||||
@@ -225,6 +225,9 @@ rule find-property-subset ( property-sets * : properties * )
|
||||
}
|
||||
|
||||
|
||||
# Returns a value to be added to some flag for some target based on the flag's
|
||||
# value definition and the given target's property set.
|
||||
#
|
||||
rule handle-flag-value ( value * : properties * )
|
||||
{
|
||||
local result ;
|
||||
@@ -245,8 +248,8 @@ rule handle-flag-value ( value * : properties * )
|
||||
local values ;
|
||||
# Treat features with && in the value specially -- each
|
||||
# &&-separated element is considered a separate value. This is
|
||||
# needed to handle searched libraries, which must be in a
|
||||
# specific order.
|
||||
# needed to handle searched libraries or include paths, which
|
||||
# may need to be in a specific order.
|
||||
if ! [ MATCH (&&) : $(p:G=) ]
|
||||
{
|
||||
values = $(p:G=) ;
|
||||
@@ -383,11 +386,11 @@ rule inherit-generators ( toolset properties * : base : generators-to-ignore * )
|
||||
if ! $(id) in $(generators-to-ignore)
|
||||
{
|
||||
# Some generator names have multiple periods in their name, so
|
||||
# $(id:B=$(toolset)) doesn't generate the right new-id name. E.g. if
|
||||
# id = gcc.compile.c++, $(id:B=darwin) = darwin.c++, which is not
|
||||
# what we want. Manually parse the base and suffix (if there's a
|
||||
# better way to do this, I'd love to see it). See also register in
|
||||
# module generators.
|
||||
# $(id:B=$(toolset)) does not generate the right new-id name. E.g.
|
||||
# if id = gcc.compile.c++ then $(id:B=darwin) = darwin.c++, which is
|
||||
# not what we want. Manually parse the base and suffix. If there is
|
||||
# a better way to do this, I would love to see it. See also the
|
||||
# register() rule in the generators module.
|
||||
local base = $(id) ;
|
||||
local suffix = "" ;
|
||||
while $(base:S)
|
||||
@@ -405,14 +408,14 @@ rule inherit-generators ( toolset properties * : base : generators-to-ignore * )
|
||||
|
||||
# Brings all flag definitions from the 'base' toolset into the 'toolset'
|
||||
# toolset. Flag definitions whose conditions make use of properties in
|
||||
# 'prohibited-properties' are ignored. Don't confuse property and feature, for
|
||||
# 'prohibited-properties' are ignored. Do not confuse property and feature, for
|
||||
# example <debug-symbols>on and <debug-symbols>off, so blocking one of them does
|
||||
# not block the other one.
|
||||
#
|
||||
# The flag conditions are not altered at all, so if a condition includes a name,
|
||||
# or version of a base toolset, it won't ever match the inheriting toolset. When
|
||||
# such flag settings must be inherited, define a rule in base toolset module and
|
||||
# call it as needed.
|
||||
# or version of a base toolset, it will not ever match the inheriting toolset.
|
||||
# When such flag settings must be inherited, define a rule in base toolset
|
||||
# module and call it as needed.
|
||||
#
|
||||
rule inherit-flags ( toolset : base : prohibited-properties * )
|
||||
{
|
||||
@@ -447,7 +450,7 @@ rule inherit-flags ( toolset : base : prohibited-properties * )
|
||||
|
||||
rule inherit-rules ( toolset : base )
|
||||
{
|
||||
# It appears that "action" creates a local rule...
|
||||
# It appears that "action" creates a local rule.
|
||||
local base-generators = [ generators.generators-for-toolset $(base) ] ;
|
||||
local rules ;
|
||||
for local g in $(base-generators)
|
||||
@@ -456,8 +459,7 @@ rule inherit-rules ( toolset : base )
|
||||
rules += $(id) ;
|
||||
}
|
||||
IMPORT $(base) : $(rules) : $(toolset) : $(rules) ;
|
||||
# Import the rules to the global scope
|
||||
IMPORT $(toolset) : $(rules) : : $(toolset).$(rules) ;
|
||||
IMPORT $(base) : $(rules) : : $(toolset).$(rules) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ import project ;
|
||||
import property ;
|
||||
import scanner ;
|
||||
|
||||
# The follwing import would create a circular dependency:
|
||||
|
||||
# The following import would create a circular dependency:
|
||||
# project -> project-root -> builtin -> type -> targets -> project
|
||||
# import targets ;
|
||||
|
||||
@@ -48,15 +49,15 @@ rule register ( type : suffixes * : base-type ? )
|
||||
else
|
||||
{
|
||||
.types += $(type) ;
|
||||
.bases.$(type) = $(base-type) ;
|
||||
.base.$(type) = $(base-type) ;
|
||||
.derived.$(base-type) += $(type) ;
|
||||
|
||||
if $(suffixes)-is-not-empty
|
||||
{
|
||||
# Specify mapping from suffixes to type.
|
||||
register-suffixes $(suffixes) : $(type) ;
|
||||
# Generated targets of 'type' will use the first of 'suffixes'. This
|
||||
# may be overriden.
|
||||
# By default generated targets of 'type' will use the first of
|
||||
#'suffixes'. This may be overriden.
|
||||
set-generated-target-suffix $(type) : : $(suffixes[1]) ;
|
||||
}
|
||||
|
||||
@@ -68,14 +69,18 @@ rule register ( type : suffixes * : base-type ? )
|
||||
feature.compose <base-target-type>$(type) : <base-target-type>$(base-type) ;
|
||||
|
||||
# We used to declare the main target rule only when a 'main' parameter
|
||||
# was specified. However, it's hard to decide that a type will *never*
|
||||
# need a main target rule and so from time to time we needed to make yet
|
||||
# another type 'main'. So now a main target rule is defined for each
|
||||
# type.
|
||||
# has been specified. However, it is hard to decide that a type will
|
||||
# *never* need a main target rule and so from time to time we needed to
|
||||
# make yet another type 'main'. So now a main target rule is defined for
|
||||
# each type.
|
||||
main-rule-name = [ type-to-rule-name $(type) ] ;
|
||||
.main-target-type.$(main-rule-name) = $(type) ;
|
||||
|
||||
IMPORT $(__name__) : main-target-rule : : $(main-rule-name) ;
|
||||
|
||||
# Adding a new derived type affects generator selection so we need to
|
||||
# make the generator selection module update any of its cached
|
||||
# information related to a new derived type being defined.
|
||||
generators.update-cached-information-with-a-new-type $(type) ;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,8 +119,8 @@ rule register-suffixes ( suffixes + : type )
|
||||
}
|
||||
else if $(.type.$(s)) != type
|
||||
{
|
||||
errors.error Attempting to specify multiple types for suffix \"$(s)\"
|
||||
: "Old type $(.type.$(s)), New type $(type)" ;
|
||||
errors.error Attempting to specify multiple types for suffix
|
||||
\"$(s)\" : "Old type $(.type.$(s)), New type $(type)" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,7 +141,7 @@ rule registered ( type )
|
||||
#
|
||||
rule validate ( type )
|
||||
{
|
||||
if ! $(type) in $(.types)
|
||||
if ! [ registered $(type) ]
|
||||
{
|
||||
errors.error "Unknown target type $(type)" ;
|
||||
}
|
||||
@@ -147,10 +152,7 @@ rule validate ( type )
|
||||
#
|
||||
rule set-scanner ( type : scanner )
|
||||
{
|
||||
if ! $(type) in $(.types)
|
||||
{
|
||||
error "Type" $(type) "is not declared" ;
|
||||
}
|
||||
validate $(type) ;
|
||||
.scanner.$(type) = $(scanner) ;
|
||||
}
|
||||
|
||||
@@ -166,6 +168,15 @@ rule get-scanner ( type : property-set )
|
||||
}
|
||||
|
||||
|
||||
# Returns a base type for the given type or nothing in case the given type is
|
||||
# not derived.
|
||||
#
|
||||
rule base ( type )
|
||||
{
|
||||
return $(.base.$(type)) ;
|
||||
}
|
||||
|
||||
|
||||
# Returns the given type and all of its base types in order of their distance
|
||||
# from type.
|
||||
#
|
||||
@@ -174,13 +185,16 @@ rule all-bases ( type )
|
||||
local result = $(type) ;
|
||||
while $(type)
|
||||
{
|
||||
type = $(.bases.$(type)) ;
|
||||
type = [ base $(type) ] ;
|
||||
result += $(type) ;
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
|
||||
# Returns the given type and all of its derived types in order of their distance
|
||||
# from type.
|
||||
#
|
||||
rule all-derived ( type )
|
||||
{
|
||||
local result = $(type) ;
|
||||
@@ -192,7 +206,8 @@ rule all-derived ( type )
|
||||
}
|
||||
|
||||
|
||||
# Returns true if 'type' has 'base' as its direct or indirect base.
|
||||
# Returns true if 'type' is equal to 'base' or has 'base' as its direct or
|
||||
# indirect base.
|
||||
#
|
||||
rule is-derived ( type base )
|
||||
{
|
||||
@@ -202,19 +217,15 @@ rule is-derived ( type base )
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Returns true if 'type' is either derived from or is equal to 'base'.
|
||||
#
|
||||
# TODO: It might be that is-derived and is-subtype were meant to be different
|
||||
# rules - one returning true for type = base and one not, but as currently
|
||||
# implemented they are actually the same. Clean this up.
|
||||
#
|
||||
rule is-subtype ( type base )
|
||||
{
|
||||
if $(type) = $(base)
|
||||
{
|
||||
return true ;
|
||||
}
|
||||
else
|
||||
{
|
||||
return [ is-derived $(type) $(base) ] ;
|
||||
}
|
||||
return [ is-derived $(type) $(base) ] ;
|
||||
}
|
||||
|
||||
|
||||
@@ -329,7 +340,7 @@ local rule generated-target-ps-real ( ps : type : properties * )
|
||||
{
|
||||
found = true ;
|
||||
}
|
||||
type = $(.bases.$(type)) ;
|
||||
type = $(.base.$(type)) ;
|
||||
}
|
||||
if $(result) = ""
|
||||
{
|
||||
@@ -345,8 +356,8 @@ local rule generated-target-ps ( ps : type : property-set )
|
||||
local v = $($(key)) ;
|
||||
if ! $(v)
|
||||
{
|
||||
v = [ generated-target-ps-real $(ps) : $(type)
|
||||
: [ $(property-set).raw ] ] ;
|
||||
v = [ generated-target-ps-real $(ps) : $(type) : [ $(property-set).raw ]
|
||||
] ;
|
||||
if ! $(v)
|
||||
{
|
||||
v = none ;
|
||||
@@ -361,9 +372,9 @@ local rule generated-target-ps ( ps : type : property-set )
|
||||
}
|
||||
|
||||
|
||||
# Returns file type given it's name. If there are several dots in filename,
|
||||
# tries each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and "so"
|
||||
# will be tried.
|
||||
# Returns file type given its name. If there are several dots in filename, tries
|
||||
# each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and "so" will
|
||||
# be tried.
|
||||
#
|
||||
rule type ( filename )
|
||||
{
|
||||
@@ -379,23 +390,32 @@ rule type ( filename )
|
||||
|
||||
|
||||
# Rule used to construct all main targets. Note that this rule gets imported
|
||||
# into the global namespace under different alias names and exactly what type of
|
||||
# target it is supposed to construct is read from the name of the alias rule
|
||||
# actually used to invoke it.
|
||||
# into the global namespace under different alias names and the exact target
|
||||
# type to construct is selected based on the alias used to actually invoke this
|
||||
# rule.
|
||||
#
|
||||
rule main-target-rule ( name : sources * : requirements * : default-build *
|
||||
: usage-requirements * )
|
||||
rule main-target-rule ( name : sources * : requirements * : default-build * :
|
||||
usage-requirements * )
|
||||
{
|
||||
# First discover the required target type, which is equal to the rule name
|
||||
# used to invoke us.
|
||||
# First discover the required target type based on the exact alias used to
|
||||
# invoke this rule.
|
||||
local bt = [ BACKTRACE 1 ] ;
|
||||
local rulename = $(bt[4]) ;
|
||||
local target-type = [ type-from-rule-name $(rulename) ] ;
|
||||
|
||||
local project = [ project.current ] ;
|
||||
|
||||
# This is a circular module dependency so it must be imported here.
|
||||
# This is a circular module dependency and so must be imported here.
|
||||
import targets ;
|
||||
return [ targets.create-typed-target $(.main-target-type.$(rulename))
|
||||
: $(project) : $(name) : $(sources) : $(requirements)
|
||||
: $(default-build) : $(usage-requirements) ] ;
|
||||
|
||||
return [ targets.create-typed-target $(target-type) : [ project.current ] :
|
||||
$(name) : $(sources) : $(requirements) : $(default-build) :
|
||||
$(usage-requirements) ] ;
|
||||
}
|
||||
|
||||
|
||||
rule __test__ ( )
|
||||
{
|
||||
import assert ;
|
||||
|
||||
# TODO: Add tests for all the is-derived, is-base & related type relation
|
||||
# checking rules.
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
# Implements virtual targets, which correspond to actual files created during a
|
||||
# build, but are not yet targets in Jam sense. They are needed, for example,
|
||||
# when searching for possible transformation sequences, when it's not yet known
|
||||
# when searching for possible transformation sequences, when it is not yet known
|
||||
# whether a particular target should be created at all.
|
||||
|
||||
import "class" : new ;
|
||||
@@ -17,6 +17,7 @@ import set ;
|
||||
import type ;
|
||||
import utility ;
|
||||
|
||||
|
||||
# +--------------------------+
|
||||
# | virtual-target |
|
||||
# +==========================+
|
||||
@@ -88,18 +89,24 @@ class virtual-target
|
||||
|
||||
# Name of this target.
|
||||
#
|
||||
rule name ( ) { return $(self.name) ; }
|
||||
rule name ( )
|
||||
{
|
||||
return $(self.name) ;
|
||||
}
|
||||
|
||||
# Project of this target.
|
||||
#
|
||||
rule project ( ) { return $(self.project) ; }
|
||||
rule project ( )
|
||||
{
|
||||
return $(self.project) ;
|
||||
}
|
||||
|
||||
# Adds additional 'virtual-target' instances this one depends on.
|
||||
#
|
||||
rule depends ( d + )
|
||||
{
|
||||
self.dependencies = [ sequence.merge $(self.dependencies)
|
||||
: [ sequence.insertion-sort $(d) ] ] ;
|
||||
self.dependencies = [ sequence.merge $(self.dependencies) :
|
||||
[ sequence.insertion-sort $(d) ] ] ;
|
||||
}
|
||||
|
||||
rule dependencies ( )
|
||||
@@ -185,7 +192,8 @@ class virtual-target
|
||||
{
|
||||
# In fact, we just need to merge virtual-target with
|
||||
# abstract-file-target as the latter is the only class derived from the
|
||||
# former. But that's for later.
|
||||
# former. But that has been left for later.
|
||||
|
||||
errors.error "method should be defined in derived classes" ;
|
||||
}
|
||||
}
|
||||
@@ -197,8 +205,9 @@ class virtual-target
|
||||
# May be a source file (when no action is specified) or a derived file
|
||||
# (otherwise).
|
||||
#
|
||||
# The target's grist is concatenation of its project's location, properties of
|
||||
# action (for derived files) and, optionally, value identifying the main target.
|
||||
# The target's grist is a concatenation of its project's location, action
|
||||
# properties (for derived targets) and, optionally, value identifying the main
|
||||
# target.
|
||||
#
|
||||
class abstract-file-target : virtual-target
|
||||
{
|
||||
@@ -236,7 +245,10 @@ class abstract-file-target : virtual-target
|
||||
}
|
||||
}
|
||||
|
||||
rule type ( ) { return $(self.type) ; }
|
||||
rule type ( )
|
||||
{
|
||||
return $(self.type) ;
|
||||
}
|
||||
|
||||
# Sets the path. When generating target name, it will override any path
|
||||
# computation from properties.
|
||||
@@ -291,11 +303,11 @@ class abstract-file-target : virtual-target
|
||||
}
|
||||
|
||||
# Return a human-readable representation of this target. If this target has
|
||||
# an action, that's:
|
||||
# an action, that is:
|
||||
#
|
||||
# { <action-name>-<self.name>.<self.type> <action-sources>... }
|
||||
#
|
||||
# otherwise, it's:
|
||||
# otherwise, it is:
|
||||
#
|
||||
# { <self.name>.<self.type> }
|
||||
#
|
||||
@@ -358,7 +370,7 @@ class abstract-file-target : virtual-target
|
||||
rule grist ( )
|
||||
{
|
||||
# Depending on target, there may be different approaches to generating
|
||||
# unique prefixes. We'll generate prefixes in the form
|
||||
# unique prefixes. We generate prefixes in the form:
|
||||
# <one letter approach code> <the actual prefix>
|
||||
local path = [ path ] ;
|
||||
if $(path)
|
||||
@@ -441,7 +453,7 @@ class abstract-file-target : virtual-target
|
||||
}
|
||||
}
|
||||
|
||||
# If there's no tag or the tag rule returned nothing.
|
||||
# If there is no tag or the tag rule returned nothing.
|
||||
if ! $(tag) || ! $(self.name)
|
||||
{
|
||||
self.name = [ virtual-target.add-prefix-and-suffix $(specified-name)
|
||||
@@ -460,7 +472,7 @@ class abstract-file-target : virtual-target
|
||||
|
||||
if $(self.action)
|
||||
{
|
||||
# For non-derived target, we don't care if there are several
|
||||
# For non-derived target, we do not care if there are several
|
||||
# virtual targets that refer to the same name. One case when
|
||||
# this is unavoidable is when the file name is main.cpp and two
|
||||
# targets have types CPP (for compiling) and MOCCABLE_CPP (for
|
||||
@@ -531,23 +543,23 @@ class file-target : abstract-file-target
|
||||
import errors ;
|
||||
|
||||
rule __init__ (
|
||||
name exact ?
|
||||
: type ? # Optional type for this target
|
||||
name exact ?
|
||||
: type ? # Optional type for this target.
|
||||
: project
|
||||
: action ?
|
||||
: path ?
|
||||
)
|
||||
{
|
||||
abstract-file-target.__init__ $(name) $(exact) : $(type) : $(project)
|
||||
: $(action) ;
|
||||
abstract-file-target.__init__ $(name) $(exact) : $(type) : $(project) :
|
||||
$(action) ;
|
||||
|
||||
self.path = $(path) ;
|
||||
}
|
||||
|
||||
rule clone-with-different-type ( new-type )
|
||||
{
|
||||
return [ new file-target $(self.name) exact : $(new-type)
|
||||
: $(self.project) : $(self.action) : $(self.path) ] ;
|
||||
return [ new file-target $(self.name) exact : $(new-type) :
|
||||
$(self.project) : $(self.action) : $(self.path) ] ;
|
||||
}
|
||||
|
||||
rule actualize-location ( target )
|
||||
@@ -581,14 +593,14 @@ class file-target : abstract-file-target
|
||||
# target has no directory name and uses a special <e> grist.
|
||||
#
|
||||
# First, that means that "bjam hello.o" will build all known hello.o
|
||||
# targets. Second, the <e> grist makes sure this target won't be
|
||||
# targets. Second, the <e> grist makes sure this target will not be
|
||||
# confused with other targets, for example, if we have subdir 'test'
|
||||
# with target 'test' in it that includes a 'test.o' file, then the
|
||||
# target for directory will be just 'test' the target for test.o
|
||||
# will be <ptest/bin/gcc/debug>test.o and the target we create below
|
||||
# will be <e>test.o
|
||||
DEPENDS $(target:G=e) : $(target) ;
|
||||
# Allow bjam <path-to-file>/<file> to work. This won't catch all
|
||||
# Allow bjam <path-to-file>/<file> to work. This will not catch all
|
||||
# possible ways to refer to the path (relative/absolute, extra ".",
|
||||
# various "..", but should help in obvious cases.
|
||||
DEPENDS $(target:G=e:R=$(path)) : $(target) ;
|
||||
@@ -608,13 +620,13 @@ class file-target : abstract-file-target
|
||||
if $(self.action)
|
||||
{
|
||||
local p = [ $(self.action).properties ] ;
|
||||
local path = [ $(p).target-path ] ;
|
||||
local path,relative-to-build-dir = [ $(p).target-path ] ;
|
||||
local path = $(path,relative-to-build-dir[1]) ;
|
||||
local relative-to-build-dir = $(path,relative-to-build-dir[2]) ;
|
||||
|
||||
if $(path[2]) = true
|
||||
if $(relative-to-build-dir)
|
||||
{
|
||||
# Indicates that the path is relative to the build dir.
|
||||
path = [ path.join [ $(self.project).build-dir ]
|
||||
$(path[1]) ] ;
|
||||
path = [ path.join [ $(self.project).build-dir ] $(path) ] ;
|
||||
}
|
||||
|
||||
self.path = [ path.native $(path) ] ;
|
||||
@@ -727,7 +739,8 @@ class action
|
||||
|
||||
actualize-sources [ sources ] : $(properties) ;
|
||||
|
||||
DEPENDS $(actual-targets) : $(self.actual-sources) $(self.dependency-only-sources) ;
|
||||
DEPENDS $(actual-targets) : $(self.actual-sources)
|
||||
$(self.dependency-only-sources) ;
|
||||
|
||||
# Action name can include additional argument to rule, which should
|
||||
# not be passed to 'set-target-variables'
|
||||
@@ -794,8 +807,8 @@ class action
|
||||
#
|
||||
# For bjam to find the dependency the generated target must be
|
||||
# actualized (i.e. have its Jam target constructed). In the above case,
|
||||
# if we're building just hello ("bjam hello"), 'a.h' won't be actualized
|
||||
# unless we do it here.
|
||||
# if we are building just hello ("bjam hello"), 'a.h' will not be
|
||||
# actualized unless we do it here.
|
||||
local implicit = [ $(self.properties).get <implicit-dependency> ] ;
|
||||
for local i in $(implicit)
|
||||
{
|
||||
@@ -816,7 +829,7 @@ class action
|
||||
|
||||
|
||||
# Action class which does nothing --- it produces the targets with specific
|
||||
# properties out of nowhere. It's needed to distinguish virtual targets with
|
||||
# properties out of nowhere. It is needed to distinguish virtual targets with
|
||||
# different properties that are known to exist and have no actions which create
|
||||
# them.
|
||||
#
|
||||
@@ -866,16 +879,21 @@ class non-scanning-action : action
|
||||
# Creates a virtual target with an appropriate name and type from 'file'. If a
|
||||
# target with that name in that project already exists, returns that already
|
||||
# created target.
|
||||
#
|
||||
# FIXME: a more correct way would be to compute the path to the file, based on
|
||||
# name and source location for the project, and use that path to determine if
|
||||
# the target was already created.
|
||||
# the target has already been created. This logic should be shared with how we
|
||||
# usually find targets identified by a specific target id. It should also be
|
||||
# updated to work correctly when the file is specified using both relative and
|
||||
# absolute paths.
|
||||
#
|
||||
# TODO: passing a project with all virtual targets is starting to be annoying.
|
||||
#
|
||||
rule from-file ( file : file-loc : project )
|
||||
{
|
||||
import type ; # Had to do this here to break a circular dependency.
|
||||
|
||||
# Check if we've created a target corresponding to this file.
|
||||
# Check whether we already created a target corresponding to this file.
|
||||
local path = [ path.root [ path.root $(file) $(file-loc) ] [ path.pwd ] ] ;
|
||||
|
||||
if $(.files.$(path))
|
||||
@@ -888,11 +906,8 @@ rule from-file ( file : file-loc : project )
|
||||
local type = [ type.type $(file) ] ;
|
||||
local result ;
|
||||
|
||||
result = [ new file-target $(file)
|
||||
: $(type)
|
||||
: $(project)
|
||||
: #action
|
||||
: $(file-loc) ] ;
|
||||
result = [ new file-target $(file) : $(type) : $(project) : :
|
||||
$(file-loc) ] ;
|
||||
|
||||
.files.$(path) = $(result) ;
|
||||
return $(result) ;
|
||||
@@ -900,7 +915,7 @@ rule from-file ( file : file-loc : project )
|
||||
}
|
||||
|
||||
|
||||
# Registers a new virtual target. Checks if there's already a registered target
|
||||
# Registers a new virtual target. Checks if there is already a registered target
|
||||
# with the same name, type, project and subvariant properties as well as the
|
||||
# same sources and equal action. If such target is found it is returned and a
|
||||
# new 'target' is not registered. Otherwise, 'target' is registered and
|
||||
@@ -926,15 +941,15 @@ rule register ( target )
|
||||
else
|
||||
{
|
||||
if $(a1) && $(a2) &&
|
||||
[ $(a1).action-name ] = [ $(a2).action-name ] &&
|
||||
[ $(a1).sources ] = [ $(a2).sources ]
|
||||
( [ $(a1).action-name ] = [ $(a2).action-name ] ) &&
|
||||
( [ $(a1).sources ] = [ $(a2).sources ] )
|
||||
{
|
||||
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).base ] [ $(ps1).free ] [ set.difference
|
||||
[ $(ps1).dependency ] : [ $(ps1).incidental ] ] ;
|
||||
local p2 = [ $(ps2).base ] [ $(ps2).free ] [ set.difference
|
||||
[ $(ps2).dependency ] : [ $(ps2).incidental ] ] ;
|
||||
if $(p1) = $(p2)
|
||||
{
|
||||
result = $(t) ;
|
||||
@@ -957,10 +972,10 @@ rule register ( target )
|
||||
}
|
||||
|
||||
|
||||
# Each target returned by 'register' is added to a .recent-targets list,
|
||||
# Each target returned by 'register' is added to the .recent-targets list,
|
||||
# returned by this function. This allows us to find all virtual targets created
|
||||
# when building a given main target, even those constructed only as intermediate
|
||||
# targets.
|
||||
# when building a specific main target, even those constructed only as
|
||||
# intermediate targets.
|
||||
#
|
||||
rule recent-targets ( )
|
||||
{
|
||||
@@ -1040,9 +1055,9 @@ rule register-actual-name ( actual-name : virtual-target )
|
||||
|
||||
# Traverses the dependency graph of 'target' and return all targets that will be
|
||||
# created before this one is created. If the root of some dependency graph is
|
||||
# found during traversal, it's either included or not, depending on the value of
|
||||
# 'include-roots'. In either case traversal stops at root targets, i.e. sources
|
||||
# of root targets are not traversed.
|
||||
# found during traversal, it is either included or not, depending on the
|
||||
# 'include-roots' value. In either case traversal stops at root targets, i.e.
|
||||
# root target sources are not traversed.
|
||||
#
|
||||
rule traverse ( target : include-roots ? : include-sources ? )
|
||||
{
|
||||
@@ -1097,9 +1112,9 @@ rule clone-action ( action : new-project : new-action-name ? : new-properties ?
|
||||
for local target in [ $(action).targets ]
|
||||
{
|
||||
local n = [ $(target).name ] ;
|
||||
# Don't modify produced targets names.
|
||||
local cloned-target = [ class.new file-target $(n) exact
|
||||
: [ $(target).type ] : $(new-project) : $(cloned-action) ] ;
|
||||
# Do not modify produced target names.
|
||||
local cloned-target = [ class.new file-target $(n) exact :
|
||||
[ $(target).type ] : $(new-project) : $(cloned-action) ] ;
|
||||
local d = [ $(target).dependencies ] ;
|
||||
if $(d)
|
||||
{
|
||||
|
||||
195
v2/contrib/wxFormBuilder.jam
Normal file
195
v2/contrib/wxFormBuilder.jam
Normal file
@@ -0,0 +1,195 @@
|
||||
################################################################################
|
||||
#
|
||||
# Copyright (c) 2007-2008 Dario Senic, Jurko Gospodnetic.
|
||||
#
|
||||
# Use, modification and distribution is subject to the Boost Software
|
||||
# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
#
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Boost Build wxFormBuilder generator tool module.
|
||||
#
|
||||
# wxFormBuilder is a GUI designer tool for the wxWidgets library. It can then
|
||||
# generate C++ sources modeling the designed GUI using the wxWidgets library
|
||||
# APIs.
|
||||
#
|
||||
# This module defines a wxFormBuilder project file type and rules needed to
|
||||
# generate C++ source files from those projects. With it you can simply list
|
||||
# wxFormBuilder projects as sources for some target and Boost Build will
|
||||
# automatically convert them to C++ sources and process from there.
|
||||
#
|
||||
# The wxFormBuilder executable location may be provided as a parameter when
|
||||
# configuring this toolset. Otherwise the default wxFormBuilder.exe executable
|
||||
# name is used located in the folder pointed to by the WXFORMBUILDER environment
|
||||
# variable.
|
||||
#
|
||||
# Current limitations:
|
||||
#
|
||||
# * Works only on Windows.
|
||||
# * Works only when run via Boost Jam using the native Windows cmd.exe command
|
||||
# interpreter, i.e. the default native Windows Boost Jam build.
|
||||
# * Used wxFormBuilder projects need to have their output file names defined
|
||||
# consistently with target names assumed by this build script. This means
|
||||
# that their target names must use the prefix 'wxFormBuilderGenerated_' and
|
||||
# have no output folder defined where the base name is equal to the .fpb
|
||||
# project file's name.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Implementation note:
|
||||
#
|
||||
# Avoiding the limitation on the generated target file names can be done but
|
||||
# would require depending on external tools to copy the wxFormBuilder project to
|
||||
# a temp location and then modify it in-place to set its target file names. On
|
||||
# the other hand wxFormBuilder is expected to add command-line options for
|
||||
# choosing the target file names from the command line which will allow us to
|
||||
# remove this limitation in a much cleaner way.
|
||||
# (23.08.2008.) (Jurko)
|
||||
#
|
||||
################################################################################
|
||||
|
||||
import generators ;
|
||||
import os ;
|
||||
import path ;
|
||||
import toolset ;
|
||||
import type ;
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# wxFormBuilder.generate()
|
||||
# ------------------------
|
||||
#
|
||||
# Action for processing WX_FORM_BUILDER_PROJECT types.
|
||||
#
|
||||
################################################################################
|
||||
#
|
||||
# Implementation notes:
|
||||
#
|
||||
# wxFormBuilder generated CPP and H files need to be moved to the location
|
||||
# where the Boost Build target system expects them so that the generated CPP
|
||||
# file can be included into the compile process and that the clean rule
|
||||
# succesfully deletes both CPP and H files. We expect wxFormBuilder to generate
|
||||
# files in the same location where the provided WX_FORM_BUILDER_PROJECT file is
|
||||
# located.
|
||||
# (15.05.2007.) (Dario)
|
||||
#
|
||||
################################################################################
|
||||
|
||||
actions generate
|
||||
{
|
||||
start "" /wait "$(EXECUTABLE)" /g "$(2)"
|
||||
move "$(1[1]:BSR=$(2:P))" "$(1[1]:P)"
|
||||
move "$(1[2]:BSR=$(2:P))" "$(1[2]:P)"
|
||||
}
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# wxFormBuilder.init()
|
||||
# --------------------
|
||||
#
|
||||
# Main toolset initialization rule called via the toolset.using rule.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
rule init ( executable ? )
|
||||
{
|
||||
if $(.initialized)
|
||||
{
|
||||
if $(.debug-configuration)
|
||||
{
|
||||
ECHO notice: [wxFormBuilder-cfg] Repeated initialization request
|
||||
(executable \"$(executable:E="")\") detected and ignored. ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
local environmentVariable = WXFORMBUILDER ;
|
||||
|
||||
if $(.debug-configuration)
|
||||
{
|
||||
ECHO notice: [wxFormBuilder-cfg] Configuring wxFormBuilder... ;
|
||||
}
|
||||
|
||||
# Deduce the path to the used wxFormBuilder executable.
|
||||
if ! $(executable)
|
||||
{
|
||||
executable = "wxFormBuilder.exe" ;
|
||||
local executable-path = [ os.environ $(environmentVariable) ] ;
|
||||
if $(executable-path)-is-not-empty
|
||||
{
|
||||
executable = [ path.root $(executable) $(executable-path) ] ;
|
||||
}
|
||||
else if $(.debug-configuration)
|
||||
{
|
||||
ECHO notice: [wxFormBuilder-cfg] No wxFormBuilder path
|
||||
configured either explicitly or using the
|
||||
$(environmentVariable) environment variable. ;
|
||||
ECHO notice: [wxFormBuilder-cfg] To avoid complications please
|
||||
update your configuration to includes a correct path to the
|
||||
wxFormBuilder executable. ;
|
||||
ECHO notice: [wxFormBuilder-cfg] wxFormBuilder executable will
|
||||
be searched for on the system path. ;
|
||||
}
|
||||
}
|
||||
if $(.debug-configuration)
|
||||
{
|
||||
ECHO notice: [wxFormBuilder-cfg] Will use wxFormBuilder executable
|
||||
\"$(executable)\". ;
|
||||
}
|
||||
|
||||
# Now we are sure we have everything we need to initialize this toolset.
|
||||
.initialized = true ;
|
||||
|
||||
# Store the path to the used wxFormBuilder executable.
|
||||
.executable = $(executable) ;
|
||||
|
||||
# Type registration.
|
||||
type.register WX_FORM_BUILDER_PROJECT : fbp ;
|
||||
|
||||
# Parameters to be forwarded to the action rule.
|
||||
toolset.flags wxFormBuilder.generate EXECUTABLE : $(.executable) ;
|
||||
|
||||
# Generator definition and registration.
|
||||
generators.register-standard wxFormBuilder.generate :
|
||||
WX_FORM_BUILDER_PROJECT : CPP(wxFormBuilderGenerated_%)
|
||||
H(wxFormBuilderGenerated_%) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# wxFormBuilder.is-initialized()
|
||||
# ------------------------------
|
||||
#
|
||||
# Returns whether this toolset has been initialized.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
rule is-initialized ( )
|
||||
{
|
||||
return $(.initialized) ;
|
||||
}
|
||||
|
||||
|
||||
################################################################################
|
||||
#
|
||||
# Startup code executed when loading this module.
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# Global variables for this module.
|
||||
.executable = ;
|
||||
.initialized = ;
|
||||
|
||||
if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
|
||||
{
|
||||
.debug-configuration = true ;
|
||||
}
|
||||
@@ -5,60 +5,78 @@
|
||||
<chapter id="bbv2.advanced">
|
||||
<title>Overview</title>
|
||||
|
||||
<para>This section will provide the information necessary to create your own
|
||||
projects using Boost.Build. The information provided here is relatively
|
||||
high-level, and <xref linkend="bbv2.reference"/> as well as the on-line help
|
||||
system must be used to obtain low-level documentation (see <xref linkend=
|
||||
"bbv2.reference.init.options.help"/>).</para>
|
||||
<para>
|
||||
This section will provide the information necessary to create your own
|
||||
projects using Boost.Build. The information provided here is relatively
|
||||
high-level, and <xref linkend="bbv2.reference"/> as well as the on-line
|
||||
help system must be used to obtain low-level documentation (see <xref
|
||||
linkend="bbv2.reference.init.options.help"/>).
|
||||
</para>
|
||||
|
||||
<para>Boost.Build actually consists of two parts - Boost.Jam, a build engine
|
||||
with its own interpreted language, and Boost.Build itself, implemented in
|
||||
Boost.Jam's language. The chain of events when you type
|
||||
<command>bjam</command> on the command line is:
|
||||
<para>
|
||||
Boost.Build actually consists of two parts - Boost.Jam, a build engine
|
||||
with its own interpreted language, and Boost.Build itself, implemented in
|
||||
Boost.Jam's language. The chain of events when you type
|
||||
<command>bjam</command> on the command line is as follows:
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Boost.Jam tries to find Boost.Build and loads the top-level
|
||||
module. The exact process is described in <xref
|
||||
linkend="bbv2.reference.init"/></para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The top-level module loads user-defined configuration files,
|
||||
<filename>user-config.jam</filename> and
|
||||
<filename>site-config.jam</filename>, which define available toolsets.
|
||||
<para>
|
||||
Boost.Jam tries to find Boost.Build and loads the top-level module.
|
||||
The exact process is described in <xref linkend=
|
||||
"bbv2.reference.init"/>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The Jamfile in the current directory is read. That in turn
|
||||
might cause reading of further Jamfiles. As a result, a tree of
|
||||
projects is created, with targets inside projects.</para>
|
||||
<para>
|
||||
The top-level module loads user-defined configuration files,
|
||||
<filename>user-config.jam</filename> and <filename>site-config.jam
|
||||
</filename>, which define available toolsets.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Finally, using the build request specified on the command line,
|
||||
Boost.Build decides which targets should be built, and how. That
|
||||
information is passed back to Boost.Jam, which takes care of
|
||||
actually running commands.</para>
|
||||
<para>
|
||||
The Jamfile in the current directory is read. That in turn might
|
||||
cause reading of further Jamfiles. As a result, a tree of projects
|
||||
is created, with targets inside projects.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Finally, using the build request specified on the command line,
|
||||
Boost.Build decides which targets should be built and how. That
|
||||
information is passed back to Boost.Jam, which takes care of
|
||||
actually running the scheduled build action commands.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
|
||||
<para>So, to be able to successfully use Boost.Build, you need to know only
|
||||
four things:
|
||||
<para>
|
||||
So, to be able to successfully use Boost.Build, you need to know only four
|
||||
things:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para><link linkend="bbv2.advanced.configuration">
|
||||
How to configure Boost.Build</link></para>
|
||||
<para>
|
||||
<link linkend="bbv2.advanced.configuration">How to configure
|
||||
Boost.Build</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="bbv2.advanced.targets">
|
||||
How to write declares targets in Jamfiles</link></para>
|
||||
<para>
|
||||
<link linkend="bbv2.advanced.targets">How to declare targets in
|
||||
Jamfiles</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><link linkend="bbv2.advanced.build_process">
|
||||
How the build process works</link></para>
|
||||
<para>
|
||||
<link linkend="bbv2.advanced.build_process">How the build process
|
||||
works</link>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Some Basics about the Boost.Jam language. See
|
||||
<xref linkend="bbv2.advanced.jam_language"/>.
|
||||
<para>
|
||||
Some Basics about the Boost.Jam language. See <xref linkend=
|
||||
"bbv2.advanced.jam_language"/>.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
@@ -67,153 +85,187 @@
|
||||
<section id="bbv2.advanced.jam_language">
|
||||
<title>Boost.Jam Language</title>
|
||||
|
||||
<para>This section will describe the basics of the Boost.Jam
|
||||
language—just enough for writing Jamfiles. For more information,
|
||||
please see the <link linkend="bbv2.jam">Boost.Jam</link> documentation.
|
||||
</para>
|
||||
|
||||
<para><link linkend="bbv2.jam">Boost.Jam</link> has an interpreted,
|
||||
procedural language. On the lowest level, a <link linkend="bbv2.jam">
|
||||
Boost.Jam</link> program consists of variables and
|
||||
<indexterm><primary>rule</primary></indexterm>
|
||||
<firstterm>rules</firstterm> (the Jam term for function). They are grouped
|
||||
in modules—there's one global module and a number of named modules.
|
||||
Besides that, a <link linkend="bbv2.jam">Boost.Jam</link> program contains
|
||||
classes and class instances.</para>
|
||||
|
||||
<para>Syntantically, a <link linkend="bbv2.jam">Boost.Jam</link> program
|
||||
consists of two kind of elements—keywords (which have a special
|
||||
meaning to <link linkend="bbv2.jam">Boost.Jam</link>) and literals.
|
||||
|
||||
Consider this code:
|
||||
<programlisting>
|
||||
a = b ;</programlisting>
|
||||
which assigns the value <literal>b</literal> to the variable
|
||||
<literal>a</literal>. Here, <literal>=</literal> and <literal>;</literal>
|
||||
are keywords, while <literal>a</literal> and <literal>b</literal> are
|
||||
literals.
|
||||
<warning>
|
||||
<para>All syntax elements, even keywords, must be separated by spaces.
|
||||
For example, omitting the space character before <literal>;</literal>
|
||||
will lead to a syntax error.
|
||||
</para>
|
||||
</warning>
|
||||
If you want to use a literal value that is the same as some keyword, the
|
||||
value can be quoted:
|
||||
<programlisting>
|
||||
a = "=" ;</programlisting>
|
||||
</para>
|
||||
|
||||
<para>All variables in <link linkend="bbv2.jam">Boost.Jam</link> have the
|
||||
same type—list of strings. To define a variable one assigns a value
|
||||
to it, like in the previous example. An undefined variable is the same as
|
||||
a variable with an empty value. Variables can be accessed using the
|
||||
<code>$(<replaceable>variable</replaceable>)</code> syntax. For example:
|
||||
<programlisting>
|
||||
a = $(b) $(c) ;</programlisting>
|
||||
<para>
|
||||
This section will describe the basics of the Boost.Jam language—
|
||||
just enough for writing Jamfiles. For more information, please see the
|
||||
<link linkend="bbv2.jam">Boost.Jam</link> documentation.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Rules are defined by specifying the rule name, the parameter names,
|
||||
and the allowed size of the list value for each parameter.
|
||||
<programlisting>
|
||||
<link linkend="bbv2.jam">Boost.Jam</link> has an interpreted, procedural
|
||||
language. On the lowest level, a <link linkend="bbv2.jam">Boost.Jam
|
||||
</link> program consists of variables and <indexterm><primary>rule
|
||||
</primary></indexterm> <firstterm>rules</firstterm> (Jam term for
|
||||
function). They are grouped into modules—there is one global
|
||||
module and a number of named modules. Besides that, a <link linkend=
|
||||
"bbv2.jam">Boost.Jam</link> program contains classes and class
|
||||
instances.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Syntantically, a <link linkend="bbv2.jam">Boost.Jam</link> program
|
||||
consists of two kind of elements—keywords (which have a special
|
||||
meaning to <link linkend="bbv2.jam">Boost.Jam</link>) and literals.
|
||||
Consider this code:
|
||||
<programlisting>
|
||||
a = b ;
|
||||
</programlisting>
|
||||
which assigns the value <literal>b</literal> to the variable <literal>a
|
||||
</literal>. Here, <literal>=</literal> and <literal>;</literal> are
|
||||
keywords, while <literal>a</literal> and <literal>b</literal> are
|
||||
literals.
|
||||
<warning>
|
||||
<para>
|
||||
All syntax elements, even keywords, must be separated by spaces. For
|
||||
example, omitting the space character before <literal>;</literal>
|
||||
will lead to a syntax error.
|
||||
</para>
|
||||
</warning>
|
||||
If you want to use a literal value that is the same as some keyword, the
|
||||
value can be quoted:
|
||||
<programlisting>
|
||||
a = "=" ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
All variables in <link linkend="bbv2.jam">Boost.Jam</link> have the same
|
||||
type—list of strings. To define a variable one assigns a value to
|
||||
it, like in the previous example. An undefined variable is the same as a
|
||||
variable with an empty value. Variables can be accessed using the
|
||||
<code>$(<replaceable>variable</replaceable>)</code> syntax. For example:
|
||||
<programlisting>
|
||||
a = $(b) $(c) ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Rules are defined by specifying the rule name, the parameter names, and
|
||||
the allowed value list size for each parameter.
|
||||
<programlisting>
|
||||
rule <replaceable>example</replaceable>
|
||||
(
|
||||
<replaceable>parameter1</replaceable> :
|
||||
<replaceable>parameter2 ?</replaceable> :
|
||||
<replaceable>parameter3 +</replaceable> :
|
||||
<replaceable>parameter4 *</replaceable>
|
||||
)
|
||||
{
|
||||
// body
|
||||
}</programlisting>
|
||||
(
|
||||
<replaceable>parameter1</replaceable> :
|
||||
<replaceable>parameter2 ?</replaceable> :
|
||||
<replaceable>parameter3 +</replaceable> :
|
||||
<replaceable>parameter4 *</replaceable>
|
||||
)
|
||||
{
|
||||
# rule body
|
||||
}
|
||||
</programlisting>
|
||||
When this rule is called, the list passed as the first argument must
|
||||
have exactly one value. The list passed as the second argument can
|
||||
either have one value of be empty. The two remaining arguments can be
|
||||
arbitrarily long, but the third argument may not be empty.
|
||||
</para>
|
||||
|
||||
<para>The overview of <link linkend="bbv2.jam">Boost.Jam</link> language
|
||||
statements is given below:
|
||||
<programlisting>
|
||||
<para>
|
||||
The overview of <link linkend="bbv2.jam">Boost.Jam</link> language
|
||||
statements is given below:
|
||||
<programlisting>
|
||||
helper 1 : 2 : 3 ;
|
||||
x = [ helper 1 : 2 : 3 ] ;</programlisting>
|
||||
This code calls the named rule with the specified arguments. When the
|
||||
result of the call must be used inside some expression, you need to add
|
||||
brackets around the call, like shown on the second line.
|
||||
<programlisting>
|
||||
if cond { statements } [ else { statements } ]</programlisting>
|
||||
This is a regular if-statement. The condition is composed of:
|
||||
<itemizedlist>
|
||||
<listitem><para>Literals (true if at least one string is not empty)</para></listitem>
|
||||
<listitem><para>Comparisons: <code>a
|
||||
<replaceable>operator</replaceable> b</code> where
|
||||
<replaceable>operator</replaceable> is one of <code>=</code>,
|
||||
<code>!=</code>, <code><</code>, <code>></code>,
|
||||
<code><=</code>, <code>>=</code>. The comparison is done
|
||||
pairwise between each string in the left and the right arguments.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem><para>Logical operations: <code>! a</code>, <code>a &&
|
||||
b</code>, <code>a || b</code></para></listitem>
|
||||
<listitem><para>Grouping: <code>( cond )</code></para></listitem>
|
||||
</itemizedlist>
|
||||
<programlisting>
|
||||
for var in list { statements }</programlisting>
|
||||
Executes statements for each element in list, setting the variable
|
||||
<varname>var</varname> to the element value.
|
||||
<programlisting>
|
||||
while cond { statements }</programlisting>
|
||||
Repeatedly execute statements while cond remains true upon entry.
|
||||
<programlisting>
|
||||
x = [ helper 1 : 2 : 3 ] ;
|
||||
</programlisting>
|
||||
This code calls the named rule with the specified arguments. When the
|
||||
result of the call must be used inside some expression, you need to add
|
||||
brackets around the call, like shown on the second line.
|
||||
<programlisting>
|
||||
if cond { statements } [ else { statements } ]
|
||||
</programlisting>
|
||||
This is a regular if-statement. The condition is composed of:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
Literals (true if at least one string is not empty)
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Comparisons: <code>a <replaceable>operator</replaceable> b</code>
|
||||
where <replaceable>operator</replaceable> is one of
|
||||
<code>=</code>, <code>!=</code>, <code><</code>,
|
||||
<code>></code>, <code><=</code> or <code>>=</code>. The
|
||||
comparison is done pairwise between each string in the left and
|
||||
the right arguments.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Logical operations: <code>! a</code>, <code>a && b</code>,
|
||||
<code>a || b</code>
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Grouping: <code>( cond )</code>
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<programlisting>
|
||||
for var in list { statements }
|
||||
</programlisting>
|
||||
Executes statements for each element in list, setting the variable
|
||||
<varname>var</varname> to the element value.
|
||||
<programlisting>
|
||||
while cond { statements }
|
||||
</programlisting>
|
||||
Repeatedly execute statements while cond remains true upon entry.
|
||||
<programlisting>
|
||||
return values ;
|
||||
</programlisting>This statement should be used only inside a
|
||||
rule and assigns <code>values</code> to the return value of the
|
||||
rule.
|
||||
<warning><para>
|
||||
The <code>return</code> statement does not exit the rule. For example:
|
||||
<programlisting>
|
||||
</programlisting>
|
||||
This statement should be used only inside a rule and assigns
|
||||
<code>values</code> to the return value of the rule.
|
||||
<warning>
|
||||
<para>
|
||||
The <code>return</code> statement does not exit the rule. For
|
||||
example:
|
||||
<programlisting>
|
||||
rule test ( )
|
||||
{
|
||||
if 1 = 1 {
|
||||
if 1 = 1
|
||||
{
|
||||
return "reasonable" ;
|
||||
}
|
||||
return "strange" ;
|
||||
}</programlisting> will return <literal>strange</literal>, not
|
||||
<literal>reasonable</literal>.
|
||||
</para></warning>
|
||||
|
||||
<programlisting>
|
||||
}
|
||||
</programlisting>
|
||||
will return <literal>strange</literal>, not
|
||||
<literal>reasonable</literal>.
|
||||
</para>
|
||||
</warning>
|
||||
<programlisting>
|
||||
import <replaceable>module</replaceable> ;
|
||||
import <replaceable>module</replaceable> : <replaceable>rule</replaceable> ;</programlisting>
|
||||
The first form imports the specified bjam module. All rules from
|
||||
that module are made available using the qualified name:
|
||||
<code><replaceable>module</replaceable>.<replaceable>rule</replaceable></code>.
|
||||
The second form imports the specified rules only, and they can be called
|
||||
using unqualified names.
|
||||
import <replaceable>module</replaceable> : <replaceable>rule</replaceable> ;
|
||||
</programlisting>
|
||||
The first form imports the specified bjam module. All rules from that
|
||||
module are made available using the qualified name: <code><replaceable>
|
||||
module</replaceable>.<replaceable>rule</replaceable></code>. The second
|
||||
form imports the specified rules only, and they can be called using
|
||||
unqualified names.
|
||||
</para>
|
||||
|
||||
<para id="bbv2.advanced.jam_language.actions">
|
||||
Sometimes, you'd need to specify the actual command lines to be used
|
||||
when creating targets. In jam language, you use named actions to do this.
|
||||
For example:
|
||||
when creating targets. In jam language, you use named actions to do
|
||||
this. For example:
|
||||
<programlisting>
|
||||
actions create-file-from-another
|
||||
{
|
||||
create-file-from-another $(<) $(>)
|
||||
}
|
||||
</programlisting>
|
||||
This specifies a named action called
|
||||
<literal>create-file-from-another</literal>. The text inside braces is
|
||||
the command to invoke. The <literal>$(<)</literal> variable will be
|
||||
expanded to a list of generated files, and the
|
||||
<literal>$(>)</literal> variable will be expanded to a list of
|
||||
source files.
|
||||
This specifies a named action called <literal>
|
||||
create-file-from-another</literal>. The text inside braces is the
|
||||
command to invoke. The <literal>$(<)</literal> variable will be
|
||||
expanded to a list of generated files, and the <literal>$(>)
|
||||
</literal> variable will be expanded to a list of source files.
|
||||
</para>
|
||||
|
||||
<para>To flexibly adjust command line, you can define a rule with the same
|
||||
name as the action, and taking three parameters -- targets, sources and
|
||||
properties. For example:
|
||||
<para>
|
||||
To flexibly adjust the command line, you can define a rule with the same
|
||||
name as the action and taking three parameters -- targets, sources and
|
||||
properties. For example:
|
||||
<programlisting>
|
||||
rule create-file-from-another ( targets * : sources * : properties * )
|
||||
{
|
||||
@@ -227,18 +279,18 @@ actions create-file-from-another
|
||||
create-file-from-another $(OPTIONS) $(<) $(>)
|
||||
}
|
||||
</programlisting>
|
||||
In this example, the rule checks if certain build property is specified.
|
||||
If so, it sets variable <varname>OPIONS</varname> that is then used inside
|
||||
the action. Note that the variables set "on a target" will be visible only
|
||||
inside actions building that target, not globally. Were they set globally,
|
||||
using variable named <varname>OPTIONS</varname> in two unrelated actions
|
||||
would be impossible.
|
||||
In this example, the rule checks if certain build property is specified.
|
||||
If so, it sets variable <varname>OPIONS</varname> that is then used
|
||||
inside the action. Note that the variables set "on a target" will be
|
||||
visible only inside actions building that target, not globally. Were
|
||||
they set globally, using variable named <varname>OPTIONS</varname> in
|
||||
two unrelated actions would be impossible.
|
||||
</para>
|
||||
|
||||
<para>More details can be found in Jam reference,
|
||||
<xref linkend="jam.language.rules"/>
|
||||
<para>
|
||||
More details can be found in Jam reference, <xref
|
||||
linkend="jam.language.rules"/>.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="bbv2.advanced.configuration">
|
||||
@@ -265,7 +317,7 @@ using <replaceable>tool-name</replaceable> ;
|
||||
default settings. For example, it will use the <command>gcc</command>
|
||||
executable found in the <envar>PATH</envar>, or look in some known
|
||||
installation locations. In most cases, this strategy works automatically.
|
||||
In case you have several versions of a compiler, it's installed in some
|
||||
In case you have several versions of a compiler, it is installed in some
|
||||
unusual location, or you need to tweak its configuration, you'll need to
|
||||
pass additional parameters to the <functionname>using</functionname> rule.
|
||||
The parameters to <functionname>using</functionname> can be different for
|
||||
@@ -310,39 +362,39 @@ bjam --help <replaceable>tool-name</replaceable>.init
|
||||
using msvc : 7.1 ;
|
||||
using gcc ;
|
||||
</programlisting>
|
||||
If the compiler can be found in the <envar>PATH</envar> but only by a
|
||||
nonstandard name, you can just supply that name:
|
||||
If the compiler can be found in the <envar>PATH</envar> but only by a
|
||||
nonstandard name, you can just supply that name:
|
||||
<programlisting>
|
||||
using gcc : : g++-3.2 ;
|
||||
</programlisting>
|
||||
Otherwise, it might be necessary to supply the complete path to the
|
||||
compiler executable:
|
||||
Otherwise, it might be necessary to supply the complete path to the
|
||||
compiler executable:
|
||||
<programlisting>
|
||||
using msvc : : "Z:/Programs/Microsoft Visual Studio/vc98/bin/cl" ;
|
||||
</programlisting>
|
||||
Some Boost.Build toolsets will use that path to take additional
|
||||
actions required before invoking the compiler, such as calling
|
||||
vendor-supplied scripts to set up its required environment variables.
|
||||
When compiler executables for C and C++ are different, path to the C++
|
||||
compiler executable must be specified. The “invocation command”
|
||||
can be any command allowed by the operating system. For example:
|
||||
Some Boost.Build toolsets will use that path to take additional actions
|
||||
required before invoking the compiler, such as calling vendor-supplied
|
||||
scripts to set up its required environment variables. When compiler
|
||||
executables for C and C++ are different, path to the C++ compiler
|
||||
executable must be specified. The “invocation command” can
|
||||
be any command allowed by the operating system. For example:
|
||||
<programlisting>
|
||||
using msvc : : echo Compiling && foo/bar/baz/cl ;
|
||||
</programlisting>
|
||||
will work.
|
||||
will work.
|
||||
</para>
|
||||
|
||||
<para>To configure several versions of a toolset, simply invoke
|
||||
the <functionname>using</functionname> rule multiple times:
|
||||
<para>
|
||||
To configure several versions of a toolset, simply invoke the
|
||||
<functionname>using</functionname> rule multiple times:
|
||||
<programlisting>
|
||||
using gcc : 3.3 ;
|
||||
using gcc : 3.4 : g++-3.4 ;
|
||||
using gcc : 3.2 : g++-3.2 ;
|
||||
</programlisting>
|
||||
Note that in the first call to
|
||||
<functionname>using</functionname>, the compiler found in the
|
||||
<envar>PATH</envar> will be used, and there's no need to
|
||||
explicitly specify the command.
|
||||
Note that in the first call to <functionname>using</functionname>, the
|
||||
compiler found in the <envar>PATH</envar> will be used, and there is no
|
||||
need to explicitly specify the command.
|
||||
</para>
|
||||
|
||||
<para>As shown above, both the <parameter
|
||||
@@ -664,34 +716,31 @@ exe b : [ glob *.cpp ] ; # all .cpp files in this directory are sources
|
||||
|
||||
<para>
|
||||
<!-- use "project-id" here? -->
|
||||
The list of sources can also refer to other main targets.
|
||||
Targets in the same project can be referred to by name, while
|
||||
targets in other projects must be qualified with a directory or a
|
||||
symbolic project name. The directory/project name is separated from
|
||||
the target name by a double forward slash. There's no special syntax to
|
||||
distinguish the directory name from the project name—the part before
|
||||
the double slash is first looked up as project name, and then as directory
|
||||
name. For example:
|
||||
The list of sources can also refer to other main targets. Targets in
|
||||
the same project can be referred to by name, while targets in other
|
||||
projects must be qualified with a directory or a symbolic project
|
||||
name. The directory/project name is separated from the target name by
|
||||
a double forward slash. There is no special syntax to distinguish the
|
||||
directory name from the project name—the part before the double
|
||||
slash is first looked up as project name, and then as directory name.
|
||||
For example:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
lib helper : helper.cpp ;
|
||||
exe a : a.cpp helper ;
|
||||
# Since all project ids start with slash, ".." is directory name.
|
||||
# Since all project ids start with slash, ".." is a directory name.
|
||||
exe b : b.cpp ..//utils ;
|
||||
exe c : c.cpp /boost/program_options//program_options ;
|
||||
</programlisting>
|
||||
<para>
|
||||
The first exe uses the library defined in the same
|
||||
project. The second one uses some target (most likely library)
|
||||
defined by Jamfile one level higher. Finally, the third target
|
||||
uses some <ulink url="http://boost.org">C++ Boost</ulink>
|
||||
library, referring to it by absolute symbolic name. More
|
||||
information about target references can be found in <xref
|
||||
linkend="bbv2.tutorial.libs"/> and <xref
|
||||
The first exe uses the library defined in the same project. The second
|
||||
one uses some target (most likely a library) defined by a Jamfile one
|
||||
level higher. Finally, the third target uses a <ulink url=
|
||||
"http://boost.org">C++ Boost</ulink> library, referring to it using
|
||||
its absolute symbolic name. More information about target references
|
||||
can be found in <xref linkend="bbv2.tutorial.libs"/> and <xref
|
||||
linkend="bbv2.reference.ids"/>.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="bbv2.advanced.targets.requirements">
|
||||
|
||||
@@ -2,191 +2,232 @@
|
||||
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
|
||||
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd">
|
||||
|
||||
<chapter id="bbv2.faq">
|
||||
<title>Frequently Asked Questions</title>
|
||||
<chapter id="bbv2.faq">
|
||||
<title>Frequently Asked Questions</title>
|
||||
|
||||
<section>
|
||||
<title>
|
||||
How do I get the current value of feature in Jamfile?
|
||||
</title>
|
||||
<section>
|
||||
<title>
|
||||
How do I get the current value of feature in Jamfile?
|
||||
</title>
|
||||
|
||||
<para>
|
||||
This is not possible, since Jamfile does not have "current" value of any
|
||||
feature, be it toolset, build variant or anything else. For a single invocation of
|
||||
<filename>bjam</filename>, any given main target can be built with several property sets.
|
||||
For example, user can request two build variants on the command line. Or one library
|
||||
is built as shared when used from one application, and as static when used from another.
|
||||
Obviously, Jamfile is read only once, so generally, there's no single value of a feature
|
||||
you can access in Jamfile.
|
||||
</para>
|
||||
<para>
|
||||
This is not possible, since Jamfile does not have "current" value of any
|
||||
feature, be it toolset, build variant or anything else. For a single
|
||||
invocation of <filename>bjam</filename>, any given main target can be
|
||||
built with several property sets. For example, user can request two build
|
||||
variants on the command line. Or one library is built as shared when used
|
||||
from one application, and as static when used from another. Each Jamfile
|
||||
is read only once so generally there is no single value of a feature you
|
||||
can access in Jamfile.
|
||||
</para>
|
||||
|
||||
<para>A feature has a specific value only when building a target, and there are two ways how you
|
||||
can use that value:</para>
|
||||
<itemizedlist>
|
||||
<listitem><simpara>Use conditional requirements or indirect conditional requirements. See
|
||||
<xref linkend="bbv2.advanced.targets.requirements.conditional"/>.</simpara>
|
||||
</listitem>
|
||||
<listitem>Define a custom generator and a custom main target type. The custom generator can do arbitrary processing
|
||||
or properties. See the <xref linkend="bbv2.extender">extender manual</xref>.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
A feature has a specific value only when building a target, and there are
|
||||
two ways you can use that value:
|
||||
</para>
|
||||
|
||||
</section>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<simpara>
|
||||
Use conditional requirements or indirect conditional requirements. See
|
||||
<xref linkend="bbv2.advanced.targets.requirements.conditional"/>.
|
||||
</simpara>
|
||||
</listitem>
|
||||
<listitem>
|
||||
Define a custom generator and a custom main target type. The custom
|
||||
generator can do arbitrary processing or properties. See the <xref
|
||||
linkend="bbv2.extender">extender manual</xref>.
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>
|
||||
I'm getting "Duplicate name of actual target" error. What
|
||||
does it mean?
|
||||
</title>
|
||||
|
||||
<para>
|
||||
The most likely case is that you're trying to
|
||||
compile the same file twice, with almost the same,
|
||||
but differing properties. For example:
|
||||
<section>
|
||||
<title>
|
||||
I am getting a "Duplicate name of actual target" error. What does that
|
||||
mean?
|
||||
</title>
|
||||
|
||||
<para>
|
||||
The most likely case is that you are trying to compile the same file
|
||||
twice, with almost the same, but differing properties. For example:
|
||||
<programlisting>
|
||||
exe a : a.cpp : <include>/usr/local/include ;
|
||||
exe b : a.cpp ;
|
||||
</programlisting>
|
||||
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The above snippet requires two different compilations
|
||||
of 'a.cpp', which differ only in 'include' property.
|
||||
Since the 'include' property is free, Boost.Build
|
||||
can't generate two objects files into different directories.
|
||||
On the other hand, it's dangerous to compile the file only
|
||||
once -- maybe you really want to compile with different
|
||||
includes.
|
||||
The above snippet requires two different compilations of
|
||||
<code>a.cpp</code>, which differ only in their <literal>include</literal>
|
||||
property. Since the <literal>include</literal> feature is declared as
|
||||
<literal>free</literal> Boost.Build does not create a separate build
|
||||
directory for each of its values and those two builds would both produce
|
||||
object files generated in the same build directory. Ignoring this and
|
||||
compiling the file only once would be dangerous as different includes
|
||||
could potentially cause completely different code to be compiled.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To solve this issue, you need to decide if file should
|
||||
be compiled once or twice.</para>
|
||||
To solve this issue, you need to decide if the file should be compiled
|
||||
once or twice.
|
||||
</para>
|
||||
|
||||
<orderedlist>
|
||||
<listitem>
|
||||
<para>Two compile file only once, make sure that properties
|
||||
are the same:
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
To compile the file only once, make sure that properties are the same
|
||||
for both target requests:
|
||||
<programlisting>
|
||||
exe a : a.cpp : <include>/usr/local/include ;
|
||||
exe b : a.cpp : <include>/usr/local/include ;
|
||||
</programlisting></para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
If changing the properties is not desirable, for example
|
||||
if 'a' and 'b' target have other sources which need
|
||||
specific properties, separate 'a.cpp' into it's own target:
|
||||
|
||||
</programlisting>
|
||||
or:
|
||||
<programlisting>
|
||||
obj a_obj : a.cpp : <include>/usr/local/include ;
|
||||
exe a : a_obj ;
|
||||
</programlisting></para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
To compile file twice, you can make the object file local
|
||||
to the main target:
|
||||
|
||||
alias a-with-include : a.cpp : <include>/usr/local/include ;
|
||||
exe a : a-with-include ;
|
||||
exe b : a-with-include ;
|
||||
</programlisting>
|
||||
or if you want the <literal>includes</literal> property not to affect
|
||||
how any other sources added for the built <code>a</code> and
|
||||
<code>b</code> executables would be compiled:
|
||||
<programlisting>
|
||||
exe a : [ obj a_obj : a.cpp ] : <include>/usr/local/include ;
|
||||
obj a-obj : a.cpp : <include>/usr/local/include ;
|
||||
exe a : a-obj ;
|
||||
exe b : a-obj ;
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Note that in both of these cases the <literal>include</literal>
|
||||
property will be applied only for building these object files and not
|
||||
any other sources that might be added for targets <code>a</code> and
|
||||
<code>b</code>.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
To compile the file twice, you can tell Boost.Build to compile it to
|
||||
two separate object files like so:
|
||||
<programlisting>
|
||||
obj a_obj : a.cpp : <include>/usr/local/include ;
|
||||
obj b_obj : a.cpp ;
|
||||
exe a : a_obj ;
|
||||
exe b : b_obj ;
|
||||
</programlisting>
|
||||
or you can make the object file targets local to the main target:
|
||||
<programlisting>
|
||||
exe a : [ obj a_obj : a.cpp : <include>/usr/local/include ] ;
|
||||
exe b : [ obj a_obj : a.cpp ] ;
|
||||
</programlisting></para></listitem>
|
||||
</programlisting>
|
||||
which will cause Boost.Build to actually change the generated object
|
||||
file names a bit for you and thus avoid any conflicts.
|
||||
</para>
|
||||
<para>
|
||||
Note that in both of these cases the <literal>include</literal>
|
||||
property will be applied only for building these object files and not
|
||||
any other sources that might be added for targets <code>a</code> and
|
||||
<code>b</code>.
|
||||
</para>
|
||||
</listitem>
|
||||
</orderedlist>
|
||||
|
||||
</orderedlist>
|
||||
<para>
|
||||
A good question is why Boost.Build can not use some of the above
|
||||
approaches automatically. The problem is that such magic would only help
|
||||
in half of the cases, while in the other half it would be silently doing
|
||||
the wrong thing. It is simpler and safer to ask the user to clarify his
|
||||
intention in such cases.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<para>
|
||||
A good question is why Boost.Build can't use some of the above
|
||||
approaches automatically. The problem is that such magic would
|
||||
require additional implementation complexities and would only
|
||||
help in half of the cases, while in other half we'd be silently
|
||||
doing the wrong thing. It's simpler and safe to ask user to
|
||||
clarify his intention in such cases.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="bbv2.faq.envar">
|
||||
<title>
|
||||
<section id="bbv2.faq.envar">
|
||||
<title>
|
||||
Accessing environment variables
|
||||
</title>
|
||||
</title>
|
||||
|
||||
<para>
|
||||
<para>
|
||||
Many users would like to use environment variables in Jamfiles, for
|
||||
example, to control location of external libraries. In many cases you
|
||||
better declare those external libraries in the site-config.jam file, as
|
||||
documented in the <link linkend="bbv2.recipies.site-config">recipes
|
||||
section</link>. However, if the users already have the environment variables set
|
||||
up, it's not convenient to ask them to set up site-config.jam files as
|
||||
well, and using environment variables might be reasonable.
|
||||
example, to control the location of external libraries. In many cases it
|
||||
is better to declare those external libraries in the site-config.jam file,
|
||||
as documented in the <link linkend="bbv2.recipies.site-config">recipes
|
||||
section</link>. However, if the users already have the environment
|
||||
variables set up, it may not be convenient for them to set up their
|
||||
site-config.jam files as well and using the environment variables might be
|
||||
reasonable.
|
||||
</para>
|
||||
|
||||
<para>In Boost.Build V2, each Jamfile is a separate namespace, and the
|
||||
variables defined in environment is imported into the global
|
||||
namespace. Therefore, to access environment variable from Jamfile, you'd
|
||||
need the following code:
|
||||
<para>
|
||||
Boost.Jam automatically imports all environment variables into its
|
||||
built-in .ENVIRON module so user can read them from there directly or by
|
||||
using the helper os.environ rule. For example:
|
||||
<programlisting>
|
||||
import os ;
|
||||
local unga-unga = [ os.environ UNGA_UNGA ] ;
|
||||
ECHO $(unga-unga) ;
|
||||
</programlisting>
|
||||
or a bit more realistic:
|
||||
<programlisting>
|
||||
import os ;
|
||||
local SOME_LIBRARY_PATH = [ os.environ SOME_LIBRARY_PATH ] ;
|
||||
exe a : a.cpp : <include>$(SOME_LIBRARY_PATH) ;
|
||||
</programlisting>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>
|
||||
How to control properties order?
|
||||
</title>
|
||||
|
||||
<para>For internal reasons, Boost.Build sorts all the properties
|
||||
alphabetically. This means that if you write:
|
||||
<programlisting>
|
||||
exe a : a.cpp : <include>b <include>a ;
|
||||
</programlisting>
|
||||
then the command line with first mention the "a" include directory, and
|
||||
then "b", even though they are specified in the opposite order. In most
|
||||
cases, the user doesn't care. But sometimes the order of includes, or
|
||||
other properties, is important. For example, if one uses both the C++
|
||||
Boost library and the "boost-sandbox" (libraries in development), then
|
||||
include path for boost-sandbox must come first, because some headers may
|
||||
override ones in C++ Boost. For such cases, a special syntax is
|
||||
provided:
|
||||
<programlisting>
|
||||
exe a : a.cpp : <include>a&&b ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>The <code>&&</code> symbols separate values of an
|
||||
property, and specify that the order of the values should be preserved. You
|
||||
are advised to use this feature only when the order of properties really
|
||||
matters, and not as a convenient shortcut. Using it everywhere might
|
||||
negatively affect performance.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>
|
||||
How to control the library order on Unix?
|
||||
How to control properties order?
|
||||
</title>
|
||||
|
||||
<para>On the Unix-like operating systems, the order in which static
|
||||
libraries are specified when invoking the linker is important, because by
|
||||
default, the linker uses one pass though the libraries list. Passing the
|
||||
libraries in the incorrect order will lead to a link error. Further, this
|
||||
behaviour is often used to make one library override symbols from
|
||||
another. So, sometimes it's necessary to force specific order of
|
||||
libraries.
|
||||
<para>
|
||||
For internal reasons, Boost.Build sorts all the properties alphabetically.
|
||||
This means that if you write:
|
||||
<programlisting>
|
||||
exe a : a.cpp : <include>b <include>a ;
|
||||
</programlisting>
|
||||
then the command line with first mention the <code>a</code> include
|
||||
directory, and then <code>b</code>, even though they are specified in the
|
||||
opposite order. In most cases, the user does not care. But sometimes the
|
||||
order of includes, or other properties, is important. For such cases, a
|
||||
special syntax is provided:
|
||||
<programlisting>
|
||||
exe a : a.cpp : <include>a&&b ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>Boost.Build tries to automatically compute the right order. The
|
||||
primary rule is that if library a "uses" library b, then library a will
|
||||
appear on the command line before library b. Library a is considered to
|
||||
use b is b is present either in the sources of a or in its
|
||||
requirements. To explicitly specify the use relationship one can use the
|
||||
<use> feature. For example, both of the following lines will cause
|
||||
a to appear before b on the command line:
|
||||
<para>
|
||||
The <code>&&</code> symbols separate property values and specify
|
||||
that their order should be preserved. You are advised to use this feature
|
||||
only when the order of properties really matters and not as a convenient
|
||||
shortcut. Using it everywhere might negatively affect performance.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>
|
||||
How to control the library linking order on Unix?
|
||||
</title>
|
||||
|
||||
<para>
|
||||
On Unix-like operating systems, the order in which static libraries are
|
||||
specified when invoking the linker is important, because by default, the
|
||||
linker uses one pass though the libraries list. Passing the libraries in
|
||||
the incorrect order will lead to a link error. Further, this behaviour is
|
||||
often used to make one library override symbols from another. So,
|
||||
sometimes it is necessary to force specific library linking order.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Boost.Build tries to automatically compute the right order. The primary
|
||||
rule is that if library <code>a</code> "uses" library <code>b</code>, then
|
||||
library <code>a</code> will appear on the command line before library
|
||||
<code>b</code>. Library <code>a</code> is considered to use <code>b</code>
|
||||
if <code>b</code> is present either in the <code>a</code> library's
|
||||
sources or its usage is listed in its requirements. To explicitly specify
|
||||
the <literal>use</literal> relationship one can use the
|
||||
<literal><use></literal> feature. For example, both of the following
|
||||
lines will cause <code>a</code> to appear before <code>b</code> on the
|
||||
command line:
|
||||
<programlisting>
|
||||
lib a : a.cpp b ;
|
||||
lib a : a.cpp : <use>b ;
|
||||
@@ -194,21 +235,22 @@ lib a : a.cpp : <use>b ;
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The same approach works for searched libraries, too:
|
||||
The same approach works for searched libraries as well:
|
||||
<programlisting>
|
||||
lib z ;
|
||||
lib png : : <use>z ;
|
||||
exe viewer : viewer png z ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="bbv2.faq.external">
|
||||
<title>Can I get output of external program as a variable in a Jamfile?
|
||||
<title>
|
||||
Can I get capture external program output using a Boost.Jam variable?
|
||||
</title>
|
||||
|
||||
<para>The <code>SHELL</code> builtin can be used for the purpose:
|
||||
<para>
|
||||
The <literal>SHELL</literal> builtin rule may be used for this purpose:
|
||||
<programlisting>
|
||||
local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
|
||||
</programlisting>
|
||||
@@ -216,7 +258,8 @@ local gtk_includes = [ SHELL "gtk-config --cflags" ] ;
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>How to get the project root (a.k.a. Jamroot.jam) location?
|
||||
<title>
|
||||
How to get the project root (a.k.a. Jamroot) location?
|
||||
</title>
|
||||
|
||||
<para>
|
||||
@@ -230,18 +273,20 @@ path-constant TOP : . ;
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>How to change compilation flags for one file?
|
||||
<title>
|
||||
How to change compilation flags for one file?
|
||||
</title>
|
||||
|
||||
<para>If one file must be compiled with special options, you need to
|
||||
explicitly declare an <code>obj</code> target for that file and then use
|
||||
that target in your <code>exe</code> or <code>lib</code> target:
|
||||
<para>
|
||||
If one file must be compiled with special options, you need to explicitly
|
||||
declare an <code>obj</code> target for that file and then use that target
|
||||
in your <code>exe</code> or <code>lib</code> target:
|
||||
<programlisting>
|
||||
exe a : a.cpp b ;
|
||||
obj b : b.cpp : <optimization>off ;
|
||||
</programlisting>
|
||||
Of course you can use other properties, for example to specify specific
|
||||
compiler options:
|
||||
C/C++ compiler options:
|
||||
<programlisting>
|
||||
exe a : a.cpp b ;
|
||||
obj b : b.cpp : <cflags>-g ;
|
||||
@@ -252,149 +297,162 @@ obj b : b.cpp : <cflags>-g ;
|
||||
exe a : a.cpp b ;
|
||||
obj b : b.cpp : <variant>release:<optimization>off ;
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="bbv2.faq.dll-path">
|
||||
<title>Why are the <code>dll-path</code> and
|
||||
<code>hardcode-dll-paths</code> properties useful?
|
||||
<title>
|
||||
Why are the <literal>dll-path</literal> and <literal>hardcode-dll-paths
|
||||
</literal> properties useful?
|
||||
</title>
|
||||
|
||||
<para>(This entry is specific to Unix system.)Before answering the
|
||||
questions, let's recall a few points about shared libraries. Shared
|
||||
libraries can be used by several applications, or other libraries,
|
||||
without physically including the library in the application. This can
|
||||
greatly decrease the total size of applications. It's also possible to
|
||||
upgrade a shared library when the application is already
|
||||
installed. Finally, shared linking can be faster.
|
||||
</para>
|
||||
|
||||
<para>However, the shared library must be found when the application is
|
||||
started. The dynamic linker will search in a system-defined list of
|
||||
paths, load the library and resolve the symbols. Which means that you
|
||||
should either change the system-defined list, given by the
|
||||
<envar>LD_LIBRARY_PATH</envar> environment variable, or install the
|
||||
libraries to a system location. This can be inconvenient when
|
||||
developing, since the libraries are not yet ready to be installed, and
|
||||
cluttering system paths is undesirable. Luckily, on Unix there's another
|
||||
way.
|
||||
</para>
|
||||
|
||||
<para>An executable can include a list of additional library paths, which
|
||||
will be searched before system paths. This is excellent for development,
|
||||
because the build system knows the paths to all libraries and can include
|
||||
them in executables. That's done when the <code>hardcode-dll-paths</code>
|
||||
feature has the <literal>true</literal> value, which is the
|
||||
default. When the executables should be installed, the story is
|
||||
different.
|
||||
<note>
|
||||
<para>
|
||||
This entry is specific to Unix systems.
|
||||
</para>
|
||||
</note>
|
||||
<para>
|
||||
Before answering the questions, let us recall a few points about shared
|
||||
libraries. Shared libraries can be used by several applications, or other
|
||||
libraries, without physically including the library in the application
|
||||
which can greatly decrease the total application size. It is also possible
|
||||
to upgrade a shared library when the application is already installed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Obviously, installed executable should not hardcode paths to your
|
||||
development tree. (The <code>stage</code> rule explicitly disables the
|
||||
<code>hardcode-dll-paths</code> feature for that reason.) However, you
|
||||
can use the <code>dll-path</code> feature to add explicit paths
|
||||
However, in order for application depending on shared libraries to be
|
||||
started the OS may need to find the shared library when the application is
|
||||
started. The dynamic linker will search in a system-defined list of paths,
|
||||
load the library and resolve the symbols. Which means that you should
|
||||
either change the system-defined list, given by the <envar>LD_LIBRARY_PATH
|
||||
</envar> environment variable, or install the libraries to a system
|
||||
location. This can be inconvenient when developing, since the libraries
|
||||
are not yet ready to be installed, and cluttering system paths may be
|
||||
undesirable. Luckily, on Unix there is another way.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An executable can include a list of additional library paths, which will
|
||||
be searched before system paths. This is excellent for development because
|
||||
the build system knows the paths to all libraries and can include them in
|
||||
the executables. That is done when the <literal>hardcode-dll-paths
|
||||
</literal> feature has the <literal>true</literal> value, which is the
|
||||
default. When the executables should be installed, the story is different.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Obviously, installed executable should not contain hardcoded paths to your
|
||||
development tree. <!-- Make the following parenthised sentence a footer
|
||||
note --> (The <literal>install</literal> rule explicitly disables the
|
||||
<literal>hardcode-dll-paths</literal> feature for that reason.) However,
|
||||
you can use the <literal>dll-path</literal> feature to add explicit paths
|
||||
manually. For example:
|
||||
<programlisting>
|
||||
stage installed : application : <dll-path>/usr/lib/snake
|
||||
<location>/usr/bin ;
|
||||
install installed : application : <dll-path>/usr/lib/snake
|
||||
<location>/usr/bin ;
|
||||
</programlisting>
|
||||
will allow the application to find libraries placed to
|
||||
<filename>/usr/lib/snake</filename>.
|
||||
will allow the application to find libraries placed in the <filename>
|
||||
/usr/lib/snake</filename> directory.
|
||||
</para>
|
||||
|
||||
<para>If you install libraries to a nonstandard location and add an
|
||||
explicit path, you get more control over libraries which will be used. A
|
||||
library of the same name in a system location will not be inadvertently
|
||||
used. If you install libraries to a system location and do not add any
|
||||
paths, the system administrator will have more control. Each library can
|
||||
be individually upgraded, and all applications will use the new library.
|
||||
<para>
|
||||
If you install libraries to a nonstandard location and add an explicit
|
||||
path, you get more control over libraries which will be used. A library of
|
||||
the same name in a system location will not be inadvertently used. If you
|
||||
install libraries to a system location and do not add any paths, the
|
||||
system administrator will have more control. Each library can be
|
||||
individually upgraded, and all applications will use the new library.
|
||||
</para>
|
||||
|
||||
<para>Which approach is best depends on your situation. If the libraries
|
||||
are relatively standalone and can be used by third party applications,
|
||||
they should be installed in the system location. If you have lots of
|
||||
libraries which can be used only by your application, it makes sense to
|
||||
install it to a nonstandard directory and add an explicit path, like the
|
||||
example above shows. Please also note that guidelines for different
|
||||
systems differ in this respect. The Debian guidelines prohibit any
|
||||
additional search paths, and Solaris guidelines suggest that they should
|
||||
<para>
|
||||
Which approach is best depends on your situation. If the libraries are
|
||||
relatively standalone and can be used by third party applications, they
|
||||
should be installed in the system location. If you have lots of libraries
|
||||
which can be used only by your application, it makes sense to install them
|
||||
to a nonstandard directory and add an explicit path, like the example
|
||||
above shows. Please also note that guidelines for different systems differ
|
||||
in this respect. For example, the Debian GNU guidelines prohibit any
|
||||
additional search paths while Solaris guidelines suggest that they should
|
||||
always be used.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section id="bbv2.recipies.site-config">
|
||||
<title>Targets in site-config.jam</title>
|
||||
|
||||
<para>It is desirable to declare standard libraries available on a
|
||||
given system. Putting target declaration in Jamfile is not really
|
||||
good, since locations of the libraries can vary. The solution is
|
||||
to declare the targets in site-config.jam:</para>
|
||||
<para>
|
||||
It is desirable to declare standard libraries available on a given system.
|
||||
Putting target declaration in a specific project's Jamfile is not really
|
||||
good, since locations of the libraries can vary between different
|
||||
development machines and then such declarations would need to be
|
||||
duplicated in different projects. The solution is to declare the targets
|
||||
in Boost.Build's <filename>site-config.jam</filename> configuration file:
|
||||
<programlisting>
|
||||
project site-config ;
|
||||
lib zlib : : <name>z ;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>Recall that both <filename>site-config.jam</filename> and
|
||||
<filename>user-config.jam</filename> are projects, and everything
|
||||
you can do in a Jamfile you can do in those files. So, you declare
|
||||
a project id and a target. Now, one can write:
|
||||
<para>
|
||||
Recall that both <filename>site-config.jam</filename> and
|
||||
<filename>user-config.jam</filename> are projects, and everything you can
|
||||
do in a Jamfile you can do in those files as well. So, you declare a
|
||||
project id and a target. Now, one can write:
|
||||
<programlisting>
|
||||
exe hello : hello.cpp /site-config//zlib ;
|
||||
</programlisting>
|
||||
in any Jamfile.</para>
|
||||
|
||||
in any Jamfile.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section id="bbv2.faq.header-only-libraries">
|
||||
<title>Header-only libraries</title>
|
||||
|
||||
<para>In modern C++, libraries often consist of just header files, without
|
||||
any source files to compile. To use such libraries, you need to add proper
|
||||
includes and, maybe, defines, to your project. But with large number of
|
||||
external libraries it becomes problematic to remember which libraries are
|
||||
header only, and which are "real" ones. However, with Boost.Build a
|
||||
header-only library can be declared as Boost.Build target and all
|
||||
dependents can use such library without remebering if it's header-only or not.
|
||||
</para>
|
||||
|
||||
<para>Header-only libraries are declared using the <code>alias</code> rule,
|
||||
that specifies only usage requirements, for example:
|
||||
<programlisting>
|
||||
alias mylib
|
||||
: # no sources
|
||||
: # no build requirements
|
||||
: # no default build
|
||||
: <include>whatever
|
||||
;
|
||||
</programlisting>
|
||||
The includes specified in usage requirements of <code>mylib</code> are
|
||||
automatically added to build properties of all dependents. The dependents
|
||||
need not care if <code>mylib</code> is header-only or not, and it's possible
|
||||
to later make <code>mylib</code> into a regular compiled library.
|
||||
<para>
|
||||
In modern C++, libraries often consist of just header files, without any
|
||||
source files to compile. To use such libraries, you need to add proper
|
||||
includes and possibly defines to your project. But with a large number of
|
||||
external libraries it becomes problematic to remember which libraries are
|
||||
header only, and which ones you have to link to. However, with Boost.Build
|
||||
a header-only library can be declared as Boost.Build target and all
|
||||
dependents can use such library without having to remeber whether it is a
|
||||
header-only library or not.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you already have proper usage requirements declared for project where
|
||||
header-only library is defined, you don't need to duplicate them for
|
||||
Header-only libraries may be declared using the <code>alias</code> rule,
|
||||
specifying their include path as a part of its usage requirements, for
|
||||
example:
|
||||
<programlisting>
|
||||
alias my-lib
|
||||
: # no sources
|
||||
: # no build requirements
|
||||
: # no default build
|
||||
: <include>whatever ;
|
||||
</programlisting>
|
||||
The includes specified in usage requirements of <code>my-lib</code> are
|
||||
automatically added to all of its dependants' build properties. The
|
||||
dependants need not care if <code>my-lib</code> is a header-only or not,
|
||||
and it is possible to later make <code>my-lib</code> into a regular
|
||||
compiled library without having to that its dependants' declarations.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you already have proper usage requirements declared for a project where
|
||||
a header-only library is defined, you do not need to duplicate them for
|
||||
the <code>alias</code> target:
|
||||
<programlisting>
|
||||
project my : usage-requirements <include>whatever ;
|
||||
alias mylib ;
|
||||
</programlisting>
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
</section>
|
||||
</chapter>
|
||||
|
||||
|
||||
</chapter>
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: nxml
|
||||
sgml-indent-data: t
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("userman.xml" "chapter")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
-->
|
||||
-->
|
||||
|
||||
@@ -420,41 +420,55 @@ path-constant DATA : data/a.txt ;
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
A feature that combines several low-level features, making
|
||||
it easy to request common build configurations.
|
||||
A feature combining several low-level features, making it easy to
|
||||
request common build configurations.
|
||||
</para>
|
||||
|
||||
<para><emphasis role="bold">Allowed values:</emphasis> <literal>debug</literal>, <literal>release</literal>,
|
||||
<literal>profile</literal>.</para>
|
||||
<para>
|
||||
<emphasis role="bold">Allowed values:</emphasis>
|
||||
<literal>debug</literal>, <literal>release</literal>,
|
||||
<literal>profile</literal>.
|
||||
</para>
|
||||
|
||||
<para>The value <literal>debug</literal> expands to</para>
|
||||
<para>
|
||||
The value <literal>debug</literal> expands to
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
<optimization>off <debug-symbols>on <inlining>off <runtime-debugging>on
|
||||
</programlisting>
|
||||
|
||||
<para>The value <literal>release</literal> expands to</para>
|
||||
<para>
|
||||
The value <literal>release</literal> expands to
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
<optimization>speed <debug-symbols>off <inlining>full <runtime-debugging>off
|
||||
</programlisting>
|
||||
|
||||
<para>The value <literal>profile</literal> expands to the same as
|
||||
<literal>release</literal>, plus:</para>
|
||||
<para>
|
||||
The value <literal>profile</literal> expands to the same as
|
||||
<literal>release</literal>, plus:
|
||||
</para>
|
||||
|
||||
<programlisting>
|
||||
<profiling>on <debug-symbols>on
|
||||
</programlisting>
|
||||
|
||||
<para>User can define his own build variants using the <code>variant</code> rule from the <code>common</code>
|
||||
module.</para>
|
||||
|
||||
<para><emphasis role="bold">Notee:</emphasis> Runtime
|
||||
debugging is on in debug builds to suit the expectations of
|
||||
people used to various IDEs.
|
||||
<!-- Define "runtime debugging." Why will those people expect it to be on in debug builds? -->
|
||||
<para>
|
||||
Users can define their own build variants using the
|
||||
<code>variant</code> rule from the <code>common</code> module.
|
||||
</para>
|
||||
</listitem></varlistentry>
|
||||
|
||||
<para>
|
||||
<emphasis role="bold">Note:</emphasis> Runtime debugging is on in
|
||||
debug builds to suit the expectations of people used to various
|
||||
IDEs.
|
||||
<!-- Define "runtime debugging". Why will those people expect it to
|
||||
be on in debug builds? -->
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="bbv2.advanced.builtins.features.link">
|
||||
<term><literal>link</literal></term>
|
||||
@@ -465,10 +479,11 @@ path-constant DATA : data/a.txt ;
|
||||
<literal>static</literal></para>
|
||||
|
||||
<simpara>
|
||||
A feature that controls how libraries are built.
|
||||
A feature controling how libraries are built.
|
||||
</simpara>
|
||||
|
||||
</listitem></varlistentry>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry id="bbv2.advanced.builtins.features.runtime-link">
|
||||
<indexterm><primary>runtime linking</primary></indexterm>
|
||||
@@ -720,7 +735,10 @@ path-constant DATA : data/a.txt ;
|
||||
<varlistentry><term><literal>instruction-set</literal></term>
|
||||
<indexterm><primary>instruction-set</primary></indexterm>
|
||||
<listitem>
|
||||
<para>Allowed values for this feature depend on used toolset.</para>
|
||||
<para>
|
||||
<emphasis role="bold">Allowed values:</emphasis> depend on the used
|
||||
toolset.
|
||||
</para>
|
||||
|
||||
<para>The <literal>instruction-set</literal> specifies for which
|
||||
specific instruction set the code should be generated. The
|
||||
@@ -751,6 +769,31 @@ path-constant DATA : data/a.txt ;
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry><term><literal>c++-template-depth</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
<emphasis role="bold">Allowed values:</emphasis> Any positive
|
||||
integer.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This feature allows configuring a C++ compiler with the maximal
|
||||
template instantiation depth parameter. Specific toolsets may or may
|
||||
not provide support for this feature depending on whether their
|
||||
compilers provide a corresponding command-line option.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<emphasis role="bold">Note:</emphasis> Due to some internal details
|
||||
in the current Boost Build implementation it is not possible to have
|
||||
features whose valid values are all positive integer. As a
|
||||
workaround a large set of allowed values has been defined for this
|
||||
feature and, if a different one is needed, user can easily add it by
|
||||
calling the feature.extend rule.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
</section>
|
||||
|
||||
@@ -970,9 +1013,9 @@ using msvc : &toolset_ops; ;
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>setup-amd64></literal></term>
|
||||
<term><literal>setup-i386></literal></term>
|
||||
<term><literal>setup-ia64></literal></term>
|
||||
<term><literal>setup-amd64</literal></term>
|
||||
<term><literal>setup-i386</literal></term>
|
||||
<term><literal>setup-ia64</literal></term>
|
||||
|
||||
<listitem><para>The filename of the target platform specific
|
||||
environment setup script to run before invoking any of the tools
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,9 +3,9 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
This example show how to add a new target type and a new tool
|
||||
support to Boost.Build. Please refer to extender manual for
|
||||
complete description of this example.
|
||||
This example show how to add a new target type and a new tool support to
|
||||
Boost.Build. Please refer to extender manual for a complete description of this
|
||||
example.
|
||||
|
||||
Note that this example requires Python. If cygwin Python on Windows is
|
||||
to be used, please go to "verbatim.jam" and follow instructions there.
|
||||
Note that this example requires Python. If cygwin Python on Windows is to be
|
||||
used, please go to "verbatim.jam" and follow instructions there.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
usage
|
||||
Usage: codegen class_name
|
||||
|
||||
This program takes a template of C++ code and replaces of
|
||||
occurences of %class_name% with the passed 'class_name'
|
||||
parameter.
|
||||
This program takes a template of C++ code and replaces of all occurrences of
|
||||
%class_name% with the passed 'class_name' parameter.
|
||||
@@ -1,15 +1,11 @@
|
||||
|
||||
This example shows the 'generate' rule, that
|
||||
allows you to construct target using any arbitrary
|
||||
set of transformation and commands.
|
||||
|
||||
The rule is similar to 'make' and 'notfile', but
|
||||
unlike those, you can operate in terms of
|
||||
Boost.Build 'virtual targets', which is more
|
||||
flexible.
|
||||
|
||||
Please consult the docs for more explanations.
|
||||
|
||||
# Copyright 2007 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
This example shows the 'generate' rule, that allows you to construct target
|
||||
using any arbitrary set of transformation and commands.
|
||||
|
||||
The rule is similar to 'make' and 'notfile', but unlike those, you can operate
|
||||
in terms of Boost.Build 'virtual targets', which is more flexible.
|
||||
|
||||
Please consult the docs for more explanations.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
This example shows how to declare a new generator class. It's necessary
|
||||
when generator's logic is more complex that just running a single tool.
|
||||
|
||||
# Copyright 2006 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
This example shows how to declare a new generator class. It is necessary when
|
||||
generator's logic is more complex that just running a single tool.
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
Copyright 2003 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
Copyright 2003 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
This example shows how it's possible to used GNU gettext utilities with
|
||||
This example shows how it is possible to use GNU gettext utilities with
|
||||
Boost.Build.
|
||||
|
||||
A simple translation file is compiled and installed as message catalog for
|
||||
russian. The main application explicitly switches to russian locale and
|
||||
output the translation of "hello".
|
||||
russian. The main application explicitly switches to russian locale and outputs
|
||||
the translation of "hello".
|
||||
|
||||
To test:
|
||||
|
||||
@@ -22,4 +22,3 @@ To test even more:
|
||||
- edit "russian.po"
|
||||
- run bjam
|
||||
- run "main"
|
||||
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
exe hello : hello.cpp ;
|
||||
7
v2/example/hello/readme.txt
Normal file
7
v2/example/hello/readme.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Copyright 2008 Jurko Gospodnetic
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
This example shows a very basic Boost Build project set up so it compiles a
|
||||
single executable from a single source file.
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
import notfile ;
|
||||
import common ;
|
||||
|
||||
exe main : main.cpp ;
|
||||
|
||||
# Create 'main.cpp' from 'main.cpp.pro' using action
|
||||
# 'do-something' defined below.
|
||||
#
|
||||
make main.cpp : main_cpp.pro : @do-something ;
|
||||
|
||||
# In this example, we'll just copy a file.
|
||||
# Need to find out the name of a command to copy a file.
|
||||
CP = [ common.copy-command ] ;
|
||||
|
||||
# The action itself.
|
||||
# The 'CP' variable is defined below
|
||||
# $(>) is source
|
||||
# $(<) is target
|
||||
actions do-something
|
||||
{
|
||||
$(CP) $(>) $(<)
|
||||
}
|
||||
2
v2/example/make/foo.py
Normal file
2
v2/example/make/foo.py
Normal file
@@ -0,0 +1,2 @@
|
||||
import sys
|
||||
open(sys.argv[2], "w").write(open(sys.argv[1]).read())
|
||||
10
v2/example/make/jamroot.jam
Normal file
10
v2/example/make/jamroot.jam
Normal file
@@ -0,0 +1,10 @@
|
||||
import toolset ;
|
||||
|
||||
path-constant HERE : . ;
|
||||
make main.cpp : main_cpp.pro : @do-something ;
|
||||
|
||||
toolset.flags do-something PYTHON : <python.interpreter> ;
|
||||
actions do-something
|
||||
{
|
||||
"$(PYTHON:E=python)" "$(HERE)/foo.py" "$(>)" "$(<)"
|
||||
}
|
||||
@@ -1,2 +1 @@
|
||||
|
||||
int main() { return 0; }
|
||||
int main() {}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
Copyright 2002, 2005 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
Copyright 2002, 2005 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
Example of using custom command to create one file from
|
||||
another, using the builtin 'make' rule.
|
||||
Example of using custom command to create one file from another, using the
|
||||
built-in 'make' rule.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Copyright 2006 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
Copyright 2006 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
This example shows how you can use Python modules from Boost.Build.
|
||||
@@ -8,8 +8,9 @@ This example shows how you can use Python modules from Boost.Build.
|
||||
In order to do this, you need to build bjam with Python support, by running:
|
||||
|
||||
./build.sh --with-python=/usr
|
||||
|
||||
in jam directory. (Replace /usr with the root of your Python installation.)
|
||||
|
||||
The integration between Python and bjam is very basic now, but enough to
|
||||
be useful.
|
||||
in the jam/src directory (replace /usr with the root of your Python
|
||||
installation).
|
||||
|
||||
The integration between Python and bjam is very basic now, but enough to be
|
||||
useful.
|
||||
|
||||
@@ -7,15 +7,14 @@ This directory contains Boost.Build examples for the Qt library
|
||||
(http://www.trolltech.com/products/qt/index.html).
|
||||
|
||||
The current examples are:
|
||||
1. Basic setup -- application with several sources and moccable header.
|
||||
2. Using of .ui source file.
|
||||
3. Running .cpp files via the moc tool.
|
||||
1. Basic setup -- application with several sources and moccable header.
|
||||
2. Using of .ui source file.
|
||||
3. Running .cpp files via the moc tool.
|
||||
|
||||
For convenience, there are examples both for 3.* and 4.* version of Qt,
|
||||
they are mostly identical and differ only in source code.
|
||||
For convenience, there are examples both for 3.* and 4.* version of Qt, they are
|
||||
mostly identical and differ only in source code.
|
||||
|
||||
All examples assumes that you just installed Boost.Build and that QTDIR
|
||||
environment variables is set (typical values can be /usr/share/qt3 and
|
||||
/usr/share/qt4). After adding "using qt ..." to your user-config.jam, you'd
|
||||
have to removing "using qt ; " statements from Jamroot file of examples.
|
||||
|
||||
/usr/share/qt4). After adding "using qt ..." to your user-config.jam, you would
|
||||
have to remove "using qt ; " statements from example Jamroot files.
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
# Copyright 2004 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
# By default, build the project with two variants
|
||||
# we've defined in project-root.jam
|
||||
project
|
||||
: default-build crazy super_release
|
||||
;
|
||||
|
||||
exe a : a.cpp libs//l ;
|
||||
|
||||
11
v2/example/variant/jamfile.jam
Normal file
11
v2/example/variant/jamfile.jam
Normal file
@@ -0,0 +1,11 @@
|
||||
# Copyright 2004 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
# By default, build the project with the two variants we have defined in
|
||||
# jamroot.jam.
|
||||
|
||||
project : default-build crazy super_release ;
|
||||
|
||||
exe a : a.cpp libs//l ;
|
||||
@@ -1,11 +1,11 @@
|
||||
Copyright 2004 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
Copyright 2004 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
This example shows how user can create his own build variants.
|
||||
Two variants are defined: "crazy", which is just random combination
|
||||
of properties, and "super-release", which is inherited from "release",
|
||||
and differs by a single define.
|
||||
This example shows how user can create his own build variants. Two variants are
|
||||
defined: "crazy", which is just a random combination of properties, and
|
||||
"super-release", which is inherited from "release", and differs by a single
|
||||
define.
|
||||
|
||||
See the project-root.jam for the definitions.
|
||||
See the jamroot.jam for the definitions.
|
||||
|
||||
@@ -1,731 +0,0 @@
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Importing by a different name keeps PyChecker happy
|
||||
from __future__ import generators as generators_
|
||||
import sys
|
||||
|
||||
|
||||
class Generator(object):
|
||||
"""Representation of a transformation from source to target types.
|
||||
|
||||
sources and targets may be either strings or sequences of
|
||||
strings.
|
||||
|
||||
>>> print Generator(('obj*', 'lib*'), 'exe')
|
||||
exe <- obj*,lib*
|
||||
|
||||
>>> assert Generator('c','o').unary
|
||||
"""
|
||||
|
||||
def __init__(self, sources, targets):
|
||||
"""
|
||||
>>> g = Generator(['obj*', 'z', 'cpp'], ['lib','dll'])
|
||||
>>> g.signature
|
||||
[('cpp', 1, 1), ('obj', 0, '*'), ('z', 1, 1)]
|
||||
>>> g = Generator('cpp', 'obj')
|
||||
>>> g.signature
|
||||
[('cpp', 1, 1)]
|
||||
"""
|
||||
self.sources = _sequence_of_strings(sources)
|
||||
self.targets =_sequence_of_strings(targets)
|
||||
self.targets_ = _string_multiset(targets)
|
||||
|
||||
signature = {}
|
||||
stars = {}
|
||||
for s in self.sources:
|
||||
if s.endswith('*'):
|
||||
stars[s[:-1]] = 1
|
||||
signature.setdefault(s[:-1],0)
|
||||
else:
|
||||
signature[s] = signature.get(s,0) + 1
|
||||
|
||||
self.signature = []
|
||||
for t, n in signature.items():
|
||||
if t in stars:
|
||||
self.signature.append((t, n, '*'))
|
||||
else:
|
||||
self.signature.append((t, n, n))
|
||||
|
||||
self.signature.sort() # makes doctests nicer
|
||||
|
||||
# Remember whether the signature is strictly unary
|
||||
self.unary = not stars and len(self.sources) == 1
|
||||
|
||||
def match(self, group):
|
||||
"""If group satisfies an element of the signature, returns an
|
||||
amended signature that consists of all other elements.
|
||||
Otherwise, returns None.
|
||||
>>> g = Generator(['obj*', 'z', 'cpp', 'z'], ['lib','dll'])
|
||||
>>> g.match(TargetTypeGroup('obj',12))
|
||||
[('cpp', 1, 1), ('z', 2, 2)]
|
||||
>>> g.match(TargetTypeGroup('cpp',12)) # None
|
||||
|
||||
>>> g.match(TargetTypeGroup('cpp',1))
|
||||
[('obj', 0, '*'), ('z', 2, 2)]
|
||||
|
||||
>>> g.match(TargetTypeGroup('z',2))
|
||||
[('cpp', 1, 1), ('obj', 0, '*')]
|
||||
|
||||
>>> Generator('cpp','obj').match(TargetTypeGroup('cpp',1))
|
||||
[]
|
||||
|
||||
>>> Generator('cpp','obj').match(TargetTypeGroup('cpp',12))
|
||||
[]
|
||||
"""
|
||||
if self in group.generators:
|
||||
return None
|
||||
|
||||
for i in range(len(self.signature)):
|
||||
e = self.signature[i]
|
||||
if e[0] == group.target_type:
|
||||
if self.unary:
|
||||
return []
|
||||
if e[1] > group.size or e[2] < group.size:
|
||||
return None
|
||||
else:
|
||||
return self.signature[:i] + self.signature[i+1:]
|
||||
return None
|
||||
|
||||
def __str__(self):
|
||||
"""Make a nice human-readable representation
|
||||
>>> g = Generator(['obj*', 'z', 'cpp'], ['lib','dll'])
|
||||
>>> print g
|
||||
lib,dll <- obj*,z,cpp
|
||||
"""
|
||||
return ','.join(self.targets) + ' <- ' + ','.join(self.sources)
|
||||
|
||||
def __type_list_rep(self, type_list):
|
||||
if len(type_list) == 1:
|
||||
return repr(type_list[0])
|
||||
else:
|
||||
return repr(type_list)
|
||||
|
||||
def __repr__(self):
|
||||
return (
|
||||
self.__module__ + '.' + type(self).__name__ + '(' +
|
||||
self.__type_list_rep(self.sources)
|
||||
+ ', ' + self.__type_list_rep(self.targets) + ')'
|
||||
)
|
||||
|
||||
def _dict_tuple(d):
|
||||
l = d.items()
|
||||
l.sort()
|
||||
return tuple(l)
|
||||
|
||||
def _sorted(list):
|
||||
list.sort()
|
||||
return list
|
||||
|
||||
class GeneratorSet(object):
|
||||
def __init__(self):
|
||||
self.all_generators = {}
|
||||
self.generators_by_type = {}
|
||||
|
||||
def __iadd__(self, generator):
|
||||
"""Add a generator to the set
|
||||
|
||||
>>> s = GeneratorSet()
|
||||
>>> s += Generator('foo', 'bar')
|
||||
>>> s += Generator('foo', 'baz')
|
||||
>>> s += Generator(['foo','bar'], 'baz')
|
||||
>>> s += Generator('bar', ['baz', 'mumble'])
|
||||
>>> s += Generator('bar*', ['bing'])
|
||||
>>> print s
|
||||
{
|
||||
bar:
|
||||
baz <- foo,bar
|
||||
baz,mumble <- bar
|
||||
bing <- bar*
|
||||
foo:
|
||||
bar <- foo
|
||||
baz <- foo
|
||||
baz <- foo,bar
|
||||
}
|
||||
|
||||
"""
|
||||
if not generator in self.all_generators:
|
||||
self.all_generators[generator] = 1
|
||||
for t in generator.sources:
|
||||
if t.endswith('*'):
|
||||
t = t[:-1]
|
||||
l = self[t]
|
||||
l.append(generator)
|
||||
return self
|
||||
|
||||
def __isub__(self, generator):
|
||||
for t in generator.sources:
|
||||
if t.endswith('*'):
|
||||
t = t[:-1]
|
||||
self[t].remove(generator)
|
||||
return self
|
||||
|
||||
def __getitem__(self, t):
|
||||
"""Given a target type, return a list of all the generators
|
||||
which can consume that target type.
|
||||
"""
|
||||
return self.generators_by_type.setdefault(t,[])
|
||||
|
||||
def __str__(self):
|
||||
# import pprint
|
||||
# return pprint.pformat(self.generators_by_type)
|
||||
|
||||
s = []
|
||||
|
||||
for k,v in _sorted(self.generators_by_type.items()):
|
||||
s += [ ' ' + k + ':\n ' + '\n '.join([ str(x) for x in v ]) ]
|
||||
|
||||
return '{\n' + '\n'.join(s) + '\n}'
|
||||
|
||||
def _dicts_intersect(d1, d2):
|
||||
"""True iff d1 and d2 have a key in common
|
||||
|
||||
>>> assert _dicts_intersect({1:0, 2:0}, {2:0})
|
||||
>>> assert _dicts_intersect({2:0}, {1:0, 2:0})
|
||||
>>> assert not _dicts_intersect({1:0, 3:0}, {2:0})
|
||||
>>> assert not _dicts_intersect({2:0}, {1:0, 3:0})
|
||||
"""
|
||||
if len(d2) < len(d1):
|
||||
tmp = d1
|
||||
d1 = d2
|
||||
d2 = tmp
|
||||
for k in d1.iterkeys():
|
||||
if k in d2:
|
||||
return True
|
||||
return False
|
||||
|
||||
class TargetTypeGroup(object):
|
||||
instances = 0
|
||||
|
||||
def __init__(
|
||||
self
|
||||
, target_type
|
||||
, size # how many of that type are in the group.
|
||||
, parents = ()
|
||||
, generator = None):
|
||||
"""
|
||||
>>> g1 = TargetTypeGroup('x', 1)
|
||||
>>> assert not g1.extra_targets
|
||||
>>> assert g1.consumed_sources == { g1:1 }
|
||||
>>> g2 = TargetTypeGroup('x', 1)
|
||||
|
||||
>>> g3 = TargetTypeGroup('x', 1, [g1,g2])
|
||||
>>> assert g1 in g3.consumed_sources
|
||||
>>> assert g2 in g3.consumed_sources
|
||||
>>> assert not g3 in g3.consumed_sources
|
||||
"""
|
||||
self.target_type = target_type
|
||||
self.size = size
|
||||
self.parents = parents
|
||||
self.generator = generator
|
||||
self.siblings = None
|
||||
self.id = TargetTypeGroup.instances
|
||||
self.ambiguous = reduce(lambda x,y: x or y.ambiguous and 1,
|
||||
parents, None)
|
||||
|
||||
self.generators = { generator : 1 } # it doesn't hurt to store None here
|
||||
ignored = [ self.generators.update(p.generators) for p in parents ]
|
||||
|
||||
self.__constituents = None
|
||||
self.__extra_targets = None
|
||||
|
||||
TargetTypeGroup.instances += 1
|
||||
|
||||
if generator:
|
||||
self.moves = { (id(generator),id(parents)) : 1 }
|
||||
else:
|
||||
self.moves = {}
|
||||
|
||||
if not parents:
|
||||
self.consumed_sources = {self:1}
|
||||
self.__extra_targets = ()
|
||||
else:
|
||||
ignored = [ self.moves.update(p.moves) for p in parents ]
|
||||
|
||||
if len(parents) == 1:
|
||||
self.consumed_sources = parents[0].consumed_sources
|
||||
else:
|
||||
self.consumed_sources = {}
|
||||
for c in parents:
|
||||
self.consumed_sources.update(c.consumed_sources)
|
||||
|
||||
# constituents property - the set of all target groups consumed in
|
||||
# creating this group
|
||||
def __get_constituents(self):
|
||||
if self.__constituents is None:
|
||||
self.__constituents = {self:1}
|
||||
for c in self.parents:
|
||||
self.__constituents.update(c.constituents)
|
||||
return self.__constituents
|
||||
|
||||
constituents = property(__get_constituents)
|
||||
|
||||
cost = property(lambda self: len(self.moves))
|
||||
|
||||
# extra targets property - in general, every target group sits at
|
||||
# the root of a DAG. The extra targets are the ones produced by
|
||||
# generators that run in this DAG but which are not part of the
|
||||
# DAG, i.e. are not constituents. In the example below, X and Y
|
||||
# are extra targets of A.
|
||||
#
|
||||
# A X B,C <- D
|
||||
# / \ / C,Y <- E
|
||||
# B C Y A,X <- B,C
|
||||
# \ / \ /
|
||||
# Sources: D E
|
||||
#
|
||||
# We use the extra targets to determine the equivalence of two
|
||||
# search States
|
||||
def __get_extra_targets(self):
|
||||
if self.__extra_targets is None:
|
||||
|
||||
if len(self.parents) == 1 and not self.siblings:
|
||||
self.__extra_targets = self.parents[0].extra_targets
|
||||
else:
|
||||
# all siblings are created incidentally
|
||||
if self.siblings:
|
||||
t = tuple([s for s in self.siblings if s != self])
|
||||
else:
|
||||
t = ()
|
||||
|
||||
# Any groups created incidentally as part of generating my
|
||||
# parents are also incidental to my generation
|
||||
for c in self.parents:
|
||||
for i in c.extra_targets:
|
||||
if i not in self.constituents:
|
||||
t += (i,)
|
||||
|
||||
self.__extra_targets = _sort_tuple(t)
|
||||
return self.__extra_targets
|
||||
|
||||
extra_targets = property(__get_extra_targets)
|
||||
|
||||
def set_siblings(self, sibs):
|
||||
assert self.__extra_targets is None, \
|
||||
"can't set siblings after extra targets already computed."
|
||||
|
||||
assert self.parents, "original source nodes don't have siblings"
|
||||
self.siblings = sibs
|
||||
|
||||
def __repr__(self):
|
||||
return '%s.%s(#%s$%s)' % (self.size,self.target_type,self.id,self.cost)
|
||||
|
||||
def is_compatible_with(self, other):
|
||||
"""True iff self and other can be used to trigger a generator.
|
||||
|
||||
>>> g1 = TargetTypeGroup('x', 1)
|
||||
>>> g2 = TargetTypeGroup('x', 1)
|
||||
>>> assert g1.is_compatible_with(g2)
|
||||
|
||||
>>> g3 = TargetTypeGroup('x', 1, [g1])
|
||||
>>> g4 = TargetTypeGroup('x', 1, [g2])
|
||||
>>> assert g3.is_compatible_with(g4)
|
||||
>>> assert g3.is_compatible_with(g2)
|
||||
>>> assert not g3.is_compatible_with(g1)
|
||||
>>> assert not g2.is_compatible_with(g4)
|
||||
|
||||
>>> g5 = TargetTypeGroup('x', 1, [g3])
|
||||
>>> assert not g5.is_compatible_with(g1)
|
||||
"""
|
||||
return not _dicts_intersect(
|
||||
self.constituents, other.constituents)
|
||||
|
||||
def all_compatible(self, others):
|
||||
"""True iff self is_compatible with every element of other
|
||||
"""
|
||||
for o in others:
|
||||
if not self.is_compatible_with(o):
|
||||
return False
|
||||
return True
|
||||
|
||||
def atoms(self):
|
||||
"""If this group was formed by combining other groups without
|
||||
a generator, return a set of its nearest parent groups which
|
||||
were not formed that way. Otherwise, return a set
|
||||
containing only this group.
|
||||
|
||||
>>> g1 = TargetTypeGroup('x',1)
|
||||
>>> g2 = TargetTypeGroup('x',1)
|
||||
>>> a = TargetTypeGroup('x',2, [g1,g2]).atoms()
|
||||
>>> assert g1 in a and g2 in a and len(a) == 2
|
||||
"""
|
||||
if self.generator or not self.parents:
|
||||
return (self,)
|
||||
x = ()
|
||||
for p in self.parents:
|
||||
x += p.atoms()
|
||||
return x
|
||||
|
||||
|
||||
def consumes(self, others):
|
||||
"""True iff not self is_compatible with every element of other
|
||||
"""
|
||||
for o in others:
|
||||
if self.is_compatible_with(o):
|
||||
return False
|
||||
return True
|
||||
|
||||
def _string_multiset(s):
|
||||
x = {}
|
||||
for t in _sequence_of_strings(s):
|
||||
x[t] = x.get(t,0) + 1
|
||||
return x
|
||||
|
||||
|
||||
def parent_sets(chosen, signature, all_groups, generator):
|
||||
"""Given an already-chosen tuple of TargetTypeGroups and a signature
|
||||
of the groups left to choose, generates all mutually-compatible
|
||||
combinations of groups starting with chosen
|
||||
|
||||
>>> TargetTypeGroup.instances = 0
|
||||
>>> groups = {
|
||||
... 'x': [ TargetTypeGroup('x', 1) ],
|
||||
... 'y': [ TargetTypeGroup('y', 1), TargetTypeGroup('y',2) ],
|
||||
... 'z': [ TargetTypeGroup('z', 1) ]
|
||||
... }
|
||||
>>> signature = (('y',0,'*'),('z',1,'1'))
|
||||
>>> chosen = (groups['x'][0],)
|
||||
>>> [ x for x in parent_sets(chosen, signature, groups, Generator('x',('y*', 'z'))) ]
|
||||
[(1.x(#0$0), 1.z(#3$0)), (1.x(#0$0), 1.y(#1$0), 1.z(#3$0)), (1.x(#0$0), 2.y(#2$0), 1.z(#3$0))]
|
||||
"""
|
||||
if len(signature) == 0:
|
||||
# The entire signature was satisfied; we can just yield the
|
||||
# one result
|
||||
yield chosen
|
||||
else:
|
||||
# find all ways to satisfy the next element of the signature
|
||||
# which are compatible with the already-chosen groups. If
|
||||
# there are no ways, we will fall off the end here and the
|
||||
# ultimate result will be empty.
|
||||
t, min, max = signature[0]
|
||||
|
||||
if min == 0:
|
||||
for s in parent_sets(chosen, signature[1:], all_groups, generator):
|
||||
yield s
|
||||
|
||||
for g in all_groups[t]:
|
||||
|
||||
# can only use a generator once in any path
|
||||
if generator in g.generators:
|
||||
continue
|
||||
|
||||
if (g.size >= min and g.size <= max and
|
||||
g.all_compatible(chosen)):
|
||||
|
||||
for s in parent_sets(
|
||||
chosen + (g,), signature[1:], all_groups, generator
|
||||
):
|
||||
yield s
|
||||
|
||||
debug = None
|
||||
|
||||
def _sort_tuple(t):
|
||||
"""copies the given sequence into a new tuple in sorted order"""
|
||||
l = list(t)
|
||||
l.sort()
|
||||
return tuple(l)
|
||||
|
||||
def _sequence_of_strings(s_or_l):
|
||||
"""if the argument is a string, wraps a tuple around it.
|
||||
Otherwise, returns the argument untouched
|
||||
"""
|
||||
if isinstance(s_or_l, type('')):
|
||||
return (s_or_l,)
|
||||
else:
|
||||
return s_or_l
|
||||
|
||||
def _examine_edge(states, queue, g):
|
||||
"""Handle a possible new state in the search.
|
||||
"""
|
||||
g_state = State(g)
|
||||
v = states.setdefault(g_state, g_state)
|
||||
|
||||
if v.group is g:
|
||||
queue.append(g_state)
|
||||
return False
|
||||
|
||||
if v.group.cost > g.cost:
|
||||
if debug:
|
||||
print 'reducing cost of state(%s) via %s' % (v.group,g)
|
||||
v.group.ambiguous = None
|
||||
v.group = g
|
||||
|
||||
elif v.group.cost < g.cost:
|
||||
if debug:
|
||||
print 'discarding %s due to lower cost state(%s)' % (g, v.group)
|
||||
|
||||
elif not (g.generator or v.group.generator) \
|
||||
and _sort_tuple(g.atoms()) == _sort_tuple(v.group.atoms()):
|
||||
# These are two different ways of combining the same groups of
|
||||
# a given type to produce a larger group, without using a generator
|
||||
if debug:
|
||||
print 'discarding %s as a redundant formulation of %s' % (g,v.group)
|
||||
else:
|
||||
if debug:
|
||||
print '%s is an ambiguous path due to %s' % (v.group, g)
|
||||
# Remember the group which caused the ambiguity
|
||||
v.group.ambiguous = g
|
||||
|
||||
return True
|
||||
|
||||
class State(object):
|
||||
"""A wrapper around a TargetTypeGroup which makes it hashable on
|
||||
the part of its data which determines its ability to contribute to
|
||||
producing the goal target type.
|
||||
"""
|
||||
def __init__(self, group):
|
||||
self.group = group
|
||||
|
||||
def __hash__(self):
|
||||
g = self.group
|
||||
x = g.consumed_sources.keys()
|
||||
x.sort()
|
||||
return hash((g.target_type, g.size, _sort_tuple(g.extra_targets), tuple(x)))
|
||||
|
||||
def __eq__(self, other):
|
||||
return (
|
||||
self.group.target_type == other.group.target_type
|
||||
and self.group.size == other.group.size
|
||||
and self.group.extra_targets == other.group.extra_targets
|
||||
and self.group.consumed_sources == other.group.consumed_sources)
|
||||
|
||||
queue_moves = 0
|
||||
|
||||
def optimal_graphs(target_type, source_groups, generators):
|
||||
"""A 'simple generator' that produces the sequence of least-cost
|
||||
solutions for producing the
|
||||
target type from a subset of the source_groups, using the given
|
||||
generators.
|
||||
"""
|
||||
# An index from target type to lists of groups with that type.
|
||||
all_groups = {}
|
||||
|
||||
# Prime the priority Queue
|
||||
q = [ State(g) for g in source_groups ]
|
||||
|
||||
# Keep a record of all known states in the search
|
||||
states = dict([ (s,s) for s in q ])
|
||||
|
||||
solution_cost = None
|
||||
while q:
|
||||
# remove a group from the queue
|
||||
g = q[0].group
|
||||
del q[0]
|
||||
|
||||
global queue_moves
|
||||
queue_moves += 1
|
||||
|
||||
global debug
|
||||
if debug:
|
||||
print '-------'
|
||||
print graph(g)
|
||||
|
||||
if g.target_type == target_type: # and g.consumes(source_groups):
|
||||
solution_cost = g.cost
|
||||
yield g
|
||||
|
||||
if g.consumes(source_groups): # Nothing left to find
|
||||
return
|
||||
|
||||
# combine with all like groups which are compatible
|
||||
for g2 in all_groups.get(g.target_type,()):
|
||||
|
||||
if g2.is_compatible_with(g):
|
||||
|
||||
_examine_edge(
|
||||
states, q,
|
||||
TargetTypeGroup(g.target_type, g2.size + g.size, (g,g2)))
|
||||
|
||||
# expand with all generators which can be triggered as a
|
||||
# result of adding this group
|
||||
for generator in generators[g.target_type]:
|
||||
|
||||
match = generator.match(g)
|
||||
if match is None:
|
||||
continue
|
||||
|
||||
if debug:
|
||||
print generator,' matched with ', match
|
||||
|
||||
# for all sets of parents which match the generator and
|
||||
# include g
|
||||
for s in parent_sets((g,), match, all_groups, generator):
|
||||
|
||||
# Create the products of running this generator with
|
||||
# the given parent set
|
||||
siblings = ()
|
||||
for t,n in generator.targets_.items():
|
||||
# Unary generators run as many times as necessary
|
||||
# to consume the group
|
||||
if (generator.unary):
|
||||
n *= g.size
|
||||
|
||||
siblings += (TargetTypeGroup(t, n, s, generator),)
|
||||
|
||||
# Make sure groups know about their siblings
|
||||
if len(siblings) > 1:
|
||||
for product in siblings:
|
||||
product.set_siblings(siblings)
|
||||
|
||||
if debug:
|
||||
print siblings, '<-', list(s)
|
||||
|
||||
# Add new search states to the queue
|
||||
for sib in siblings:
|
||||
_examine_edge(states, q, sib)
|
||||
|
||||
# Add to the set of all groups so that we can combine it with
|
||||
# others in future iterations
|
||||
l = all_groups.get(g.target_type)
|
||||
if l is None:
|
||||
l = all_groups.setdefault(g.target_type,[])
|
||||
l.append(g)
|
||||
|
||||
# Sort the queue; in 'real life' use a priority queue
|
||||
q.sort(lambda v1,v2: v1.group.cost - v2.group.cost)
|
||||
|
||||
|
||||
def graph(group, indent = 0, visited = None):
|
||||
|
||||
"""Produce a string representation of the search graph
|
||||
that produced the given group.
|
||||
"""
|
||||
if (visited is None):
|
||||
visited = {}
|
||||
s = indent * ' '
|
||||
s += repr(group)
|
||||
if group in visited:
|
||||
s += '...\n'
|
||||
else:
|
||||
visited[group] = True
|
||||
s += '[%s]' % group.generator
|
||||
|
||||
if group.ambiguous:
|
||||
s += ' *ambiguous* '
|
||||
if type(group.ambiguous) is not type(1):
|
||||
s += 'due to %s' % group.ambiguous
|
||||
if group.siblings:
|
||||
s += ' siblings ' + str([sib for sib in group.siblings if
|
||||
sib != group])
|
||||
s += '\n' + '\n'.join(
|
||||
[graph(g,indent+1,visited) for g in group.parents])
|
||||
return s
|
||||
|
||||
def ambiguities(group):
|
||||
"""Returns a list of groups that caused ambiguities with this one
|
||||
or its constituents.
|
||||
"""
|
||||
result = []
|
||||
for g in group.parents:
|
||||
result.extend(ambiguities(g))
|
||||
if group.ambiguous and type(group.ambiguous) is not type(1):
|
||||
result.append(group.ambiguous)
|
||||
return result
|
||||
|
||||
def search(generators, targets, sources):
|
||||
import sys
|
||||
global queue_moves
|
||||
|
||||
TargetTypeGroup.instances = 0
|
||||
queue_moves = 0
|
||||
|
||||
# Remember what we started with
|
||||
source_groups = tuple([
|
||||
TargetTypeGroup(i[0],i[1])
|
||||
for i in _string_multiset(sources).items() ])
|
||||
|
||||
solutions = {}
|
||||
max_consumed = 0
|
||||
|
||||
for g in optimal_graphs(targets, source_groups, generators):
|
||||
|
||||
if len(g.consumed_sources) > max_consumed:
|
||||
max_consumed = len(g.consumed_sources)
|
||||
|
||||
g2 = solutions.setdefault(len(g.consumed_sources), g)
|
||||
if g2 is not g:
|
||||
if g2.cost == g.cost:
|
||||
g2.ambiguous = g
|
||||
|
||||
if max_consumed:
|
||||
g = solutions[max_consumed]
|
||||
|
||||
print 80 * '='
|
||||
print graph(g)
|
||||
|
||||
if g.ambiguous:
|
||||
print 40 * '-'
|
||||
print 'ambiguities:'
|
||||
for a in ambiguities(g):
|
||||
print graph(a)
|
||||
print
|
||||
|
||||
print queue_moves, 'queue_moves'
|
||||
print 80 * '='
|
||||
sys.stdout.flush()
|
||||
|
||||
print queue_moves, 'queue moves'
|
||||
print '\n\n*****\n\n'
|
||||
|
||||
|
||||
def test():
|
||||
"""Runs Volodya's example, but doesn't get the result he'd like.
|
||||
"""
|
||||
# EST_EXE <- OBJ*
|
||||
# OBJ <- CPP
|
||||
# {CPP,STATIC_DATA} <- NM_ASM
|
||||
# {CPP,CPP} <- ECPP (only first CPP must be further converted into NM_ASM)
|
||||
# NM_ASM <- CPP
|
||||
# {CPP,STATIC_DATA} <- STATIC_DATA*
|
||||
# STATIC_DATA <- NM_ASM
|
||||
# NM_OBJ <- NM_ASM
|
||||
# NM_EXE <- NM_OBJ*
|
||||
generators = GeneratorSet()
|
||||
generators += Generator('OBJ*', 'EST_EXE')
|
||||
generators += Generator('CPP', 'OBJ')
|
||||
generators += Generator('NM_ASM', ('CPP', 'STATIC_DATA'))
|
||||
generators += Generator('ECPP', ('CPP','CPP'))
|
||||
generators += Generator('CPP', 'NM_ASM')
|
||||
generators += Generator('STATIC_DATA*', ('CPP', 'STATIC_DATA'))
|
||||
generators += Generator('NM_ASM', 'NM_OBJ')
|
||||
generators += Generator('NM_OBJ*', 'NM_EXE')
|
||||
|
||||
search(generators, 'EST_EXE', ('CPP', 'NM_ASM', 'ECPP'))
|
||||
# Try the same search with a source type that can't be consumed.
|
||||
# This will exhaust all transformations before stopping.
|
||||
search(generators, 'EST_EXE', ('CPP', 'NM_ASM', 'ECPP', 'FOO'))
|
||||
search(generators, 'NM_EXE', ('CPP'))
|
||||
|
||||
def run(args = None):
|
||||
import doctest
|
||||
import sys
|
||||
|
||||
if args is not None:
|
||||
sys.argv = args
|
||||
|
||||
error = doctest.testmod(sys.modules.get(__name__))
|
||||
|
||||
if not error[0]:
|
||||
global debug
|
||||
if '--debug' in sys.argv:
|
||||
debug = 1
|
||||
test()
|
||||
|
||||
return error
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
sys.exit(run()[0])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ div.sidebar p.rubric {
|
||||
<input type="submit" value="Search">
|
||||
</form> -->
|
||||
</ul>
|
||||
<li><a href="http://zigzag.cs.msu.su/boost.build">Bug tracker</a>
|
||||
<li><a href="http://zigzag.lvk.cs.msu.su/boost.build">Bug tracker</a>
|
||||
<!-- <li>Rate Boost.Build: <a href="http://freshmeat.net/rate/38012/">Freshmeat</a> -->
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
@@ -242,11 +242,13 @@ rule import ( module-names + : rules-opt * : rename-opt * )
|
||||
{
|
||||
if ( $(rules-opt) = * || ! $(rules-opt) ) && $(rename-opt)
|
||||
{
|
||||
import errors ;
|
||||
errors.error "Rule aliasing is only available for explicit imports." ;
|
||||
}
|
||||
|
||||
if $(module-names[2]) && ( $(rules-opt) || $(rename-opt) )
|
||||
{
|
||||
import errors ;
|
||||
errors.error "When loading multiple modules, no specific rules or"
|
||||
"renaming is allowed" ;
|
||||
}
|
||||
|
||||
@@ -25,5 +25,5 @@ echo "Building packages and uploading docs"
|
||||
./roll.sh > ../roll-log 2>&1
|
||||
cd ..
|
||||
echo "Uploading packages"
|
||||
scp boost-build.zip boost-build.tar.bz2 vladimir_prus@shell.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2 > scp-log
|
||||
scp boost-build.zip boost-build.tar.bz2 vladimir_prus,boost@web.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2 > scp-log
|
||||
echo "Nightly build successful"
|
||||
|
||||
@@ -26,7 +26,7 @@ rm -rf example/versioned
|
||||
find . -maxdepth 1 -type f | egrep -v "boost-build.jam|timestamp.txt|roll.sh|bootstrap.jam|build-system.jam|boost_build.png|index.html|hacking.txt|site-config.jam|user-config.jam" | xargs rm -f
|
||||
|
||||
# Build the documentation
|
||||
touch doc/project-root.jam
|
||||
touch doc/jamroot.jam
|
||||
export BOOST_BUILD_PATH=`pwd`
|
||||
cd doc
|
||||
/home/ghost/Work/Boost/boost-svn/tools/jam/src/bin.linuxx86/bjam --v2
|
||||
@@ -65,5 +65,5 @@ urchinTracker();
|
||||
EOF`
|
||||
echo $x
|
||||
perl -pi -e "s|</body>|$x</body>|" `find doc -name '*.html'`
|
||||
scp -r doc example boost_build.png *.html hacking.txt vladimir_prus@shell.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2
|
||||
scp ../userman.pdf vladimir_prus@shell.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2/doc
|
||||
scp -r doc example boost_build.png *.html hacking.txt vladimir_prus,boost@web.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2
|
||||
scp ../userman.pdf vladimir_prus,boost@web.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2/doc
|
||||
|
||||
@@ -67,7 +67,7 @@ def get_toolset():
|
||||
|
||||
# Detect the host OS.
|
||||
windows = False
|
||||
if os.environ.get('OS','').lower().startswith('windows') or \
|
||||
if os.environ.get('OS', '').lower().startswith('windows') or \
|
||||
os.__dict__.has_key('uname') and \
|
||||
os.uname()[0].lower().startswith('cygwin'):
|
||||
windows = True
|
||||
@@ -88,13 +88,13 @@ def prepare_suffix_map(toolset):
|
||||
suffixes['.lib'] = '.a' # static libs have '.a' suffix with mingw...
|
||||
suffixes['.obj'] = '.o'
|
||||
suffixes['.implib'] = '.lib'
|
||||
if os.__dict__.has_key('uname') and os.uname()[0] == 'Darwin':
|
||||
if os.__dict__.has_key('uname') and (os.uname()[0] == 'Darwin'):
|
||||
suffixes['.dll'] = '.dylib'
|
||||
|
||||
|
||||
def re_remove(sequence, regex):
|
||||
me = re.compile(regex)
|
||||
result = filter( lambda x: me.match(x), sequence )
|
||||
result = filter(lambda x: me.match(x), sequence)
|
||||
if 0 == len(result):
|
||||
raise ValueError()
|
||||
for r in result:
|
||||
@@ -102,7 +102,7 @@ def re_remove(sequence, regex):
|
||||
|
||||
|
||||
def glob_remove(sequence, pattern):
|
||||
result = fnmatch.filter(sequence,pattern)
|
||||
result = fnmatch.filter(sequence, pattern)
|
||||
if 0 == len(result):
|
||||
raise ValueError()
|
||||
for r in result:
|
||||
@@ -206,7 +206,7 @@ class Tester(TestCmd.TestCmd):
|
||||
jam_build_dir = ""
|
||||
if os.name == 'nt':
|
||||
jam_build_dir = "bin.ntx86"
|
||||
elif os.name == 'posix' and os.__dict__.has_key('uname'):
|
||||
elif (os.name == 'posix') and os.__dict__.has_key('uname'):
|
||||
if os.uname()[0].lower().startswith('cygwin'):
|
||||
jam_build_dir = "bin.cygwinx86"
|
||||
if 'TMP' in os.environ and os.environ['TMP'].find('~') != -1:
|
||||
@@ -238,7 +238,7 @@ class Tester(TestCmd.TestCmd):
|
||||
else:
|
||||
raise "Don't know directory where Jam is built for this system: " + os.name
|
||||
|
||||
# Find where jam_src is located. Try for the debug version if it's
|
||||
# Find where jam_src is located. Try for the debug version if it is
|
||||
# lying around.
|
||||
dirs = [os.path.join('../../../jam/src', jam_build_dir + '.debug'),
|
||||
os.path.join('../../../jam/src', jam_build_dir),
|
||||
@@ -445,7 +445,7 @@ class Tester(TestCmd.TestCmd):
|
||||
finally:
|
||||
self.last_build_time_finish = time.time()
|
||||
|
||||
if status != None and _failed(self, status):
|
||||
if (status != None) and _failed(self, status):
|
||||
expect = ''
|
||||
if status != 0:
|
||||
expect = " (expected %d)" % status
|
||||
@@ -456,7 +456,7 @@ class Tester(TestCmd.TestCmd):
|
||||
annotation("reason", "error returned by bjam")
|
||||
self.fail_test(1)
|
||||
|
||||
if not stdout is None and not match(self.stdout(), stdout):
|
||||
if not (stdout is None) and not match(self.stdout(), stdout):
|
||||
annotation("failure", "Unexpected stdout")
|
||||
annotation("Expected STDOUT", stdout)
|
||||
annotation("Actual STDOUT", self.stdout())
|
||||
@@ -470,7 +470,7 @@ class Tester(TestCmd.TestCmd):
|
||||
intel_workaround = re.compile("^xi(link|lib): executing.*\n", re.M)
|
||||
actual_stderr = re.sub(intel_workaround, "", self.stderr())
|
||||
|
||||
if not stderr is None and not match(actual_stderr, stderr):
|
||||
if not (stderr is None) and not match(actual_stderr, stderr):
|
||||
annotation("failure", "Unexpected stderr")
|
||||
annotation("Expected STDERR", stderr)
|
||||
annotation("Actual STDERR", self.stderr())
|
||||
@@ -480,7 +480,7 @@ class Tester(TestCmd.TestCmd):
|
||||
|
||||
if not expected_duration is None:
|
||||
actual_duration = self.last_build_time_finish - self.last_build_time_start
|
||||
if ( actual_duration > expected_duration ):
|
||||
if (actual_duration > expected_duration):
|
||||
print "Test run lasted %f seconds while it was expected to " \
|
||||
"finish in under %f seconds." % (actual_duration,
|
||||
expected_duration)
|
||||
@@ -493,9 +493,9 @@ class Tester(TestCmd.TestCmd):
|
||||
|
||||
def glob_file(self, name):
|
||||
result = None
|
||||
if hasattr(self,'difference'):
|
||||
if hasattr(self, 'difference'):
|
||||
for f in self.difference.added_files+self.difference.modified_files+self.difference.touched_files:
|
||||
if fnmatch.fnmatch(f,name):
|
||||
if fnmatch.fnmatch(f, name):
|
||||
result = self.native_file_name(f)
|
||||
break
|
||||
if not result:
|
||||
@@ -510,7 +510,7 @@ class Tester(TestCmd.TestCmd):
|
||||
name = string.replace(name, "$toolset", self.toolset+"*")
|
||||
name = self.glob_file(name)
|
||||
openMode = "r"
|
||||
if ( binary ):
|
||||
if binary:
|
||||
openMode += "b"
|
||||
else:
|
||||
openMode += "U"
|
||||
@@ -564,7 +564,7 @@ class Tester(TestCmd.TestCmd):
|
||||
def expect_addition(self, names):
|
||||
for name in self.adjust_names(names):
|
||||
try:
|
||||
glob_remove(self.unexpected_difference.added_files,name)
|
||||
glob_remove(self.unexpected_difference.added_files, name)
|
||||
except:
|
||||
print "File %s not added as expected" % name
|
||||
self.fail_test(1)
|
||||
@@ -575,7 +575,7 @@ class Tester(TestCmd.TestCmd):
|
||||
def expect_removal(self, names):
|
||||
for name in self.adjust_names(names):
|
||||
try:
|
||||
glob_remove(self.unexpected_difference.removed_files,name)
|
||||
glob_remove(self.unexpected_difference.removed_files, name)
|
||||
except:
|
||||
print "File %s not removed as expected" % name
|
||||
self.fail_test(1)
|
||||
@@ -586,13 +586,14 @@ class Tester(TestCmd.TestCmd):
|
||||
def expect_modification(self, names):
|
||||
for name in self.adjust_names(names):
|
||||
try:
|
||||
glob_remove(self.unexpected_difference.modified_files,name)
|
||||
glob_remove(self.unexpected_difference.modified_files, name)
|
||||
except:
|
||||
print "File %s not modified as expected" % name
|
||||
self.fail_test(1)
|
||||
|
||||
def ignore_modification(self, wildcard):
|
||||
self.ignore_elements(self.unexpected_difference.modified_files, wildcard)
|
||||
self.ignore_elements(self.unexpected_difference.modified_files, \
|
||||
wildcard)
|
||||
|
||||
def expect_touch(self, names):
|
||||
d = self.unexpected_difference
|
||||
@@ -607,7 +608,7 @@ class Tester(TestCmd.TestCmd):
|
||||
|
||||
while filesets:
|
||||
try:
|
||||
glob_remove(filesets[-1],name)
|
||||
glob_remove(filesets[-1], name)
|
||||
break
|
||||
except ValueError:
|
||||
filesets.pop()
|
||||
@@ -646,7 +647,7 @@ class Tester(TestCmd.TestCmd):
|
||||
self.fail_test(1)
|
||||
|
||||
def expect_nothing_more(self):
|
||||
# Not totally sure about this change, but I don't see a good
|
||||
# Not totally sure about this change, but I do not see a good
|
||||
# alternative.
|
||||
if windows:
|
||||
self.ignore('*.ilk') # MSVC incremental linking files.
|
||||
@@ -676,12 +677,12 @@ class Tester(TestCmd.TestCmd):
|
||||
break
|
||||
|
||||
if expected_to_exist and not found:
|
||||
annotation( "failure",
|
||||
annotation("failure",
|
||||
"Did not find expected line:\n%s\nin output:\n%s" %
|
||||
(expected, content))
|
||||
self.fail_test(1)
|
||||
if not expected_to_exist and found:
|
||||
annotation( "failure",
|
||||
annotation("failure",
|
||||
"Found an unexpected line:\n%s\nin output:\n%s" %
|
||||
(expected, content))
|
||||
self.fail_test(1)
|
||||
@@ -712,22 +713,22 @@ class Tester(TestCmd.TestCmd):
|
||||
|
||||
matched = False
|
||||
if exact:
|
||||
matched = fnmatch.fnmatch(actual,content)
|
||||
matched = fnmatch.fnmatch(actual, content)
|
||||
else:
|
||||
def sorted_(x):
|
||||
x.sort()
|
||||
return x
|
||||
actual_ = map(lambda x: sorted_(x.split()),actual.splitlines())
|
||||
content_ = map(lambda x: sorted_(x.split()),content.splitlines())
|
||||
actual_ = map(lambda x: sorted_(x.split()), actual.splitlines())
|
||||
content_ = map(lambda x: sorted_(x.split()), content.splitlines())
|
||||
if len(actual_) == len(content_):
|
||||
matched = map(
|
||||
lambda x,y: map(lambda n,p: fnmatch.fnmatch(n,p),x,y),
|
||||
actual_, content_ )
|
||||
lambda x, y: map(lambda n, p: fnmatch.fnmatch(n, p), x, y),
|
||||
actual_, content_)
|
||||
matched = reduce(
|
||||
lambda x,y: x and reduce(
|
||||
lambda a,b: a and b,
|
||||
y ),
|
||||
matched )
|
||||
lambda x, y: x and reduce(
|
||||
lambda a, b: a and b,
|
||||
y),
|
||||
matched)
|
||||
|
||||
if not matched:
|
||||
print "Expected:\n"
|
||||
@@ -744,7 +745,7 @@ class Tester(TestCmd.TestCmd):
|
||||
open(a, "w").write(actual)
|
||||
print "DIFFERENCE"
|
||||
if os.system("diff -u " + e + " " + a):
|
||||
print "Unable to compute difference: diff -u %s %s" % (e,a)
|
||||
print "Unable to compute difference: diff -u %s %s" % (e, a)
|
||||
os.unlink(e)
|
||||
os.unlink(a)
|
||||
else:
|
||||
@@ -793,7 +794,7 @@ class Tester(TestCmd.TestCmd):
|
||||
tail = "lib" + tail
|
||||
result = os.path.join(head, tail)
|
||||
# If we want to use this name in a Jamfile, we better convert \ to /, as
|
||||
# otherwise we'd have to quote \.
|
||||
# otherwise we would have to quote \.
|
||||
result = string.replace(result, "\\", "/")
|
||||
return result
|
||||
|
||||
@@ -873,7 +874,7 @@ class List:
|
||||
return str(self.l)
|
||||
|
||||
def __repr__(self):
|
||||
return ( self.__module__ + '.List('
|
||||
return (self.__module__ + '.List('
|
||||
+ repr(string.join(self.l, ' '))
|
||||
+ ')')
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Niklaus Giger, 2005-03-15
|
||||
# Testing whether we may run a test in a absolute directories
|
||||
# There are no tests for temporary directories as this is implictly tested in a lot of other cases
|
||||
# Testing whether we may run a test in absolute directories. There are no tests
|
||||
# for temporary directories as this is implictly tested in a lot of other cases.
|
||||
|
||||
import BoostBuild
|
||||
import os
|
||||
@@ -9,10 +9,10 @@ import string
|
||||
t = BoostBuild.Tester(arguments="pwd", executable="jam", workdir=os.getcwd(),
|
||||
pass_toolset=0)
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
actions print_pwd { pwd ; }
|
||||
print_pwd pwd ;
|
||||
Always pwd ;
|
||||
ALWAYS pwd ;
|
||||
""")
|
||||
|
||||
t.run_build_system(status=0)
|
||||
@@ -30,5 +30,5 @@ if string.rfind(t.stdout(), 'build/v2/test') == -1:
|
||||
|
||||
t.run_build_system(status=1, subdir="/must/fail/with/absolute/path",
|
||||
stderr=None)
|
||||
t.cleanup
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,72 +1,76 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003, 2004 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003, 2004 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that sources with absolute names are handled OK.
|
||||
|
||||
from BoostBuild import Tester
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
|
||||
t.write("project-root.jam", """
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("jamroot.jam", """
|
||||
path-constant TOP : . ;
|
||||
""")
|
||||
t.write("Jamfile", """
|
||||
|
||||
t.write("jamfile.jam", """
|
||||
local pwd = [ PWD ] ;
|
||||
ECHO $(pwd) XXXXX ;
|
||||
exe hello : $(pwd)/hello.cpp $(TOP)/empty.cpp ;
|
||||
""")
|
||||
t.write("hello.cpp", "int main() { return 0; }\n")
|
||||
|
||||
t.write("hello.cpp", "int main() {}\n")
|
||||
|
||||
t.write("empty.cpp", "\n")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/hello.exe")
|
||||
|
||||
# Test a contrived case. There, absolute name is used in
|
||||
# standalone project (not Jamfile). Moreover, the target with
|
||||
# absolute name is returned by 'alias' and used from other project.
|
||||
t.write("a.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
# Test a contrived case. There, absolute name is used in a standalone project
|
||||
# (not Jamfile). Moreover, the target with an absolute name is returned by
|
||||
# 'alias' and used from another project.
|
||||
t.write("a.cpp", """
|
||||
int main() {}
|
||||
""")
|
||||
|
||||
t.write("Jamfile", """
|
||||
exe a : /standalone//a ;
|
||||
t.write("jamfile.jam", """
|
||||
exe a : /standalone//a ;
|
||||
""")
|
||||
|
||||
t.write("project-root.jam", """
|
||||
import standalone ;
|
||||
t.write("jamroot.jam", """
|
||||
import standalone ;
|
||||
""")
|
||||
|
||||
t.write("standalone.jam", """
|
||||
t.write("standalone.jam", """
|
||||
import project ;
|
||||
|
||||
project.initialize $(__name__) ;
|
||||
project standalone ;
|
||||
|
||||
local pwd = [ PWD ] ;
|
||||
|
||||
alias a : $(pwd)/a.cpp ;
|
||||
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/a.exe")
|
||||
|
||||
# Test absolute path in target ids
|
||||
# Test absolute path in target ids.
|
||||
t.rm(".")
|
||||
t.write("d1/project-root.jam", "")
|
||||
t.write("d1/Jamfile", """
|
||||
|
||||
t.write("d1/jamroot.jam", "")
|
||||
|
||||
t.write("d1/jamfile.jam", """
|
||||
exe a : a.cpp ;
|
||||
""")
|
||||
|
||||
t.write("d1/a.cpp", """
|
||||
int main() { return 0; }
|
||||
int main() {}
|
||||
""")
|
||||
t.write("d2/project-root.jam", "")
|
||||
t.write("d2/Jamfile", """
|
||||
|
||||
t.write("d2/jamroot.jam", "")
|
||||
|
||||
t.write("d2/jamfile.jam", """
|
||||
local pwd = [ PWD ] ;
|
||||
alias x : $(pwd)/../d1//a ;
|
||||
""")
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
|
||||
|
||||
################################################################################
|
||||
@@ -19,7 +19,7 @@ def test_alias_rule(t):
|
||||
"""Basic alias rule test.
|
||||
"""
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe a : a.cpp ;
|
||||
exe b : b.cpp ;
|
||||
exe c : c.cpp ;
|
||||
@@ -31,7 +31,7 @@ alias src : s.cpp ;
|
||||
exe hello : hello.cpp src ;
|
||||
""")
|
||||
|
||||
t.write("a.cpp", "int main() { return 0; }\n")
|
||||
t.write("a.cpp", "int main() {}\n")
|
||||
t.copy("a.cpp", "b.cpp")
|
||||
t.copy("a.cpp", "c.cpp")
|
||||
t.copy("a.cpp", "hello.cpp")
|
||||
@@ -39,19 +39,20 @@ exe hello : hello.cpp src ;
|
||||
|
||||
# Check that targets to which "bin1" refers are updated, and only those.
|
||||
t.run_build_system("bin1")
|
||||
t.expect_addition(List("bin/$toolset/debug/") * "a.exe a.obj")
|
||||
t.expect_addition(BoostBuild.List("bin/$toolset/debug/") * "a.exe a.obj")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Try again with "bin2"
|
||||
t.run_build_system("bin2")
|
||||
t.expect_addition(List("bin/$toolset/debug/") * "b.exe b.obj")
|
||||
t.expect_addition(BoostBuild.List("bin/$toolset/debug/") * "b.exe b.obj")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Try building everything, making sure 'hello' target is created.
|
||||
t.run_build_system()
|
||||
t.expect_addition(List("bin/$toolset/debug/") * "hello.exe hello.obj")
|
||||
t.expect_addition(BoostBuild.List("bin/$toolset/debug/") * \
|
||||
"hello.exe hello.obj")
|
||||
t.expect_addition("bin/$toolset/debug/s.obj")
|
||||
t.expect_addition(List("bin/$toolset/debug/") * "c.exe c.obj")
|
||||
t.expect_addition(BoostBuild.List("bin/$toolset/debug/") * "c.exe c.obj")
|
||||
t.expect_nothing_more()
|
||||
|
||||
|
||||
@@ -68,7 +69,7 @@ def test_alias_source_usage_requirements(t):
|
||||
anywhere in the source.
|
||||
"""
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
lib l : l.cpp : : : <define>WANT_MAIN ;
|
||||
alias la : l ;
|
||||
exe main : main.cpp la ;
|
||||
@@ -84,7 +85,7 @@ foo() {}
|
||||
|
||||
t.write("main.cpp", """
|
||||
#ifdef WANT_MAIN
|
||||
int main() { return 0; }
|
||||
int main() {}
|
||||
#endif
|
||||
""")
|
||||
|
||||
@@ -98,7 +99,7 @@ int main() { return 0; }
|
||||
#
|
||||
################################################################################
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
test_alias_rule(t)
|
||||
test_alias_source_usage_requirements(t)
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2003, 2006 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2003, 2006 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test main target alternatives.
|
||||
|
||||
from BoostBuild import Tester
|
||||
from string import find
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
import string
|
||||
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
# Test that basic alternatives selection works.
|
||||
t.write("project-root.jam", " ")
|
||||
t.write("Jamfile", """
|
||||
t.write("jamroot.jam", "")
|
||||
|
||||
t.write("jamfile.jam", """
|
||||
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.write("a.cpp", "int main() {}\n")
|
||||
|
||||
t.run_build_system("release")
|
||||
|
||||
t.expect_addition("bin/$toolset/release/a.exe")
|
||||
|
||||
# Test that alternative selection works for ordinary
|
||||
# properties, in particular user-defined.
|
||||
t.write("project-root.jam", " ")
|
||||
t.write("Jamfile", """
|
||||
# Test that alternative selection works for ordinary properties, in particular
|
||||
# user-defined.
|
||||
t.write("jamroot.jam", "")
|
||||
|
||||
t.write("jamfile.jam", """
|
||||
import feature ;
|
||||
feature.feature X : off on : propagated ;
|
||||
|
||||
exe a : b.cpp ;
|
||||
exe a : a.cpp : <X>on ;
|
||||
""")
|
||||
t.write("b.cpp", "int main() { return 0; }\n")
|
||||
t.write("b.cpp", "int main() {}\n")
|
||||
|
||||
t.rm("bin")
|
||||
|
||||
@@ -48,11 +50,8 @@ t.expect_addition("bin/$toolset/debug/X-on/a.obj")
|
||||
|
||||
t.rm("bin")
|
||||
|
||||
# Test that everything works ok even with default
|
||||
# build.
|
||||
|
||||
t.write("Jamfile", """
|
||||
|
||||
# Test that everything works ok even with default build.
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a_empty.cpp : <variant>release ;
|
||||
exe a : a.cpp : <variant>debug ;
|
||||
""")
|
||||
@@ -60,12 +59,10 @@ exe a : a.cpp : <variant>debug ;
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/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
|
||||
# Test that only properties which are in build request matter for alternative
|
||||
# selection. IOW, alternative with <variant>release is better than one with
|
||||
# <variant>debug when building release version.
|
||||
t.write("Jamfile", """
|
||||
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a_empty.cpp : <variant>debug ;
|
||||
exe a : a.cpp : <variant>release ;
|
||||
""")
|
||||
@@ -73,10 +70,9 @@ exe a : a.cpp : <variant>release ;
|
||||
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", """
|
||||
# Test that free properties do not matter. We really do not want <cxxflags>
|
||||
# property in build request to affect alternative selection.
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a_empty.cpp : <variant>debug <define>FOO <include>BAR ;
|
||||
exe a : a.cpp : <variant>release ;
|
||||
""")
|
||||
@@ -85,28 +81,26 @@ 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", """
|
||||
# Test that ambiguity is reported correctly.
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a_empty.cpp ;
|
||||
exe a : a.cpp ;
|
||||
""")
|
||||
t.run_build_system("--no-error-backtrace", status=None)
|
||||
t.fail_test(find(t.stdout(), "No best alternative") == -1)
|
||||
t.fail_test(string.find(t.stdout(), "No best alternative") == -1)
|
||||
|
||||
# Another ambiguity test: two matches properties in one alternative are
|
||||
# neither better nor worse than a single one in another alternative.
|
||||
t.write("Jamfile", """
|
||||
# Another ambiguity test: two matches properties in one alternative are neither
|
||||
# better nor worse than a single one in another alternative.
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a_empty.cpp : <optimization>off <profiling>off ;
|
||||
exe a : a.cpp : <debug-symbols>on ;
|
||||
""")
|
||||
|
||||
t.run_build_system("--no-error-backtrace", status=None)
|
||||
t.fail_test(find(t.stdout(), "No best alternative") == -1)
|
||||
t.fail_test(string.find(t.stdout(), "No best alternative") == -1)
|
||||
|
||||
|
||||
|
||||
# Test that we can have alternative without sources
|
||||
t.write("Jamfile", """
|
||||
# Test that we can have alternative without sources.
|
||||
t.write("jamfile.jam", """
|
||||
alias specific-sources ;
|
||||
import feature ;
|
||||
feature.extend os : MAGIC ;
|
||||
@@ -116,5 +110,4 @@ exe a : a.cpp specific-sources ;
|
||||
t.rm("bin")
|
||||
t.run_build_system()
|
||||
|
||||
|
||||
t.cleanup()
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Regression test: when directory of project root contained regex metacharacters,
|
||||
# Boost.Build failed to work. Bug reported by Michael Stevens
|
||||
# Regression test: when directory of project root contained regex
|
||||
# metacharacters, Boost.Build failed to work. Bug reported by Michael Stevens.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("bad[abc]dirname/Jamfile", """
|
||||
t.write("bad[abc]dirname/jamfile.jam", """
|
||||
""")
|
||||
|
||||
t.write("bad[abc]dirname/project-root.jam", """
|
||||
t.write("bad[abc]dirname/jamroot.jam", """
|
||||
""")
|
||||
|
||||
t.run_build_system(subdir="bad[abc]dirname")
|
||||
|
||||
t.cleanup()
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2004, 2006 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2004, 2006 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
import string
|
||||
|
||||
# Create a temporary working directory
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.set_tree("boostbook")
|
||||
|
||||
# For some reason, the messages are sent to stderr.
|
||||
t.run_build_system()
|
||||
t.fail_test(string.find(t.stdout(), """Writing boost/A.html for refentry(boost.A)
|
||||
|
||||
@@ -1,55 +1,52 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2002, 2003, 2005 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2002, 2003, 2005 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that we can change build directory using
|
||||
# the 'build-dir' project attribute.
|
||||
# Test that we can change build directory using the 'build-dir' project
|
||||
# attribute.
|
||||
|
||||
from BoostBuild import Tester
|
||||
import BoostBuild
|
||||
import string
|
||||
import os
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
|
||||
# Test that top-level project can affect build dir
|
||||
t.write("project-root.jam", "import gcc ; ")
|
||||
t.write("Jamfile", """
|
||||
project
|
||||
: build-dir build
|
||||
;
|
||||
|
||||
# Test that top-level project can affect build dir.
|
||||
t.write("jamroot.jam", "import gcc ;")
|
||||
t.write("jamfile.jam", """
|
||||
project : build-dir build ;
|
||||
exe a : a.cpp ;
|
||||
build-project src ;
|
||||
build-project src ;
|
||||
""")
|
||||
t.write("a.cpp", "int main() { return 0; }\n")
|
||||
|
||||
t.write("src/Jamfile", "exe b : b.cpp ; ")
|
||||
t.write("src/b.cpp", "int main() { return 0; }\n")
|
||||
t.write("a.cpp", "int main() {}\n")
|
||||
|
||||
t.write("src/jamfile.jam", "exe b : b.cpp ; ")
|
||||
|
||||
t.write("src/b.cpp", "int main() {}\n")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_addition(["build/$toolset/debug/a.exe",
|
||||
"build/src/$toolset/debug/b.exe"])
|
||||
|
||||
# Test that building from child projects work
|
||||
|
||||
# Test that building from child projects work.
|
||||
t.run_build_system(subdir='src')
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Test that project can override build dir
|
||||
t.write("Jamfile", """
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Test that project can override build dir.
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a.cpp ;
|
||||
build-project src ;
|
||||
""")
|
||||
""")
|
||||
|
||||
t.write("src/Jamfile", """
|
||||
project
|
||||
: build-dir build
|
||||
;
|
||||
exe b : b.cpp ;
|
||||
t.write("src/jamfile.jam", """
|
||||
project : build-dir build ;
|
||||
exe b : b.cpp ;
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
@@ -58,46 +55,44 @@ t.expect_addition(["bin/$toolset/debug/a.exe",
|
||||
|
||||
# Now test the '--build-dir' option.
|
||||
t.rm(".")
|
||||
t.write("Jamroot", "")
|
||||
t.write("jamroot.jam", "")
|
||||
|
||||
# Test that we get an error when no project id is specified.
|
||||
t.run_build_system("--build-dir=foo")
|
||||
t.fail_test(string.find(t.stdout(),
|
||||
"warning: the --build-dir option will be ignored") == -1)
|
||||
|
||||
t.write("Jamroot", """
|
||||
t.write("jamroot.jam", """
|
||||
project foo ;
|
||||
exe a : a.cpp ;
|
||||
build-project sub ;
|
||||
""")
|
||||
t.write("a.cpp", "int main() { return 0; }\n")
|
||||
t.write("sub/Jamfile", "exe b : b.cpp ;\n")
|
||||
t.write("sub/b.cpp", "int main() { return 0; }\n")
|
||||
t.write("a.cpp", "int main() {}\n")
|
||||
t.write("sub/jamfile.jam", "exe b : b.cpp ;\n")
|
||||
t.write("sub/b.cpp", "int main() {}\n")
|
||||
|
||||
t.run_build_system("--build-dir=build")
|
||||
t.expect_addition(["build/foo/$toolset/debug/a.exe",
|
||||
"build/foo/sub/$toolset/debug/b.exe"])
|
||||
|
||||
t.write("Jamroot", """
|
||||
t.write("jamroot.jam", """
|
||||
project foo : build-dir bin.v2 ;
|
||||
exe a : a.cpp ;
|
||||
build-project sub ;
|
||||
""")
|
||||
|
||||
t.run_build_system("--build-dir=build")
|
||||
t.expect_addition(["build/foo/bin.v2/$toolset/debug/a.exe",
|
||||
t.expect_addition(["build/foo/bin.v2/$toolset/debug/a.exe",
|
||||
"build/foo/bin.v2/sub/$toolset/debug/b.exe"])
|
||||
|
||||
# Try building in subdir. We expect that the entire build
|
||||
# tree with be in 'sub/build'. Today, I'm not sure if
|
||||
# this is what the user expects, but let it be.
|
||||
# Try building in subdir. We expect that the entire build tree with be in
|
||||
# 'sub/build'. Today, I am not sure if this is what the user expects, but let it
|
||||
# be.
|
||||
t.rm('build')
|
||||
t.run_build_system("--build-dir=build", subdir="sub")
|
||||
t.expect_addition(["sub/build/foo/bin.v2/sub/$toolset/debug/b.exe"])
|
||||
|
||||
|
||||
|
||||
t.write("Jamroot", """
|
||||
t.write("jamroot.jam", """
|
||||
project foo : build-dir %s ;
|
||||
exe a : a.cpp ;
|
||||
build-project sub ;
|
||||
@@ -105,9 +100,6 @@ build-project sub ;
|
||||
|
||||
t.run_build_system("--build-dir=build", status=1)
|
||||
t.fail_test(string.find(t.stdout(),
|
||||
"Absolute directory specified via 'build-dir' project attribute") == -1)
|
||||
"Absolute directory specified via 'build-dir' project attribute") == -1)
|
||||
|
||||
|
||||
|
||||
|
||||
t.cleanup()
|
||||
t.cleanup()
|
||||
|
||||
@@ -22,18 +22,18 @@ import BoostBuild
|
||||
def test_building_file_from_specific_project():
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello : hello.cpp ;
|
||||
exe hello2 : hello.cpp ;
|
||||
build-project sub ;
|
||||
""")
|
||||
t.write("hello.cpp", "int main() { return 0; }")
|
||||
t.write("sub/Jamfile.jam", """
|
||||
t.write("hello.cpp", "int main() {}")
|
||||
t.write("sub/jamfile.jam", """
|
||||
exe hello : hello.cpp ;
|
||||
exe hello2 : hello.cpp ;
|
||||
exe sub : hello.cpp ;
|
||||
""")
|
||||
t.write("sub/hello.cpp", "int main() { return 0; }")
|
||||
t.write("sub/hello.cpp", "int main() {}")
|
||||
|
||||
t.run_build_system("sub " + t.adjust_suffix("hello.obj"))
|
||||
t.expect_output_line("*depends on itself*", False)
|
||||
@@ -53,14 +53,14 @@ exe sub : hello.cpp ;
|
||||
def test_building_file_from_specific_target():
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello1 : hello1.cpp ;
|
||||
exe hello2 : hello2.cpp ;
|
||||
exe hello3 : hello3.cpp ;
|
||||
""")
|
||||
t.write("hello1.cpp", "int main() { return 0; }")
|
||||
t.write("hello2.cpp", "int main() { return 0; }")
|
||||
t.write("hello3.cpp", "int main() { return 0; }")
|
||||
t.write("hello1.cpp", "int main() {}")
|
||||
t.write("hello2.cpp", "int main() {}")
|
||||
t.write("hello3.cpp", "int main() {}")
|
||||
|
||||
t.run_build_system("hello1 " + t.adjust_suffix("hello1.obj"))
|
||||
t.expect_addition("bin/$toolset/debug/hello1.obj")
|
||||
@@ -79,17 +79,17 @@ exe hello3 : hello3.cpp ;
|
||||
def test_building_missing_file_from_specific_target():
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello1 : hello1.cpp ;
|
||||
exe hello2 : hello2.cpp ;
|
||||
exe hello3 : hello3.cpp ;
|
||||
""")
|
||||
t.write("hello1.cpp", "int main() { return 0; }")
|
||||
t.write("hello2.cpp", "int main() { return 0; }")
|
||||
t.write("hello3.cpp", "int main() { return 0; }")
|
||||
t.write("hello1.cpp", "int main() {}")
|
||||
t.write("hello2.cpp", "int main() {}")
|
||||
t.write("hello3.cpp", "int main() {}")
|
||||
|
||||
t.run_build_system("hello1 " + t.adjust_suffix("hello2.obj"), status=1)
|
||||
t.expect_output_line("don't know how to make*hello2.obj")
|
||||
t.expect_output_line("don't know how to make*" + t.adjust_suffix("hello2.obj"))
|
||||
t.expect_nothing_more()
|
||||
|
||||
t.cleanup()
|
||||
@@ -105,14 +105,14 @@ exe hello3 : hello3.cpp ;
|
||||
def test_building_multiple_files_with_different_names():
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello1 : hello1.cpp ;
|
||||
exe hello2 : hello2.cpp ;
|
||||
exe hello3 : hello3.cpp ;
|
||||
""")
|
||||
t.write("hello1.cpp", "int main() { return 0; }")
|
||||
t.write("hello2.cpp", "int main() { return 0; }")
|
||||
t.write("hello3.cpp", "int main() { return 0; }")
|
||||
t.write("hello1.cpp", "int main() {}")
|
||||
t.write("hello2.cpp", "int main() {}")
|
||||
t.write("hello3.cpp", "int main() {}")
|
||||
|
||||
t.run_build_system(
|
||||
t.adjust_suffix("hello1.obj") + " " +
|
||||
@@ -134,18 +134,18 @@ exe hello3 : hello3.cpp ;
|
||||
def test_building_multiple_files_with_the_same_name():
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello : hello.cpp ;
|
||||
exe hello2 : hello.cpp ;
|
||||
build-project sub ;
|
||||
""")
|
||||
t.write("hello.cpp", "int main() { return 0; }")
|
||||
t.write("sub/Jamfile.jam", """
|
||||
t.write("hello.cpp", "int main() {}")
|
||||
t.write("sub/jamfile.jam", """
|
||||
exe hello : hello.cpp ;
|
||||
exe hello2 : hello.cpp ;
|
||||
exe sub : hello.cpp ;
|
||||
""")
|
||||
t.write("sub/hello.cpp", "int main() { return 0; }")
|
||||
t.write("sub/hello.cpp", "int main() {}")
|
||||
|
||||
t.run_build_system(t.adjust_suffix("hello.obj"))
|
||||
t.expect_output_line("*depends on itself*", False)
|
||||
|
||||
@@ -1,28 +1,22 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) Vladimir Prus 2006.
|
||||
# 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)
|
||||
# Copyright (C) Vladimir Prus 2006.
|
||||
# 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 that <build>no property prevents a target from being built.
|
||||
from BoostBuild import Tester, List
|
||||
import string
|
||||
# Tests that <build>no property prevents a target from being built.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
# Create a temporary working directory
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
# Create the needed files
|
||||
t.write("Jamroot", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello : hello.cpp : <variant>debug:<build>no ;
|
||||
""")
|
||||
t.write("hello.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t.write("hello.cpp", """
|
||||
int main() {}
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
@@ -31,5 +25,4 @@ t.expect_nothing_more()
|
||||
t.run_build_system("release")
|
||||
t.expect_addition("bin/$toolset/release/hello.exe")
|
||||
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,26 +1,27 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that C files are compiled by C compiler
|
||||
from BoostBuild import Tester, List
|
||||
# Test that C files are compiled by a C compiler.
|
||||
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
|
||||
t.write("project-root.jam", "")
|
||||
t.write("Jamfile", """
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("jamroot.jam", """
|
||||
project ;
|
||||
|
||||
exe hello : hello.cpp a.c ;
|
||||
""")
|
||||
|
||||
t.write("hello.cpp", """
|
||||
extern "C" int foo();
|
||||
int main() { return foo(); }
|
||||
""")
|
||||
|
||||
t.write("a.c", """
|
||||
// This won't compile unless in C mode
|
||||
// This will not compile unless in C mode.
|
||||
int foo()
|
||||
{
|
||||
int new = 0;
|
||||
@@ -28,6 +29,7 @@ int foo()
|
||||
return new;
|
||||
}
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/hello.exe")
|
||||
|
||||
|
||||
@@ -5,38 +5,33 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This tests that
|
||||
# 1) the 'make' correctly assigns types to produced targets
|
||||
# 2) than if 'make' create targets of type CPP, they are
|
||||
# correctly used (there was a bug with it).
|
||||
# This tests that :
|
||||
# 1) the 'make' correctly assigns types to produced targets
|
||||
# 2) if 'make' creates targets of type CPP, they are correctly used.
|
||||
|
||||
from BoostBuild import Tester
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
|
||||
# In order to correctly link this app, 'b.cpp', created by 'make'
|
||||
# rule, should be compiled.
|
||||
t.write("project-root.jam", "import gcc ;")
|
||||
t.write("Jamfile", r'''
|
||||
rule create ( dst : src * : properties * )
|
||||
{
|
||||
# hack to echo a space under NT
|
||||
setup on $(dst) = "set x=int main(){ return 0; }" ;
|
||||
}
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
# In order to correctly link this app, 'b.cpp', created by a 'make' rule, should
|
||||
# be compiled.
|
||||
|
||||
t.write("jamroot.jam", "import gcc ;")
|
||||
|
||||
t.write("jamfile.jam", r'''
|
||||
import modules ;
|
||||
if [ modules.peek : NT ]
|
||||
{
|
||||
actions create
|
||||
{
|
||||
$(setup)
|
||||
echo %x% > $(<)
|
||||
echo int main() {} > $(<)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actions create
|
||||
{
|
||||
echo "int main(){ return 0; }" > $(<)
|
||||
echo "int main() {}" > $(<)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,13 +39,14 @@ IMPORT $(__name__) : create : : create ;
|
||||
|
||||
exe a : l dummy.cpp ;
|
||||
|
||||
# needs to be static lib for Windows - main cannot appear in DLL
|
||||
# Needs to be static lib for Windows - main() cannot appear in DLL.
|
||||
static-lib l : a.cpp b.cpp ;
|
||||
|
||||
make b.cpp : : create ;
|
||||
|
||||
''')
|
||||
|
||||
t.write("a.cpp", "")
|
||||
|
||||
t.write("dummy.cpp", "// msvc needs at least one object file\n")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
@@ -5,21 +5,19 @@
|
||||
# accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import string
|
||||
import BoostBuild
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("a.cpp", """
|
||||
t.write("a.cpp", """
|
||||
int main() {}
|
||||
|
||||
""")
|
||||
|
||||
t.write("Jamroot", """
|
||||
exe a : a.cpp sub1//sub1 sub2//sub2 sub3//sub3 ;
|
||||
t.write("jamroot.jam", """
|
||||
exe a : a.cpp sub1//sub1 sub2//sub2 sub3//sub3 ;
|
||||
""")
|
||||
|
||||
t.write("sub1/Jamfile", """
|
||||
t.write("sub1/jamfile.jam", """
|
||||
lib sub1 : sub1.cpp sub1_2 ../sub2//sub2 ;
|
||||
lib sub1_2 : sub1_2.cpp ;
|
||||
""")
|
||||
@@ -29,7 +27,6 @@ t.write("sub1/sub1.cpp", """
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void sub1() {}
|
||||
|
||||
""")
|
||||
|
||||
t.write("sub1/sub1_2.cpp", """
|
||||
@@ -37,12 +34,10 @@ t.write("sub1/sub1_2.cpp", """
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void sub1() {}
|
||||
|
||||
""")
|
||||
|
||||
|
||||
t.write("sub2/Jamfile", """
|
||||
lib sub2 : sub2.cpp ;
|
||||
t.write("sub2/jamfile.jam", """
|
||||
lib sub2 : sub2.cpp ;
|
||||
""")
|
||||
|
||||
t.write("sub2/sub2.cpp", """
|
||||
@@ -50,11 +45,10 @@ t.write("sub2/sub2.cpp", """
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void sub2() {}
|
||||
|
||||
""")
|
||||
|
||||
t.write("sub3/Jamroot", """
|
||||
lib sub3 : sub3.cpp ;
|
||||
t.write("sub3/jamroot.jam", """
|
||||
lib sub3 : sub3.cpp ;
|
||||
""")
|
||||
|
||||
t.write("sub3/sub3.cpp", """
|
||||
@@ -62,11 +56,9 @@ t.write("sub3/sub3.cpp", """
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void sub3() {}
|
||||
|
||||
""")
|
||||
|
||||
|
||||
# The 'clean' should not remove files under separate Jamroot.
|
||||
# The 'clean' should not remove files under separate jamroot.jam.
|
||||
t.run_build_system()
|
||||
t.run_build_system("--clean")
|
||||
t.expect_removal("bin/$toolset/debug/a.obj")
|
||||
@@ -77,15 +69,14 @@ t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
|
||||
|
||||
# The 'clean-all' removes everything it can reach.
|
||||
t.run_build_system()
|
||||
t.run_build_system("--clean")
|
||||
t.run_build_system("--clean-all")
|
||||
t.expect_removal("bin/$toolset/debug/a.obj")
|
||||
t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
|
||||
t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
|
||||
t.expect_removal("sub2/bin/$toolset/debug/sub2.obj")
|
||||
t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
|
||||
|
||||
# The 'clean' together with project target removes
|
||||
# only under that probject
|
||||
# The 'clean' together with project target removes only under that project.
|
||||
t.run_build_system()
|
||||
t.run_build_system("sub1 --clean")
|
||||
t.expect_nothing("bin/$toolset/debug/a.obj")
|
||||
@@ -94,7 +85,7 @@ t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
|
||||
t.expect_nothing("sub2/bin/$toolset/debug/sub2.obj")
|
||||
t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
|
||||
|
||||
# And clean-all removes everything.
|
||||
# And 'clean-all' removes everything.
|
||||
t.run_build_system()
|
||||
t.run_build_system("sub1 --clean-all")
|
||||
t.expect_nothing("bin/$toolset/debug/a.obj")
|
||||
@@ -103,9 +94,8 @@ t.expect_removal("sub1/bin/$toolset/debug/sub1_2.obj")
|
||||
t.expect_removal("sub2/bin/$toolset/debug/sub2.obj")
|
||||
t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
|
||||
|
||||
# If main target is explicitly named, we should not remove
|
||||
# files from other targets.
|
||||
|
||||
# If main target is explicitly named, we should not remove files from other
|
||||
# targets.
|
||||
t.run_build_system()
|
||||
t.run_build_system("sub1//sub1 --clean")
|
||||
t.expect_removal("sub1/bin/$toolset/debug/sub1.obj")
|
||||
@@ -113,18 +103,14 @@ t.expect_nothing("sub1/bin/$toolset/debug/sub1_2.obj")
|
||||
t.expect_nothing("sub2/bin/$toolset/debug/sub2.obj")
|
||||
t.expect_nothing("sub3/bin/$toolset/debug/sub3.obj")
|
||||
|
||||
|
||||
# Regression test: sources of the 'cast' rule were mistakenly
|
||||
# deleted.
|
||||
# Regression test: sources of the 'cast' rule were mistakenly deleted.
|
||||
t.rm(".")
|
||||
t.write("Jamroot", """
|
||||
t.write("jamroot.jam", """
|
||||
import cast ;
|
||||
cast a cpp : a.h ;
|
||||
""")
|
||||
t.write("a.h", "")
|
||||
|
||||
t.run_build_system("--clean")
|
||||
t.expect_nothing("a.h")
|
||||
|
||||
t.cleanup()
|
||||
|
||||
|
||||
@@ -4,26 +4,22 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that composite properties are handled correctly.
|
||||
from BoostBuild import Tester, List
|
||||
# Test that composite properties are handled correctly.
|
||||
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
|
||||
t.write("project-root.jam", "")
|
||||
t.write("Jamfile", """
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("jamroot.jam", """
|
||||
exe hello : hello.cpp : <variant>release ;
|
||||
""")
|
||||
t.write("hello.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t.write("hello.cpp", """
|
||||
int main() {}
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
t.expect_addition("bin/$toolset/release/hello.exe")
|
||||
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -15,18 +15,18 @@ t = BoostBuild.Tester()
|
||||
# define.
|
||||
t.write("a.cpp", """
|
||||
#ifdef STATIC
|
||||
int main() { return 0; }
|
||||
int main() {}
|
||||
#endif
|
||||
""")
|
||||
|
||||
# Test conditionals in target requirements.
|
||||
t.write("Jamroot.jam", "exe a : a.cpp : <link>static:<define>STATIC ;")
|
||||
t.write("jamroot.jam", "exe a : a.cpp : <link>static:<define>STATIC ;")
|
||||
t.run_build_system("link=static")
|
||||
t.expect_addition("bin/$toolset/debug/link-static/a.exe")
|
||||
t.rm("bin")
|
||||
|
||||
# Test conditionals in project requirements.
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
project : requirements <link>static:<define>STATIC ;
|
||||
exe a : a.cpp ;
|
||||
""")
|
||||
@@ -36,7 +36,7 @@ t.rm("bin")
|
||||
|
||||
# Regression test for a bug found by Ali Azarbayejani. Conditionals inside usage
|
||||
# requirement were not being evaluated.
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
lib l : l.cpp : : : <link>static:<define>STATIC ;
|
||||
exe a : a.cpp l ;
|
||||
""")
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Regression test: it was possible that due to evaluation of conditional
|
||||
# requirements, two different values of non-free features were present in
|
||||
# property set.
|
||||
# Regression test: it was possible that due to evaluation of conditional
|
||||
# requirements, two different values of non-free features were present in a
|
||||
# property set.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
@@ -14,7 +14,7 @@ t = BoostBuild.Tester()
|
||||
|
||||
t.write("a.cpp", "")
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import feature ;
|
||||
import common ;
|
||||
|
||||
|
||||
@@ -4,23 +4,23 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that conditional properties work, even if property is free, and value
|
||||
# includes a colon.
|
||||
# Test that conditional properties work, even if property is free, and value
|
||||
# includes a colon.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
exe hello : hello.cpp : <variant>debug:<define>CLASS=Foo::Bar ;
|
||||
""")
|
||||
|
||||
t.write("hello.cpp", """
|
||||
namespace Foo { class Bar { } ; }
|
||||
int main()
|
||||
{
|
||||
CLASS c;
|
||||
c; // Disables the unused variable warning.
|
||||
return 0;
|
||||
}
|
||||
""")
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ def test_multiple_conditions():
|
||||
"""Basic tests for properties conditioned on multiple other properties.
|
||||
"""
|
||||
|
||||
t = BoostBuild.Tester("--ignore-regular-config toolset=testToolset", pass_toolset=False, use_test_config=False)
|
||||
t = BoostBuild.Tester("--ignore-regular-config toolset=testToolset",
|
||||
pass_toolset=False, use_test_config=False)
|
||||
|
||||
t.write("testToolset.jam", """
|
||||
import feature ;
|
||||
@@ -29,7 +30,7 @@ feature.extend toolset : testToolset ;
|
||||
rule init ( ) { }
|
||||
""")
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import feature ;
|
||||
import notfile ;
|
||||
import toolset ;
|
||||
@@ -134,7 +135,7 @@ feature.subfeature toolset %(toolset)s : version : 0 1 ;
|
||||
rule init ( version ? ) { }
|
||||
""" % {"toolset": toolset})
|
||||
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import feature ;
|
||||
import notfile ;
|
||||
import toolset ;
|
||||
|
||||
@@ -23,7 +23,8 @@ def test_user_configuration():
|
||||
path handling is tested.
|
||||
"""
|
||||
|
||||
t = BoostBuild.Tester("--debug-configuration", pass_toolset=False, use_test_config=False)
|
||||
t = BoostBuild.Tester("--debug-configuration", pass_toolset=False,
|
||||
use_test_config=False)
|
||||
|
||||
implicitConfigLoadMessage = "notice: Loading user-config configuration file: *"
|
||||
explicitConfigLoadMessage = "notice: Loading explicitly specified user configuration file:"
|
||||
@@ -46,7 +47,7 @@ import feature ;
|
||||
feature.extend toolset : %s ;
|
||||
rule init ( ) { }
|
||||
""" % toolsetName )
|
||||
t.write("Jamroot.jam", "using %s ;" % toolsetName)
|
||||
t.write("jamroot.jam", "using %s ;" % toolsetName)
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_output_line(explicitConfigLoadMessage, False)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2002, 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2002, 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This tests correct handling of "-d1" and "-d2" options.
|
||||
|
||||
@@ -11,14 +11,9 @@ import BoostBuild
|
||||
t = BoostBuild.Tester(pass_toolset=0)
|
||||
|
||||
t.write("file.jam", """
|
||||
actions a {
|
||||
}
|
||||
|
||||
actions quietly b {
|
||||
}
|
||||
|
||||
actions a { }
|
||||
actions quietly b { }
|
||||
ALWAYS all ;
|
||||
|
||||
a all ;
|
||||
b all ;
|
||||
""")
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This tests the facilities for deleting modules.
|
||||
|
||||
@@ -28,12 +28,12 @@ module foo
|
||||
{
|
||||
EXIT DELETE_MODULE failed to kill foo's variables ;
|
||||
}
|
||||
|
||||
|
||||
rule bar { }
|
||||
var = x y ;
|
||||
|
||||
|
||||
DELETE_MODULE foo ;
|
||||
|
||||
|
||||
if $(var)
|
||||
{
|
||||
EXIT internal DELETE_MODULE failed to kill foo's variables ;
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This tests correct handling of dependencies, specifically, on
|
||||
# generated sources, and from generated sources.
|
||||
# This tests correct handling of dependencies, specifically, on generated
|
||||
# sources, and from generated sources.
|
||||
|
||||
import BoostBuild
|
||||
from string import find
|
||||
|
||||
import string
|
||||
|
||||
t = BoostBuild.Tester(pass_toolset=0)
|
||||
|
||||
@@ -37,20 +38,22 @@ HDRRULE on b foo.h bar.h = hdrrule ;
|
||||
HDRSCAN on b foo.h bar.h = \"#include <(.*)>\" ;
|
||||
"""
|
||||
|
||||
# This creates 'a' which depends on 'b', which is generated.
|
||||
# The generated 'b' contains '#include <foo.h>' and no rules for
|
||||
# foo.h are given. The system should error out on the first invocation.
|
||||
# This creates 'a' which depends on 'b', which is generated. The generated 'b'
|
||||
# contains '#include <foo.h>' and no rules for foo.h are given. The system
|
||||
# should error out on the first invocation.
|
||||
t.run_build_system("-f-", stdin=code)
|
||||
t.fail_test(find(t.stdout(), "...skipped a for lack of foo.h...") == -1)
|
||||
t.fail_test(string.find(t.stdout(), "...skipped a for lack of foo.h...") == -1)
|
||||
|
||||
t.rm('b')
|
||||
# Now test that if target 'c' also depends on 'b', then it won't be built, as well.
|
||||
|
||||
# Now test that if target 'c' also depends on 'b', then it will not be built, as
|
||||
# well.
|
||||
t.run_build_system("-f-", stdin=code + " copy c : b ; DEPENDS c : b ; DEPENDS all : c ; ")
|
||||
t.fail_test(find(t.stdout(), "...skipped c for lack of foo.h...") == -1)
|
||||
t.fail_test(string.find(t.stdout(), "...skipped c for lack of foo.h...") == -1)
|
||||
|
||||
|
||||
# Now add a rule for creating foo.h
|
||||
t.rm('b')
|
||||
|
||||
# Now add a rule for creating foo.h.
|
||||
code += """
|
||||
actions create-foo
|
||||
{
|
||||
@@ -60,36 +63,35 @@ create-foo foo.h ;
|
||||
"""
|
||||
t.run_build_system("-f-", stdin=code)
|
||||
|
||||
# Run two times, adding explicit dependency from all to foo.h at
|
||||
# the beginning and at the end, to make sure that foo.h is generated before
|
||||
# 'a' in all cases.
|
||||
# Run two times, adding explicit dependency from all to foo.h at the beginning
|
||||
# and at the end, to make sure that foo.h is generated before 'a' in all cases.
|
||||
|
||||
def mk_right_order_func(s1, s2):
|
||||
def right_order(s):
|
||||
n1 = find(s, s1)
|
||||
n2 = find(s, s2)
|
||||
return n1 != -1 and n2 != -1 and n1 < n2
|
||||
return right_order
|
||||
def mk_correct_order_func(s1, s2):
|
||||
def correct_order(s):
|
||||
n1 = string.find(s, s1)
|
||||
n2 = string.find(s, s2)
|
||||
return ( n1 != -1 ) and ( n2 != -1 ) and ( n1 < n2 )
|
||||
return correct_order
|
||||
|
||||
right_order = mk_right_order_func("create-foo", "copy a")
|
||||
correct_order = mk_correct_order_func("create-foo", "copy a")
|
||||
|
||||
t.rm(["a", "b", "foo.h"])
|
||||
t.run_build_system("-d+2 -f-", stdin=code + " DEPENDS all : foo.h ;")
|
||||
t.fail_test(not right_order(t.stdout()))
|
||||
t.fail_test(not correct_order(t.stdout()))
|
||||
|
||||
t.rm(["a", "b", "foo.h"])
|
||||
t.run_build_system("-d+2 -f-", stdin=" DEPENDS all : foo.h ; " + code)
|
||||
t.fail_test(not right_order(t.stdout()))
|
||||
t.fail_test(not correct_order(t.stdout()))
|
||||
|
||||
# Now foo.h exists. Test include from b -> foo.h -> bar.h -> biz.h
|
||||
# b and foo.h already have updating actions.
|
||||
# Now foo.h exists. Test include from b -> foo.h -> bar.h -> biz.h. b and foo.h
|
||||
# already have updating actions.
|
||||
t.rm(["a", "b"])
|
||||
t.write("foo.h", "#include <bar.h>")
|
||||
t.write("bar.h", "#include <biz.h>")
|
||||
t.run_build_system("-d+2 -f-", stdin=code)
|
||||
t.fail_test(find(t.stdout(), "...skipped a for lack of biz.h...") == -1)
|
||||
t.fail_test(string.find(t.stdout(), "...skipped a for lack of biz.h...") == -1)
|
||||
|
||||
# Add an action for biz.h
|
||||
# Add an action for biz.h.
|
||||
code += """
|
||||
actions create-biz
|
||||
{
|
||||
@@ -97,15 +99,15 @@ actions create-biz
|
||||
}
|
||||
create-biz biz.h ;
|
||||
"""
|
||||
|
||||
t.rm(["b"])
|
||||
right_order = mk_right_order_func("create-biz", "copy a")
|
||||
correct_order = mk_correct_order_func("create-biz", "copy a")
|
||||
t.run_build_system("-d+2 -f-", stdin=code + " DEPENDS all : biz.h ;")
|
||||
t.fail_test(not right_order(t.stdout()))
|
||||
t.fail_test(not correct_order(t.stdout()))
|
||||
|
||||
t.rm(["a", "biz.h"])
|
||||
t.run_build_system("-d+2 -f-", stdin=" DEPENDS all : biz.h ; " + code)
|
||||
t.fail_test(not right_order(t.stdout()))
|
||||
|
||||
t.fail_test(not correct_order(t.stdout()))
|
||||
|
||||
t.write("a", "")
|
||||
|
||||
@@ -147,10 +149,9 @@ rule hdrrule
|
||||
INCLUDES $(1) : d ;
|
||||
}
|
||||
"""
|
||||
right_order = mk_right_order_func("create-d", "copy main")
|
||||
|
||||
correct_order = mk_correct_order_func("create-d", "copy main")
|
||||
t.run_build_system("-d2 -f-", stdin=code)
|
||||
t.fail_test(not right_order(t.stdout()))
|
||||
|
||||
|
||||
t.fail_test(not correct_order(t.stdout()))
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,24 +1,23 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
|
||||
|
||||
t = Tester(pass_toolset=0)
|
||||
|
||||
# Test that
|
||||
t = BoostBuild.Tester(pass_toolset=0)
|
||||
|
||||
t.write("code", """
|
||||
module a {
|
||||
module a
|
||||
{
|
||||
rule r1 ( )
|
||||
{
|
||||
ECHO R1 ;
|
||||
}
|
||||
}
|
||||
module a2 {
|
||||
module a2
|
||||
{
|
||||
rule r2 ( )
|
||||
{
|
||||
ECHO R2 ;
|
||||
@@ -26,9 +25,9 @@ module a2 {
|
||||
}
|
||||
IMPORT a2 : r2 : : a2.r2 ;
|
||||
|
||||
module b {
|
||||
module b
|
||||
{
|
||||
IMPORT_MODULE a : b ;
|
||||
|
||||
rule test
|
||||
{
|
||||
# Call rule visible via IMPORT_MODULE
|
||||
@@ -41,19 +40,19 @@ module b {
|
||||
IMPORT b : test : : test ;
|
||||
test ;
|
||||
|
||||
module c {
|
||||
module c
|
||||
{
|
||||
rule test
|
||||
{
|
||||
ECHO CTEST ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IMPORT_MODULE c : ;
|
||||
c.test ;
|
||||
|
||||
actions do-nothing { }
|
||||
do-nothing all ;
|
||||
|
||||
""")
|
||||
|
||||
t.run_build_system("-fcode", stdout="""R1
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This tests the "existing" and "updated" modifiers on actions.
|
||||
|
||||
import BoostBuild
|
||||
from string import strip, replace
|
||||
import string
|
||||
|
||||
t = BoostBuild.Tester(pass_toolset=0)
|
||||
|
||||
code = """
|
||||
|
||||
DEPENDS all : a ;
|
||||
ALWAYS a ;
|
||||
NOTFILE a ;
|
||||
@@ -36,25 +35,17 @@ t.write("file.jam", code)
|
||||
t.write("a-1", "")
|
||||
|
||||
t.run_build_system("-ffile.jam")
|
||||
t.fail_test(strip(t.read("list")) != "a-1")
|
||||
t.fail_test(string.strip(t.read("list")) != "a-1")
|
||||
t.rm(["a-3", "list"])
|
||||
|
||||
code = replace(code, "existing", "updated")
|
||||
code = string.replace(code, "existing", "updated")
|
||||
t.write("file.jam", code)
|
||||
t.run_build_system("-ffile.jam")
|
||||
t.fail_test(strip(t.read("list")) != "a-3")
|
||||
t.fail_test(string.strip(t.read("list")) != "a-3")
|
||||
|
||||
code = replace(code, "updated", "existing updated")
|
||||
code = string.replace(code, "updated", "existing updated")
|
||||
t.write("file.jam", code)
|
||||
t.run_build_system("-ffile.jam")
|
||||
t.fail_test(strip(t.read("list")) != "a-1 a-3")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
t.fail_test(string.strip(t.read("list")) != "a-1 a-3")
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This tests the core rule for enumerating the variable names in a module
|
||||
# This tests the core rule for enumerating the variable names in a module.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
@@ -34,4 +34,5 @@ NOTFILE xx ;
|
||||
""")
|
||||
|
||||
t.run_build_system("-ffile.jam", status=0)
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -4,19 +4,17 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Attempt to declare a generator for creating OBJ from RC files. That generator
|
||||
# should be considered together with standard CPP->OBJ generators and
|
||||
# successfully create the target. Since we do not have a RC compiler everywhere,
|
||||
# we fake the action. The resulting OBJ will be unusable, but it must be
|
||||
# created.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t = Tester()
|
||||
|
||||
# Attempt to declare a generator for creating OBJ from RC files.
|
||||
# That generator should be considered together with standard
|
||||
# CPP->OBJ generators and successfully create the target.
|
||||
# Since we don't have RC compiler everywhere, we fake the action.
|
||||
# The resulting OBJ will be unusable, but it must be created.
|
||||
|
||||
t.write("project-root.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import rcc ;
|
||||
""")
|
||||
|
||||
@@ -25,8 +23,8 @@ import type ;
|
||||
import generators ;
|
||||
import print ;
|
||||
|
||||
# Use 'RCC' to avoid conflicts with definitions in
|
||||
# the standard rc.jam and msvc.jam
|
||||
# Use 'RCC' to avoid conflicts with definitions in the standard rc.jam and
|
||||
# msvc.jam
|
||||
type.register RCC : rcc ;
|
||||
|
||||
rule resource-compile ( targets * : sources * : properties * )
|
||||
@@ -36,10 +34,9 @@ rule resource-compile ( targets * : sources * : properties * )
|
||||
}
|
||||
|
||||
generators.register-standard rcc.resource-compile : RCC : OBJ ;
|
||||
|
||||
""")
|
||||
|
||||
t.write("Jamfile", """
|
||||
t.write("jamfile.jam", """
|
||||
obj r : r.rcc ;
|
||||
""")
|
||||
|
||||
@@ -50,6 +47,3 @@ t.run_build_system()
|
||||
t.expect_content("bin/$toolset/debug/r.obj", "rc-object")
|
||||
|
||||
t.cleanup()
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,38 +1,38 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2002, 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2002, 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that default build clause actually has any effect.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
|
||||
t.write("project-root.jam", "import gcc ;")
|
||||
t.write("Jamfile", "exe a : a.cpp : : debug release ;")
|
||||
t.write("a.cpp", "int main() { return 0; }\n")
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("jamroot.jam", "import gcc ;")
|
||||
t.write("jamfile.jam", "exe a : a.cpp : : debug release ;")
|
||||
t.write("a.cpp", "int main() {}\n")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/a.exe")
|
||||
t.expect_addition("bin/$toolset/release/a.exe")
|
||||
|
||||
# Check that explictly-specified build variant supresses
|
||||
# default-build
|
||||
# Check that explictly-specified build variant supresses default-build.
|
||||
t.rm("bin")
|
||||
t.run_build_system("release")
|
||||
t.expect_addition(List("bin/$toolset/release/") * "a.exe a.obj")
|
||||
t.expect_addition(BoostBuild.List("bin/$toolset/release/") * "a.exe a.obj")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Now check that we can specify explicit build request and
|
||||
# default-build will be combined with it
|
||||
# Now check that we can specify explicit build request and default-build will be
|
||||
# combined with it.
|
||||
t.run_build_system("optimization=space")
|
||||
t.expect_addition("bin/$toolset/debug/optimization-space/a.exe")
|
||||
t.expect_addition("bin/$toolset/release/optimization-space/a.exe")
|
||||
|
||||
# Test that default-build must be identical in all alternatives. Error case.
|
||||
t.write("Jamfile", """
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a.cpp : : debug ;
|
||||
exe a : b.cpp : : ;
|
||||
""")
|
||||
@@ -44,40 +44,40 @@ differing from previous default build <variant>debug
|
||||
"""
|
||||
t.run_build_system("-n --no-error-backtrace", status=1, stdout=expected)
|
||||
|
||||
# Test that default-build must be identical in all alternatives. No Error case, empty default build.
|
||||
t.write("Jamfile", """
|
||||
# Test that default-build must be identical in all alternatives. No Error case,
|
||||
# empty default build.
|
||||
t.write("jamfile.jam", """
|
||||
exe a : a.cpp : <variant>debug ;
|
||||
exe a : b.cpp : <variant>release ;
|
||||
""")
|
||||
t.run_build_system("-n --no-error-backtrace", status=0)
|
||||
|
||||
|
||||
# Now try a harder example: default build which contains <define>
|
||||
# should cause <define> to be present when "b" is compiled.
|
||||
# This happens only of "build-project b" is placed first.
|
||||
t.write("Jamfile", """
|
||||
project
|
||||
: default-build <define>FOO
|
||||
;
|
||||
|
||||
build-project a ;
|
||||
build-project b ;
|
||||
# Now try a harder example: default build which contains <define> should cause
|
||||
# <define> to be present when "b" is compiled. This happens only if
|
||||
# "build-project b" is placed first.
|
||||
t.write("jamfile.jam", """
|
||||
project : default-build <define>FOO ;
|
||||
build-project a ;
|
||||
build-project b ;
|
||||
""")
|
||||
|
||||
t.write("a/Jamfile", """
|
||||
exe a : a.cpp ../b//b ;
|
||||
t.write("a/jamfile.jam", """
|
||||
exe a : a.cpp ../b//b ;
|
||||
""")
|
||||
|
||||
t.write("a/a.cpp", """
|
||||
#ifdef _WIN32
|
||||
__declspec(dllimport)
|
||||
#endif
|
||||
void foo();
|
||||
int main() { foo(); return 0; }
|
||||
int main() { foo(); }
|
||||
""")
|
||||
|
||||
t.write("b/Jamfile", """
|
||||
lib b : b.cpp ;
|
||||
t.write("b/jamfile.jam", """
|
||||
lib b : b.cpp ;
|
||||
""")
|
||||
|
||||
t.write("b/b.cpp", """
|
||||
#ifdef FOO
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -1,44 +1,39 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
# Copyright 2003 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Test that features with default values are always present
|
||||
# in build properties of any target.
|
||||
# Test that features with default values are always present in build properties
|
||||
# of any target.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
# Declare *non-propagated* feature foo.
|
||||
t.write("project-root.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import feature : feature ;
|
||||
|
||||
feature foo : on off ;
|
||||
""")
|
||||
|
||||
# Note that '<foo>on' won't be propagated
|
||||
# to 'd/l'.
|
||||
t.write("Jamfile", """
|
||||
# Note that '<foo>on' will not be propagated to 'd/l'.
|
||||
t.write("jamfile.jam", """
|
||||
exe hello : hello.cpp d//l ;
|
||||
""")
|
||||
|
||||
t.write("hello.cpp", """
|
||||
#ifdef _WIN32
|
||||
__declspec(dllimport)
|
||||
#endif
|
||||
void foo();
|
||||
int main()
|
||||
{
|
||||
foo();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int main() { foo(); }
|
||||
""")
|
||||
|
||||
t.write("d/Jamfile", """
|
||||
t.write("d/jamfile.jam", """
|
||||
lib l : l.cpp : <foo>on:<define>FOO ;
|
||||
""")
|
||||
|
||||
t.write("d/l.cpp", """
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
@@ -46,7 +41,6 @@ __declspec(dllexport)
|
||||
#ifdef FOO
|
||||
void foo() {}
|
||||
#endif
|
||||
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
|
||||
@@ -58,7 +58,7 @@ rule init ( version ) { ECHO "%(message_initialized)s" ; }
|
||||
'toolset_version_unused': toolset_version_unused})
|
||||
|
||||
# Main Boost Build project script.
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import build-system ;
|
||||
import errors ;
|
||||
import feature ;
|
||||
@@ -121,7 +121,7 @@ def test_default_toolset_on_os( os, expected_toolset ):
|
||||
t = BoostBuild.Tester("--user-config= --ignore-site-config",
|
||||
pass_toolset=False, use_test_config=False)
|
||||
|
||||
t.write("Jamroot.jam", "modules.poke os : .name : %s ;" % os)
|
||||
t.write("jamroot.jam", "modules.poke os : .name : %s ;" % os)
|
||||
|
||||
# We need to tell the test system to ignore stderr output as attempting to
|
||||
# load missing toolsets might cause random failures with which we are not
|
||||
@@ -159,7 +159,7 @@ rule init ( ) { }
|
||||
""" % {'toolset_name': toolset_name})
|
||||
|
||||
# Main Boost Build project script.
|
||||
t.write("Jamroot.jam", """
|
||||
t.write("jamroot.jam", """
|
||||
import build-system ;
|
||||
import errors ;
|
||||
import feature ;
|
||||
|
||||
@@ -4,30 +4,25 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# Regression test: virtual targets with different dependency properties
|
||||
# were considered different by 'virtual-target.register', but the code
|
||||
# which determined target paths ignored dependency properties --- so both
|
||||
# targets used to be placed to the same location.
|
||||
# Regression test: virtual targets with different dependency properties were
|
||||
# considered different by 'virtual-target.register', but the code which
|
||||
# determined target paths ignored dependency properties --- so both targets used
|
||||
# to be placed to the same location.
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
from string import find
|
||||
import BoostBuild
|
||||
import string
|
||||
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("project-root.jam", "")
|
||||
t.write("Jamfile", """
|
||||
t.write("jamroot.jam", """
|
||||
lib foo : foo.cpp ;
|
||||
exe hello : hello.cpp ;
|
||||
exe hello2 : hello.cpp : <library>foo ;
|
||||
""")
|
||||
t.write("hello.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
""")
|
||||
t.write("hello.cpp", "int main() {}\n")
|
||||
|
||||
t.write("foo.cpp", """
|
||||
#ifdef _WIN32
|
||||
__declspec(dllexport)
|
||||
@@ -36,6 +31,6 @@ void foo() {}
|
||||
""")
|
||||
|
||||
t.run_build_system("--no-error-backtrace", status=1)
|
||||
t.fail_test(find(t.stdout(), "Duplicate name of actual target") == -1)
|
||||
t.fail_test(string.find(t.stdout(), "Duplicate name of actual target") == -1)
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -5,19 +5,20 @@
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import BoostBuild
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.set_tree("dependency-test")
|
||||
|
||||
t.run_build_system()
|
||||
# Check that main target 'c' was able to find 'x.h' from
|
||||
# 'a's dependency graph
|
||||
|
||||
# Check that main target 'c' was able to find 'x.h' from 'a's dependency graph.
|
||||
t.expect_addition("bin/$toolset/debug/c.exe")
|
||||
|
||||
# Check handling of first level includes.
|
||||
|
||||
# Both 'a' and 'b' include "a.h" and should be updated
|
||||
# Both 'a' and 'b' include "a.h" and should be updated.
|
||||
t.touch("a.h")
|
||||
t.run_build_system()
|
||||
|
||||
@@ -26,14 +27,13 @@ t.expect_touch("bin/$toolset/debug/a.obj")
|
||||
t.expect_touch("bin/$toolset/debug/a_c.obj")
|
||||
t.expect_touch("bin/$toolset/debug/b.exe")
|
||||
t.expect_touch("bin/$toolset/debug/b.obj")
|
||||
# Now, <dependency> does not add dependency.
|
||||
# It sound weird, but is intentional. Need
|
||||
# to rename <dependency> eventually.
|
||||
# Now, <dependency> does not add a dependency. It sound weird, but is
|
||||
# intentional. Need to rename <dependency> eventually.
|
||||
#t.expect_touch("bin/$toolset/debug/main-target-c/c.exe")
|
||||
t.ignore("*.tds")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Only 'a' include <a.h> and should be updated
|
||||
# Only 'a' include <a.h> and should be updated.
|
||||
t.touch("src1/a.h")
|
||||
t.run_build_system()
|
||||
|
||||
@@ -43,7 +43,7 @@ t.expect_touch("bin/$toolset/debug/a_c.obj")
|
||||
t.ignore("*.tds")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# "src/a.h" includes "b.h" (in the same dir)
|
||||
# "src/a.h" includes "b.h" (in the same dir).
|
||||
t.touch("src1/b.h")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/$toolset/debug/a.exe")
|
||||
@@ -52,8 +52,8 @@ t.expect_touch("bin/$toolset/debug/a_c.obj")
|
||||
t.ignore("*.tds")
|
||||
t.expect_nothing_more()
|
||||
|
||||
# included by "src/b.h". We had a bug: file included via "",
|
||||
# like "b.h" is in this case was not scanned at all.
|
||||
# Included by "src/b.h". We had a bug: file included via "", like "b.h" is in
|
||||
# this case was not scanned at all.
|
||||
t.touch("src1/c.h")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/$toolset/debug/a.exe")
|
||||
@@ -62,41 +62,38 @@ t.touch("b.h")
|
||||
t.run_build_system()
|
||||
t.expect_nothing_more()
|
||||
|
||||
# Test dependency on generated header.
|
||||
# TODO: we have also to check that generated header is found correctly
|
||||
# if it is different for different subvariants. Lacking any toolset
|
||||
# support, this check will be implemented later.
|
||||
# Test dependency on a generated header.
|
||||
#
|
||||
# TODO: we have also to check that generated header is found correctly if it is
|
||||
# different for different subvariants. Lacking any toolset support, this check
|
||||
# will be implemented later.
|
||||
t.touch("x.foo")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/$toolset/debug/a.obj")
|
||||
t.expect_touch("bin/$toolset/debug/a_c.obj")
|
||||
|
||||
# Check that generated headers are scanned for dependencies as well
|
||||
# Check that generated headers are scanned for dependencies as well.
|
||||
t.touch("src1/z.h")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/$toolset/debug/a.obj")
|
||||
t.expect_touch("bin/$toolset/debug/a_c.obj")
|
||||
|
||||
# Regression test: on windows, <includes> with absolute paths
|
||||
# were not considered when scanning dependencies.
|
||||
|
||||
# Regression test: on Windows, <includes> with absolute paths were not
|
||||
# considered when scanning dependencies.
|
||||
t.rm(".")
|
||||
|
||||
t.write("Jamroot", """
|
||||
t.write("jamroot.jam", """
|
||||
path-constant TOP : . ;
|
||||
exe app : main.cpp
|
||||
: <include>$(TOP)/include
|
||||
;
|
||||
exe app : main.cpp : <include>$(TOP)/include ;
|
||||
""");
|
||||
|
||||
t.write("main.cpp", """
|
||||
#include <dir/header.h>
|
||||
|
||||
int main() { return 0; }
|
||||
|
||||
int main() {}
|
||||
""")
|
||||
|
||||
t.write("include/dir/header.h", "")
|
||||
|
||||
t.run_build_system()
|
||||
t.expect_addition("bin/$toolset/debug/main.obj")
|
||||
|
||||
@@ -104,6 +101,4 @@ t.touch("include/dir/header.h")
|
||||
t.run_build_system()
|
||||
t.expect_touch("bin/$toolset/debug/main.obj")
|
||||
|
||||
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,46 +1,40 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
from BoostBuild import Tester, List
|
||||
import os
|
||||
from string import strip
|
||||
import BoostBuild
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
# First check some startup
|
||||
|
||||
# First check some startup.
|
||||
t.set_tree("direct-request-test")
|
||||
t.run_build_system(extra_args="define=MACROS")
|
||||
|
||||
t.expect_addition("bin/$toolset/debug/"
|
||||
* (List("a.obj b.obj b.dll a.exe")))
|
||||
* (BoostBuild.List("a.obj b.obj b.dll a.exe")))
|
||||
|
||||
# When building debug version, the 'define' still applies
|
||||
|
||||
# When building a debug version, the 'define' still applies.
|
||||
t.rm("bin")
|
||||
t.run_build_system(extra_args="debug define=MACROS")
|
||||
t.expect_addition("bin/$toolset/debug/"
|
||||
* (List("a.obj b.obj b.dll a.exe")))
|
||||
* (BoostBuild.List("a.obj b.obj b.dll a.exe")))
|
||||
|
||||
# When building release version, the 'define' should not
|
||||
# apply: we'll have direct build request 'release <define>MACROS'
|
||||
# and real build properties 'debug'.
|
||||
t.copy("Jamfile2", "Jamfile")
|
||||
|
||||
# When building release version, the 'define' should not apply: we will have
|
||||
# direct build request 'release <define>MACROS' and a real build property
|
||||
# 'debug'.
|
||||
t.copy("jamfile2.jam", "jamfile.jam")
|
||||
t.copy("b_inverse.cpp", "b.cpp")
|
||||
t.rm("bin")
|
||||
t.run_build_system(extra_args="release define=MACROS")
|
||||
|
||||
|
||||
# Regression test: direct build request was not working
|
||||
# when there's more than one level of 'build-project'
|
||||
|
||||
# Regression test: direct build request was not working when there was more than
|
||||
# one level of 'build-project'.
|
||||
t.rm(".")
|
||||
t.write('project-root.jam', '')
|
||||
t.write('Jamfile', 'build-project a ;')
|
||||
t.write('a/Jamfile', 'build-project b ;')
|
||||
t.write('a/b/Jamfile', '')
|
||||
|
||||
t.write('jamroot.jam', '')
|
||||
t.write('jamfile.jam', 'build-project a ;')
|
||||
t.write('a/jamfile.jam', 'build-project b ;')
|
||||
t.write('a/b/jamfile.jam', '')
|
||||
t.run_build_system("release")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# Copyright (C) Vladimir Prus 2006.
|
||||
# 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)
|
||||
# Copyright (C) Vladimir Prus 2006.
|
||||
# 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)
|
||||
|
||||
# Test that it's possible to add a suffix to a main target name to
|
||||
# disambiguate that main target from another, and that this does not
|
||||
# affect the names of the generated targets.
|
||||
from BoostBuild import Tester, List
|
||||
# Test that it is possible to add a suffix to a main target name to disambiguate
|
||||
# that main target from another, and that this does not affect the names of the
|
||||
# generated targets.
|
||||
|
||||
# Create a temporary working directory
|
||||
t = Tester()
|
||||
import BoostBuild
|
||||
|
||||
# Create the needed files
|
||||
t.write("Jamroot", """
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
t.write("jamroot.jam", """
|
||||
exe hello.exe : hello.obj ;
|
||||
obj hello.obj : hello.cpp : <variant>debug ;
|
||||
obj hello.obj2 : hello.cpp : <variant>release ;
|
||||
""")
|
||||
t.write("hello.cpp", """
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
t.write("hello.cpp", """
|
||||
int main() {}
|
||||
""")
|
||||
|
||||
t.run_build_system()
|
||||
@@ -33,5 +29,4 @@ t.expect_addition("bin/$toolset/debug/hello.exe")
|
||||
t.expect_addition("bin/$toolset/debug/hello.obj")
|
||||
t.expect_addition("bin/$toolset/release/hello.obj")
|
||||
|
||||
|
||||
t.cleanup()
|
||||
|
||||
@@ -1,41 +1,38 @@
|
||||
#!/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.
|
||||
# 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.
|
||||
|
||||
# Test that the <dll-path> property is correctly set when using
|
||||
# <hardcode-dll-paths>true.
|
||||
from BoostBuild import Tester, List
|
||||
from string import find
|
||||
# Test that the <dll-path> property is correctly set when using
|
||||
# <hardcode-dll-paths>true.
|
||||
|
||||
import BoostBuild
|
||||
|
||||
t = Tester()
|
||||
t = BoostBuild.Tester()
|
||||
|
||||
# The point of this test is to have exe "main" which uses library "b",
|
||||
# which uses library "a". When "main" is built with <hardcode-dll-paths>true,
|
||||
# paths to both libraries should be present as values of <dll-path> feature.
|
||||
# We create a special target type which reports <dll-path> values on its sources
|
||||
# and compare the list of found values with out expectations.
|
||||
# The point of this test is to have exe "main" which uses library "b", which
|
||||
# uses library "a". When "main" is built with <hardcode-dll-paths>true, paths to
|
||||
# both libraries should be present as values of <dll-path> feature. We create a
|
||||
# special target type which reports <dll-path> values on its sources and compare
|
||||
# the list of found values with out expectations.
|
||||
|
||||
t.write("Jamfile", """
|
||||
t.write("jamfile.jam", """
|
||||
exe main : main.cpp b//b ;
|
||||
explicit main ;
|
||||
|
||||
path-list mp : main ;
|
||||
path-list mp : main ;
|
||||
""")
|
||||
|
||||
t.write("main.cpp", """
|
||||
int main() { return 0; }
|
||||
|
||||
t.write("main.cpp", """
|
||||
int main() {}
|
||||
""")
|
||||
|
||||
t.write("project-root.jam", """
|
||||
using dll-paths ;
|
||||
t.write("jamroot.jam", """
|
||||
using dll-paths ;
|
||||
""")
|
||||
|
||||
t.write("dll-paths.jam", """
|
||||
t.write("dll-paths.jam", """
|
||||
import type ;
|
||||
import generators ;
|
||||
import feature ;
|
||||
@@ -43,18 +40,18 @@ import sequence ;
|
||||
import print ;
|
||||
import "class" : new ;
|
||||
|
||||
rule init ( )
|
||||
{
|
||||
rule init ( )
|
||||
{
|
||||
type.register PATH_LIST : pathlist ;
|
||||
|
||||
class dll-paths-list-generator : generator
|
||||
|
||||
class dll-paths-list-generator : generator
|
||||
{
|
||||
rule __init__ ( )
|
||||
{
|
||||
generator.__init__ dll-paths.list : EXE : PATH_LIST ;
|
||||
}
|
||||
|
||||
rule generated-targets ( sources + : property-set : project name ? )
|
||||
|
||||
rule generated-targets ( sources + : property-set : project name ? )
|
||||
{
|
||||
local dll-paths ;
|
||||
for local s in $(sources)
|
||||
@@ -64,15 +61,15 @@ rule init ( )
|
||||
{
|
||||
local p = [ $(a).properties ] ;
|
||||
dll-paths += [ $(p).get <dll-path> ] ;
|
||||
}
|
||||
}
|
||||
}
|
||||
return [ generator.generated-targets $(sources)
|
||||
: [ $(property-set).add-raw $(dll-paths:G=<dll-path>) ] : $(project) $(name) ] ;
|
||||
|
||||
return [ generator.generated-targets $(sources) :
|
||||
[ $(property-set).add-raw $(dll-paths:G=<dll-path>) ] :
|
||||
$(project) $(name) ] ;
|
||||
|
||||
}
|
||||
}
|
||||
generators.register [ new dll-paths-list-generator ] ;
|
||||
|
||||
}
|
||||
|
||||
rule list ( target : sources * : properties * )
|
||||
@@ -82,35 +79,30 @@ rule list ( target : sources * : properties * )
|
||||
print.output $(target) ;
|
||||
print.text $(paths) ;
|
||||
}
|
||||
|
||||
""")
|
||||
|
||||
t.write("a/a.cpp", """
|
||||
t.write("a/a.cpp", """
|
||||
void
|
||||
#if defined(_WIN32)
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
foo() {}
|
||||
|
||||
|
||||
""")
|
||||
|
||||
t.write("a/Jamfile", """
|
||||
lib a : a.cpp ;
|
||||
t.write("a/jamfile.jam", """
|
||||
lib a : a.cpp ;
|
||||
""")
|
||||
|
||||
t.write("b/b.cpp", """
|
||||
t.write("b/b.cpp", """
|
||||
void
|
||||
#if defined(_WIN32)
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
bar() {}
|
||||
|
||||
|
||||
""")
|
||||
|
||||
t.write("b/Jamfile", """
|
||||
lib b : b.cpp ../a//a ;
|
||||
t.write("b/jamfile.jam", """
|
||||
lib b : b.cpp ../a//a ;
|
||||
""")
|
||||
|
||||
t.run_build_system("hardcode-dll-paths=true")
|
||||
@@ -124,4 +116,3 @@ t.expect_content_line("bin/$toolset/debug/mp.pathlist", "*" + es1);
|
||||
t.expect_content_line("bin/$toolset/debug/mp.pathlist", "*" + es2);
|
||||
|
||||
t.cleanup()
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user