/usr/share/boost-build/src/build
Edit: /usr/share/boost-build/src/build/build-request.jam (12722B)
# Copyright 2002 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)
import "class" : new ;
import sequence ;
import set ;
import regex ;
import feature ;
import property ;
import container ;
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) ] ;
return [ string.join [ $(f) $(properties) ] : / ] ;
}
# 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.
local expanded-property-sets = [ sequence.transform apply-to-property-set
feature.expand-subfeatures : $(property-sets) ] ;
# Now combine all of the expanded property-sets
local product = [ x-product $(expanded-property-sets) : $(feature-space) ] ;
return $(product) ;
}
# Update the list of expected conflicts based on the new
# features.
#
local rule remove-conflicts ( conflicts * : features * )
{
local result ;
for local c in $(conflicts)
{
if ! [ set.intersection [ regex.split $(c) "/" ] : $(features) ]
{
result += $(c) ;
}
}
return $(result) ;
}
# Implementation of x-product, below. Expects all the project files to already
# be loaded.
#
local rule x-product-aux ( property-sets + )
{
local result ;
local p = [ feature.split $(property-sets[1]) ] ;
local f = [ set.difference $(p:G) : [ feature.free-features ] ] ;
local seen ;
local extra-conflicts ;
# No conflict with things used at a higher level?
if ! [ set.intersection $(f) : $(x-product-used) ]
{
local x-product-seen ;
local x-product-conflicts =
[ remove-conflicts $(x-product-conflicts) : $(f) ] ;
{
# Do not mix in any conflicting features.
local x-product-used = $(x-product-used) $(f) ;
if $(property-sets[2])
{
local rest = [ x-product-aux $(property-sets[2-]) ] ;
result = $(property-sets[1])/$(rest) ;
}
if ! $(x-product-conflicts)
{
result ?= $(property-sets[1]) ;
}
}
# If we did not encounter a conflicting feature lower down, do not
# recurse again.
if ! [ set.intersection $(f) : $(x-product-seen) ]
|| [ remove-conflicts $(x-product-conflicts) : $(x-product-seen) ]
{
property-sets = ;
}
else
{
# A property is only allowed to be absent if it conflicts
# with either a higher or lower layer. We don't need to
# bother setting this if we already know that we don't need
# to recurse again.
extra-conflicts = $(f:J=/) ;
}
seen = $(x-product-seen) ;
}
if $(property-sets[2])
{
# Lower layers expansion must conflict with this
local x-product-conflicts = $(x-product-conflicts) $(extra-conflicts) ;
result += [ x-product-aux $(property-sets[2-]) ] ;
}
# Note that we have seen these features so that higher levels will recurse
# again without them set.
x-product-seen += $(f) $(seen) ;
return $(result) ;
}
# 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.
#
# Formal definition:
# Returns all maximum non-conflicting subsets of property-sets.
# The result is a list of all property-sets p such that
# 1. p is composed by joining a subset of property-sets without removing
# duplicates
# 2. p contains at most one instance of every single-valued feature
# 3. Adding any additional element of property-sets to p be would
# violate (2)
local rule x-product ( property-sets * )
{
if $(property-sets).non-empty
{
# Prepare some "scoped globals" that can be used by the implementation
# function, x-product-aux.
local x-product-seen x-product-used x-product-conflicts ;
return [ x-product-aux $(property-sets) : $(feature-space) ] ;
}
# Otherwise return empty.
}
# 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) ]
{
return true ;
}
else
{
local split = [ regex.split $(v) - ] ;
if [ feature.is-implicit-value $(split[1]) ]
{
return true ;
}
}
}
# Takes the command line tokens (such as taken from the ARGV rule) and
# constructs a build request from them. Returns a vector of two vectors (where
# "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 ;
local properties ;
command-line = $(command-line[2-]) ;
local skip-next = ;
for local e in $(command-line)
{
if $(skip-next)
{
skip-next = ;
}
else if ! [ MATCH ^(-) : $(e) ]
{
# Build request spec either has "=" in it or completely consists of
# implicit feature values.
local fs = feature-space ;
if [ MATCH "(.*=.*)" : $(e) ]
|| [ looks-like-implicit-value $(e:D=) : $(feature-space) ]
{
properties += $(e) ;
}
else if $(e)
{
targets += $(e) ;
}
}
else if [ MATCH "^(-[-ldjfsto])$" : $(e) ]
{
skip-next = true ;
}
}
return [ new vector
[ new vector $(targets) ]
[ new vector $(properties) ] ] ;
}
# Converts a list of elements of command line build request specification into internal
# form. Expects all the project files to already be loaded.
#
rule convert-command-line-elements ( elements * )
{
local result ;
for local e in $(elements)
{
result += [ convert-command-line-element $(e) ] ;
}
return $(result) ;
}
# Converts one element of command line build request specification into internal
# form.
local rule convert-command-line-element ( e )
{
local result ;
local parts = [ regex.split $(e) "/" ] ;
while $(parts)
{
local p = $(parts[1]) ;
local m = [ MATCH "([^=]*)=(.*)" : $(p) ] ;
local lresult ;
local feature ;
local values ;
if $(m)
{
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
# here.
for local p in $(lresult)
{
property.validate $(p) : $(feature-space) ;
}
}
if ! $(result)
{
result = $(lresult) ;
}
else
{
result = $(result)/$(lresult) ;
}
parts = $(parts[2-]) ;
}
return $(result) ;
}
rule __test__ ( )
{
import assert ;
import feature ;
feature.prepare-test build-request-test-temp ;
import build-request ;
import build-request : expand-no-defaults : build-request.expand-no-defaults ;
import errors : try catch ;
import feature : feature subfeature ;
feature toolset : gcc msvc borland : implicit ;
subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4
3.0 3.0.1 3.0.2 : optional ;
feature variant : debug release : implicit composite ;
feature inlining : on off ;
feature "include" : : free ;
feature stdlib : native stlport : implicit ;
feature runtime-link : dynamic static : symmetric ;
# Empty build requests should expand to empty.
assert.result
: build-request.expand-no-defaults ;
assert.result
gcc/3.0.1/stlport/debug
msvc/stlport/debug
msvc/debug
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug ;
assert.result
gcc/3.0.1/stlport/debug
msvc/debug
debug/msvc/stlport
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport ;
assert.result
gcc/3.0.1/stlport/debug/off
gcc/3.0.1/stlport/release/off
: build-request.expand-no-defaults gcc-3.0.1/stlport debug release off ;
assert.result
a/b/c/gcc/3.0.1/stlport/debug/x/y/z
a/b/c/msvc/stlport/debug/x/y/z
a/b/c/msvc/debug/x/y/z
: build-request.expand-no-defaults a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug x/y/z ;
local r ;
try ;
{
r = [ build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ] ;
build-request.convert-command-line-elements [ $(r).get-at 2 ] ;
}
catch \"static\" is not an implicit feature value ;
r = [ build-request.from-command-line bjam debug runtime-link=dynamic ] ;
assert.equal [ $(r).get-at 1 ] : ;
assert.equal [ $(r).get-at 2 ] : debug runtime-link=dynamic ;
assert.equal
[ build-request.convert-command-line-elements debug runtime-link=dynamic ]
: debug dynamic ;
r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ;
assert.equal [ $(r).get-at 1 ] : target ;
assert.equal [ $(r).get-at 2 ] : debug runtime-link=dynamic ;
assert.equal
[ build-request.convert-command-line-elements debug runtime-link=dynamic ]
: debug dynamic ;
r = [ build-request.from-command-line bjam debug runtime-link=dynamic,static ] ;
assert.equal [ $(r).get-at 1 ] : ;
assert.equal [ $(r).get-at 2 ] : debug runtime-link=dynamic,static ;
assert.equal
[ build-request.convert-command-line-elements debug runtime-link=dynamic,static ]
: debug dynamic static ;
r = [ build-request.from-command-line bjam debug gcc/runtime-link=dynamic,static ] ;
assert.equal [ $(r).get-at 1 ] : ;
assert.equal [ $(r).get-at 2 ] : debug gcc/runtime-link=dynamic,static ;
assert.equal
[ build-request.convert-command-line-elements debug gcc/runtime-link=dynamic,static ]
: debug gcc/dynamic gcc/static ;
r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static ] ;
assert.equal [ $(r).get-at 1 ] : ;
assert.equal [ $(r).get-at 2 ] : msvc gcc,borland/runtime-link=static ;
assert.equal
[ build-request.convert-command-line-elements msvc gcc,borland/runtime-link=static ]
: msvc gcc/static borland/static ;
r = [ build-request.from-command-line bjam gcc-3.0 ] ;
assert.equal [ $(r).get-at 1 ] : ;
assert.equal [ $(r).get-at 2 ] : gcc-3.0 ;
assert.equal
[ build-request.convert-command-line-elements gcc-3.0 ]
: gcc-3.0 ;
feature.finish-test build-request-test-temp ;
}