1569 lines
46 KiB
Plaintext
1569 lines
46 KiB
Plaintext
# (C) Copyright David Abrahams and Carlos Pinto Coelho 2001. 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.
|
|
#
|
|
# Jamrules file by David Abrahams (abrahams@mediaone.net) and Carlos Pinto
|
|
# Coelho (cfspc@altrabroadband.com).
|
|
|
|
# Notes on the design of the system:
|
|
#
|
|
# This system is designed to support building the "same" targets with multiple
|
|
# build tool suites (e.g. msvc, gcc,...) and build variants (e.g. debug,
|
|
# release...). Although it currently varies across two dimensions, it should
|
|
# trivially support extension to three or more, e.g. in case of cross-platform
|
|
# builds. The word "same" is written in quotes above because internally,
|
|
# separate targets are generated for each unique toolset/build-variant
|
|
# combination.
|
|
#
|
|
# Specifics of build tool suites are specified in files with names of the form
|
|
# "<name>-tools.jam", where <name> is the name used to identify the tool suite.
|
|
|
|
# Workarounds for Jam limitations:
|
|
#
|
|
# 1. Jam supports something like the setting of attributes on targets using the
|
|
# syntax:
|
|
# <name> on <target> = <expression>
|
|
#
|
|
# This facility is used to control build actions for individual targets
|
|
# (target-specific variables take precedence over global ones when build
|
|
# actions # are executed). An obvious approach would be to use target
|
|
# attributes to hold # properties of build tools (e.g. where to find the
|
|
# standard includes). # Unfortunately, although you can write target
|
|
# attributes, there is no way to # read them. Instead, we take advantage of
|
|
# two properties of Jam:
|
|
#
|
|
# a. A variable name can be formed by evaluating an expression. For example,
|
|
# the following rule, appends FOOBAR to its first argument to form the
|
|
# name of a new variable, which is given the value "baz"
|
|
#
|
|
# rule X { $(1)FOOBAR = baz ; }
|
|
#
|
|
# b. Any character is allowed in a variable name. So, although they are
|
|
# actually global variables, we can form names like <name>.c++-flags thus:
|
|
#
|
|
# C++FLAGS = $($(1).c++-flags) # Get the c++-flags "attribute" from $(1)
|
|
#
|
|
# 2. There is no way to call a rule based on the value of a variable
|
|
# other than by using a switch statement. Because that approach requires
|
|
# intrusive changes to rules when the system is extended, we have avoided
|
|
# it. Instead, we have taken advantage of two "features" of Jam:
|
|
#
|
|
# a. The name of a file to be included can be computed from an
|
|
# expression. For example, the following includes a file whose name is
|
|
# formed by concatenating $(1) and "-tools.jam":
|
|
#
|
|
# include $(1)-tools.jam
|
|
#
|
|
# b. A rule can be redefined any number of times. Its latest definition is
|
|
# the one invoked. For example, the following prints "#2".
|
|
#
|
|
# rule X { ECHO #1 ; }
|
|
# rule X { ECHO #2 ; }
|
|
# X ;
|
|
#
|
|
# Together, these facts allow us to select tool-suite-specific actions for
|
|
# building specific target types by repeatedly redefining the generalized
|
|
# build actions in the various <build-tools>-tools.jam files
|
|
|
|
if $(NT)
|
|
{
|
|
TOOLS ?= borland gcc metrowerks msvc ;
|
|
}
|
|
else
|
|
{
|
|
TOOLS ?= gcc ;
|
|
}
|
|
|
|
SHARED_TYPES = DLL ;
|
|
|
|
# detect-build-tools <tools-name> : <detection-command>
|
|
#
|
|
# Declares a pseudotarget for the specified build tools which is built by
|
|
# the given <detection-command>.
|
|
#
|
|
# Although not currently implemented, the plan is to make compilation of
|
|
# tool-specific targets dependent on this pseudotarget. That way, we will never
|
|
# even attempt to build targets for tools that don't exist.
|
|
rule detect-build-tools
|
|
{
|
|
detection-command on $(<) = $($(<).bin-directory)$(>) ;
|
|
}
|
|
|
|
rule library-file
|
|
{
|
|
LibraryFromObjects $(<) : [ Objects $(>) ] ;
|
|
}
|
|
|
|
rule executable-file
|
|
{
|
|
type-DEPENDS exe : $(<) ;
|
|
main-from-objects $(<) : [ Objects $(>) ] : EXE ;
|
|
}
|
|
|
|
rule dll-files ( module implib ? : sources * : target-type ? )
|
|
{
|
|
type-DEPENDS dll : $(<) ;
|
|
|
|
# Set up the import library dependency on Windows
|
|
if $(<[2])
|
|
{
|
|
INCLUDES $(<[1]) : $(<[2-]) ;
|
|
INCLUDES $(<[2-]) : $(<[1]) ;
|
|
}
|
|
target-type ?= DLL ;
|
|
main-from-objects $(<) : [ Objects $(>) ] : $(target-type) ;
|
|
}
|
|
|
|
# main-from-objects exe-target : obj-target... : ("EXE"|"DLL")
|
|
#
|
|
# generate instructions to build the given "main" target from the given object
|
|
# files given in the 2nd parameter. The 3rd parameter should be EXE for an
|
|
# executable, or DLL for a shared library.
|
|
rule main-from-objects
|
|
{
|
|
# make compiled sources a dependency of target
|
|
|
|
MakeLocate $(<) : $(LOCATE_TARGET) ;
|
|
|
|
Clean clean : $(<) ;
|
|
|
|
MODE on $(<) = $($(3)MODE) ;
|
|
local link-function = Link-$(3) ;
|
|
local ignored = [ $(link-function) $(<) : $(>) : $(3) ] ;
|
|
Chmod $(<[1]) ;
|
|
DEPENDS $(<) : $(>) ;
|
|
}
|
|
|
|
rule Link-EXE
|
|
{
|
|
# N.B. By the time this rule is invoked, we had better have gRUN_PATH completely set.
|
|
Link-action $(<) : $(>) : EXE ;
|
|
RUN_PATH on $(<) = [ join $(gRUN_PATH($(<))) $(RUN_PATH) : $(SPLITPATH) ] ;
|
|
if $(UNIX)
|
|
{
|
|
RUN_LD_LIBRARY_PATH on $(<) = [ join $(gRUN_LD_LIBRARY_PATH($(<))) $(RUN_LD_LIBRARY_PATH) : $(SPLITPATH) ] ;
|
|
}
|
|
}
|
|
|
|
rule Link-DLL
|
|
{
|
|
if $(<[2])
|
|
{
|
|
MODE on $(<[2]) = $(IMPMODE) ;
|
|
Chmod $(<[2]) ;
|
|
}
|
|
|
|
gRUN_PATH($(<)) += $(gLOCATE($(<[1]))) ;
|
|
if $(UNIX)
|
|
{
|
|
gRUN_LD_LIBRARY_PATH($(<)) += $(gLOCATE($(<[1]))) ;
|
|
}
|
|
Link-action $(<) : $(>) : DLL ;
|
|
}
|
|
|
|
# store the shell's PATH again, just in case someone uses PATH.
|
|
# This also allows the user to customize the base path for running built
|
|
# products from the command-line
|
|
RUN_PATH ?= $(PATH) ;
|
|
if $(UNIX)
|
|
{
|
|
RUN_LD_LIBRARY_PATH ?= $(LD_LIBRARY_PATH) ;
|
|
}
|
|
if $(NT)
|
|
{
|
|
# Try some other likely spellings
|
|
RUN_PATH ?= $(Path) ;
|
|
RUN_PATH ?= $(path) ;
|
|
}
|
|
# Now set this, just in case someone tries to use it.
|
|
PATH = $(RUN_PATH) ;
|
|
if $(UNIX)
|
|
{
|
|
LD_LIBRARY_PATH = $(RUN_LD_LIBRARY_PATH) ;
|
|
}
|
|
|
|
# A simple action to run an executable target
|
|
if $(UNIX)
|
|
{
|
|
actions Run
|
|
{
|
|
$(SHELL_SET)PATH=$(RUN_PATH)
|
|
$(SHELL_EXPORT)PATH
|
|
$(SHELL_SET)LD_LIBRARY_PATH=$(RUN_LD_LIBRARY_PATH)
|
|
$(SHELL_EXPORT)LD_LIBRARY_PATH
|
|
$(<) $(COMMAND-LINE)
|
|
}
|
|
}
|
|
else
|
|
{
|
|
actions Run
|
|
{
|
|
$(SHELL_SET)PATH=$(RUN_PATH)
|
|
$(SHELL_EXPORT)PATH
|
|
$(<) $(COMMAND-LINE)
|
|
}
|
|
}
|
|
|
|
# bubble variable-name
|
|
#
|
|
# Helper function for sort, below
|
|
# Removes the greatest element from $(variable-name) and returns it.
|
|
rule bubble #
|
|
{
|
|
local result = ;
|
|
local last = $($(<)[1]) ;
|
|
for x in $($(<)[2-])
|
|
{
|
|
if $(last) <= $(x)
|
|
{
|
|
result += $(last) ;
|
|
last = $(x) ;
|
|
}
|
|
else
|
|
{
|
|
result += $(x) ;
|
|
}
|
|
}
|
|
$(<) = $(result) ;
|
|
return $(last) ;
|
|
}
|
|
|
|
# sort args
|
|
#
|
|
# return args sorted in lexicographic order.
|
|
rule sort
|
|
{
|
|
local _all = $(<) ;
|
|
local _result = ;
|
|
local _count ;
|
|
for _count in $(<)
|
|
{
|
|
_result = [ bubble _all ] $(_result) ;
|
|
}
|
|
return $(_result) ;
|
|
}
|
|
|
|
# min args
|
|
#
|
|
# return the lexicographic minimum element of args
|
|
rule min
|
|
{
|
|
local result = ;
|
|
local x ;
|
|
for x in $(<)
|
|
{
|
|
if ! $(result) || ( $(x) < $(result) )
|
|
{
|
|
result = $(x) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# difference listB : listA
|
|
# returns the elements of B that are not in A
|
|
rule difference
|
|
{
|
|
local result = ;
|
|
local element ;
|
|
for element in $(<)
|
|
{
|
|
if ! ( $(element) in $(>) )
|
|
{
|
|
result += $(element) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# replace list : old-value new-value
|
|
#
|
|
# returns list with occurrences of old-value replaced by new-value
|
|
rule replace
|
|
{
|
|
local result = ;
|
|
local x ;
|
|
for x in $(<)
|
|
{
|
|
if $(x) = $(>[1])
|
|
{
|
|
result += $(>[2]) ;
|
|
}
|
|
else
|
|
{
|
|
result += $(x) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# select-ungristed list...
|
|
#
|
|
# Returns the elements of list that have no grist
|
|
rule select-ungristed
|
|
{
|
|
local result x ;
|
|
for x in $(<)
|
|
{
|
|
if ! $(x:G)
|
|
{
|
|
result += $(x) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
rule select-gristed ( list * )
|
|
{
|
|
local result ;
|
|
for local x in $(list)
|
|
{
|
|
if $(x:G)
|
|
{
|
|
result += $(x) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# Split a qualified property into 3 elements.
|
|
#
|
|
# Grammar description of qualified-property :
|
|
# [[<toolset>]<variant>]property
|
|
#
|
|
# returns <toolset> <variant> property
|
|
# missing <toolset> or <variant> are treated as <*>
|
|
rule split-qualified-property
|
|
{
|
|
local grist1 = $(<:G) ;
|
|
local ungrist1 = $(<:G=) ;
|
|
local grist2 = $(ungrist1:G) ;
|
|
local ungrist2 = $(ungrist1:G=) ;
|
|
local grist3 = $(ungrist2:G) ;
|
|
local ungrist3 = $(ungrist2:G=) ;
|
|
if $(grist3)
|
|
{
|
|
return $(grist1) $(grist2) $(grist3)$(ungrist3) ;
|
|
}
|
|
else if $(grist2)
|
|
{
|
|
return <*> $(grist1) $(grist2)$(ungrist2) ;
|
|
}
|
|
else
|
|
{
|
|
return <*> <*> $(<) ;
|
|
}
|
|
}
|
|
|
|
rule unique # list
|
|
{
|
|
local result = ;
|
|
local f ;
|
|
for f in $(<)
|
|
{
|
|
if ! $(f) in $(result)
|
|
{
|
|
result += $(f) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# get-properties features : properties
|
|
#
|
|
# Given a list of gristed features and a list of properties, returns the
|
|
# properties matching the given features.
|
|
rule get-properties
|
|
{
|
|
local result = ;
|
|
local property ;
|
|
for property in $(>)
|
|
{
|
|
if $(property:G) in $(<)
|
|
{
|
|
result += $(property) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# get-values features : properties
|
|
#
|
|
# Given a list of gristed feature names and a list of properties, returns the
|
|
# value(s) of the given features.
|
|
rule get-values
|
|
{
|
|
local _properties = [ get-properties $(<) : $(>) ] ;
|
|
return $(_properties:G=) ;
|
|
}
|
|
|
|
# normalize-properties properties
|
|
#
|
|
# Normalizes a set of (possibly qualified) properties by prepending <*> as many
|
|
# times as neccessary to ensure that each property has at least 3 gristed elements.
|
|
rule normalize-properties
|
|
{
|
|
local property ;
|
|
local result ;
|
|
for property in $(<)
|
|
{
|
|
switch $(property)
|
|
{
|
|
case <*><*><*><*@*>* : result += $(property) ;
|
|
case <*><*><*@*>* : result += <*>$(property) ;
|
|
case <*><*@*>* : result += <*><*>$(property) ;
|
|
case <*@*>* : result += <*><*><*>$(property) ;
|
|
|
|
case <*><*><*>* : result += $(property) ;
|
|
case <*><*>* : result += <*>$(property) ;
|
|
case <*>* : result += <*><*>$(property) ;
|
|
case * : result += <*><*><*>$(property) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# intersection set1 : set2
|
|
#
|
|
# Removes from set1 any items which don't appear in set2 and returns the result.
|
|
rule intersection
|
|
{
|
|
local result v ;
|
|
for v in $(<)
|
|
{
|
|
if $(v) in $(>)
|
|
{
|
|
result += $(v) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# subset sub : super
|
|
#
|
|
# Returns true iff sub is a subset of super, empty otherwise
|
|
rule is-subset
|
|
{
|
|
if [ intersection $(<) : $(>) ] = $(<)
|
|
{
|
|
return true ;
|
|
}
|
|
}
|
|
|
|
# distribute-feature <feature>value1[/value2...]
|
|
#
|
|
# Distribute the given feature across the slash-separated set of values, i.e.
|
|
# returns <feature>value1[ <feature>/value2...]
|
|
rule distribute-feature
|
|
{
|
|
local g = $(<:G) ;
|
|
local result = [ split-path $(<:G=) ] ;
|
|
return $(g)$(result) ;
|
|
}
|
|
|
|
# set-insert variable-name : value... ;
|
|
#
|
|
# Appends the given values to the list designated by variable-name if they are
|
|
# not already present.
|
|
rule set-insert
|
|
{
|
|
local v ;
|
|
for v in $(>)
|
|
{
|
|
if ! ( $(v) in $($(<)) )
|
|
{
|
|
$(<) += $(v) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
# equal-sets set1 : set2
|
|
#
|
|
# Returns true iff set1 contains the same elements as set2.
|
|
# Not sensitive to the same element appearing multiple times
|
|
rule equal-sets
|
|
{
|
|
if ( ! [ difference $(<) : $(>) ] ) && ( ! [ difference $(>) : $(<) ] )
|
|
{
|
|
return true ;
|
|
}
|
|
}
|
|
|
|
# feature name : [values...]
|
|
#
|
|
# Declares a feature with the given name, and the given allowed values.
|
|
rule feature
|
|
{
|
|
if $(<) in $(gFEATURES)
|
|
{
|
|
EXIT feature $(<) : $(gFEATURE_VALUES(<$(<)>) redeclared as $(<) : $(>) ;
|
|
}
|
|
gFEATURES += <$(<)> ;
|
|
gUNGRISTED(<$(<)>) = $(<) ;
|
|
gFEATURE_VALUES(<$(<)>) = $(>) ;
|
|
}
|
|
|
|
rule free-feature
|
|
{
|
|
feature $(<) : $(>) ;
|
|
gFREE_FEATURES += <$(<)> ;
|
|
if $(>)
|
|
{
|
|
gSINGLE_VALUED_FREE_FEATURES += <$(<)> ;
|
|
}
|
|
}
|
|
|
|
rule path-feature
|
|
{
|
|
free-feature $(<) : $(>) ;
|
|
gPATH_FEATURES += <$(<)> ;
|
|
}
|
|
|
|
rule dependency-feature
|
|
{
|
|
path-feature $(<) : $(>) ;
|
|
gDEPENDENCY_FEATURES += <$(<)> ;
|
|
}
|
|
|
|
# feature-default <feature>...
|
|
#
|
|
# return the default properties corresponding to the given feature(s)
|
|
rule feature-default
|
|
{
|
|
local result f ;
|
|
for f in $(<)
|
|
{
|
|
result += $(f)$(gFEATURE_VALUES($(f))[1]) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# flags tools-name variable-name condition [: value(s)]
|
|
#
|
|
# Declare command-line settings for a given toolset.
|
|
# toolset: the name of the toolset
|
|
# variable-name: the name of a global variable which can be used to carry
|
|
# information to a command-line
|
|
# condition: One of the following:
|
|
# 1. zero or more property-sets of the form:
|
|
# <feature>value[/<feature>value...]
|
|
# 2. one or more <feature>[/<feature>...]
|
|
#
|
|
# This rule appends to the specified variable, depending on a target's build
|
|
# configuration and the form of condition.
|
|
#
|
|
# 1. if any specified property-set is a subset of the target's build properties or if
|
|
# condition is empty, the values specified in $(3) will be appended once to
|
|
# /variable-name/.
|
|
#
|
|
# 2. The value of each specified feature that participates in the target's
|
|
# build properaties is appended to /variable-name/.
|
|
#
|
|
# The variable will be set "on" the target so it may be used in its build actions.
|
|
rule flags
|
|
{
|
|
local toolset = $(<[1]) ;
|
|
local variable = $(<[2]) ;
|
|
local condition = $(<[3-]) ;
|
|
|
|
# record the names of all variables used so they can be set on targets
|
|
if ! ( $(variable) in $(gTARGET_VARIABLES) )
|
|
{
|
|
gTARGET_VARIABLES += $(variable) ;
|
|
$(variable) = ;
|
|
}
|
|
|
|
local found = ;
|
|
local x ;
|
|
for x in $(condition)
|
|
{
|
|
x = [ split-path $(x) ] ;
|
|
|
|
# Add each feature to the set of features relevant to the toolset
|
|
gRELEVANT_FEATURES($(toolset)) += $(x:G) ;
|
|
|
|
# is it a property set?
|
|
if $(x:G=)
|
|
{
|
|
# if this property_set is a subset of the current build-properties
|
|
if ( ! $(found) ) && [ is-subset $(x) : $(gBUILD_PROPERTIES) ]
|
|
{
|
|
found = true ;
|
|
$(variable) += $(>) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$(variable) += [ get-values $(x) : $(gBUILD_PROPERTIES) ] ;
|
|
if $(x:G) in $(gDEPENDENCY_FEATURES)
|
|
{
|
|
gDEPENDENCY_VARIABLES($(toolset)) += $(variable) ;
|
|
}
|
|
}
|
|
}
|
|
if ! $(condition)
|
|
{
|
|
$(variable) += $(>) ;
|
|
}
|
|
}
|
|
|
|
# include-tools toolset
|
|
#
|
|
# Unconditionally process the specification file for the given toolset. It is
|
|
# neccessary to do this for each target built with that toolset, since the
|
|
# toolset will invoke the flags rule to set global variables based on the build
|
|
# properties of the target.
|
|
rule include-tools
|
|
{
|
|
gCURRENT_TOOLSET = $(<) ;
|
|
|
|
# clear any lingering target variables that may have been declared
|
|
$(gTARGET_VARIABLES) = ;
|
|
gTARGET_VARIABLES = NEEDLIBS ; # start over from the beginning
|
|
|
|
gRELEVANT_FEATURES($(<)) = ; # clear relevant feature set
|
|
gDEPENDENCY_VARIABLES($(<)) = ;
|
|
|
|
include $(BOOST_BUILD_INSTALLATION)$(SLASH)$(<)-tools.jam ;
|
|
|
|
# Always maintain the list of relevant features as unique
|
|
gRELEVANT_FEATURES($(<)) = [ unique $(gRELEVANT_FEATURES($(<))) ] ;
|
|
|
|
gINCLUDED($(BOOST_BUILD_INSTALLATION)$(SLASH)$(<)-tools.jam) = true ;
|
|
}
|
|
|
|
# extends-toolset toolset
|
|
#
|
|
# Used in a toolset definition file; Declares that the toolset currently being
|
|
# defined is an extension of the given toolset.
|
|
rule extends-toolset
|
|
{
|
|
{
|
|
local gCURRENT_TOOLSET ; # protect this from being clobbered
|
|
include-tools $(<) ;
|
|
}
|
|
# Add the relevant features from the base toolset
|
|
gRELEVANT_FEATURES($(gCURRENT_TOOLSET)) += $(gRELEVANT_FEATURES($(<))) ;
|
|
gDEPENDENCY_VARIABLES($(gCURRENT_TOOLSET)) += $(gDEPENDENCY_VARIABLES($(<))) ;
|
|
}
|
|
|
|
# relevant-features toolset
|
|
#
|
|
# Returns the set of unique features relevant to the given toolset; includes the
|
|
# toolset description file as a side-effect if neccessary.
|
|
rule relevant-features # name
|
|
{
|
|
if ! $(gRELEVANT_FEATURES($(<)))
|
|
{
|
|
include-tools $(<) ;
|
|
}
|
|
return $(gRELEVANT_FEATURES($(<))) ;
|
|
}
|
|
|
|
# variant name [ : parents... ] : [<toolset>]<feature>value...
|
|
#
|
|
# Declare a build variant, whose configuration is given by the given (optionally
|
|
# toolset-qualified) properties.
|
|
rule variant ( name : parents-or-properties * : tool-properties * )
|
|
{
|
|
gALL_VARIANTS += $(name) ;
|
|
local parents ;
|
|
if ! $(tool-properties)
|
|
{
|
|
if $(parents-or-properties[1]:G)
|
|
{
|
|
tool-properties = $(parents-or-properties) ;
|
|
}
|
|
else
|
|
{
|
|
parents = $(parents-or-properties) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
parents = $(parents-or-properties) ;
|
|
}
|
|
local toolset ;
|
|
for toolset in $(TOOLS)
|
|
{
|
|
# We hijack select-properties to do our dirty work here.
|
|
# Because properties in a variant declaration are only qualified with
|
|
# toolset and not variant, we specify the toolset where
|
|
# select-properties expects a variant name. The first toolset parameter
|
|
# is neccessary to get the relevant-features correctly set. We supply
|
|
# the variant name as the target name, so that error messages will look
|
|
# coherent.
|
|
local name-properties
|
|
= [ select-properties $(toolset) $(toolset) $(name) : $(tool-properties) ] ;
|
|
if $(parents)
|
|
{
|
|
local parent ;
|
|
for parent in $(parents)
|
|
{
|
|
local parent-properties
|
|
= $(gBASE_PROPERTIES($(toolset),$(parent))) ;
|
|
local inherited-features
|
|
= [ unique
|
|
[ difference $(parent-properties:G) : $(name-properties:G) ]
|
|
$(gFREE_FEATURES)
|
|
$(gPATH_FEATURES)
|
|
$(gDEPENDENCY_FEATURES ] ;
|
|
local inherited-properties
|
|
= [ get-properties $(inherited-features) : $(parent-properties) ] ;
|
|
name-properties
|
|
+= $(inherited-properties) ;
|
|
}
|
|
}
|
|
gBASE_PROPERTIES($(toolset),$(name)) = [ sort $(name-properties) ] ;
|
|
}
|
|
}
|
|
|
|
# select-properties toolset variant target : qualified-properties...
|
|
#
|
|
# Returns
|
|
rule select-properties ( toolset variant target ? : qualified-properties * )
|
|
{
|
|
local relevant_features = [ relevant-features $(toolset) ] ;
|
|
local normalized = [ normalize-properties $(>) ] ;
|
|
|
|
# Classify properties by the specificity of their qualification.
|
|
# First, grab those that apply to this toolset, or all toolsets
|
|
local this_toolset = [ get-values <$(toolset)> : $(normalized) ] ;
|
|
local all_toolsets = [ get-values <*> : $(normalized) ] ;
|
|
|
|
local 0-stars = [ get-values <$(variant)> : $(this_toolset) ] ;
|
|
local 1-stars = [ get-values <*> : $(this_toolset) ] [ get-values <$(variant)> : $(all_toolsets) ] ;
|
|
local 2-stars = [ get-values <*> : $(all_toolsets) ] ;
|
|
|
|
# Select feature names from the features relevant to the toolset.
|
|
local features = [ intersection $(relevant_features)
|
|
: $(0-stars:G) $(1-stars:G) $(2-stars:G) ] ;
|
|
|
|
local result f ;
|
|
for f in $(features)
|
|
{
|
|
local is_free = [ intersection $(f) : $(gFREE_FEATURES) ] ;
|
|
|
|
# Go through the $(n-stars) lists from most- to least- specific;
|
|
# collect the best set of values of a simple feature, and /all/
|
|
# values of a free feature.
|
|
local r n ;
|
|
for n in 0 1 2
|
|
{
|
|
if ! $(r) || $(is_free)
|
|
{
|
|
r += [ get-values $(f) : $($(n)-stars) ] ;
|
|
}
|
|
}
|
|
|
|
r = [ unique $(r) ] ;
|
|
if $(r[2]) && ! $(is_free) # Check for conflicting simple-feature requests
|
|
{
|
|
EXIT "Error: Ambiguous properties requested for"
|
|
$(target) <$(toolset)><$(variant)> ":" $(f)$(r) ;
|
|
}
|
|
result += $(f)$(r) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
# get toolset features
|
|
include $(BOOST_BUILD_INSTALLATION)$(SLASH)features.jam ;
|
|
|
|
# ungrist-properties properties...
|
|
#
|
|
# Transforms a list of properties of the form:
|
|
# <feature1>value1 [<feature2>value2... ]
|
|
# into a list of the form:
|
|
# feature1-value1 feature2-value2
|
|
# suitable for use as directory path elements
|
|
#
|
|
rule ungrist-properties
|
|
{
|
|
local property ;
|
|
local result = ;
|
|
for property in $(<)
|
|
{
|
|
result += $(gUNGRISTED($(property:G)))-$(property:G=) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# set-target-variables target
|
|
#
|
|
# attach global build tool settings to the given file-target, so that they can be
|
|
# used in build actions.
|
|
rule set-target-variables # file-target
|
|
{
|
|
local s ;
|
|
for s in $(gTARGET_VARIABLES)
|
|
{
|
|
$(s) on $(<) = $($(s)) ;
|
|
|
|
# set up dependencies if the target is a "top-level" target
|
|
if ( $(s) in $(gDEPENDENCY_VARIABLES($(gCURRENT_TOOLSET))) ) && $(gTARGET_TYPE($(<)))
|
|
{
|
|
DEPENDS $(<) : $($(s)) ;
|
|
}
|
|
}
|
|
}
|
|
|
|
# fixup-path-properties properties...
|
|
#
|
|
# For path properties, add a relative path prefix to the value as neccessary to
|
|
# locate the path relative to the current subproject.
|
|
rule fixup-path-properties
|
|
{
|
|
local path-properties = [ get-properties $(gPATH_FEATURES) : $(<) ] ;
|
|
local non-path = [ difference $(<) : $(path-properties) ] ;
|
|
if $(RELATIVE_SUBDIR)
|
|
{
|
|
path-properties = [ root-paths $(path-properties) : $(RELATIVE_SUBDIR) ] ;
|
|
}
|
|
return $(path-properties) $(non-path) ;
|
|
}
|
|
|
|
# report-any-incompatible-properties requirements... : build-request... : target-name
|
|
#
|
|
# If any element of requirements has the same grist but a different ungristed
|
|
# part as any element of build-request, exits with an error report about target-name
|
|
rule report-any-incompatible-properties
|
|
{
|
|
local all-properties = [ unique $(<) $(>) ] ;
|
|
local all-features = $(all-properties:G) ;
|
|
local unique-features = [ unique $(all-features) ] ;
|
|
if $(all-features) != $(unique-features)
|
|
{
|
|
EXIT "Error:" "$(3):" "target requirements conflict for requested build {" $(<) $(>) "}" ;
|
|
}
|
|
}
|
|
if report-any-incompatible-properties in $(TEST)
|
|
{
|
|
report-any-incompatible-properties <foo>bar <baz>mumble : <b>c <foo>bar : my-target ;
|
|
report-any-incompatible-properties <foo>bat <baz>mumble <baz>buz <d>f : <b>c <foo>bar : my-target ;
|
|
}
|
|
|
|
# multiply-property-sets [<feature>value1[/value2...] ]...
|
|
#
|
|
# Expands a set of (possibly multi-valued) properties into all the combinations
|
|
# that include every feature in the set. Each combination is given as a path,
|
|
# with the slash separating the properties, sorted in feature order.
|
|
rule multiply-property-sets
|
|
{
|
|
local result p ;
|
|
for p in [ sort $(<) ]
|
|
{
|
|
# expand any multi-valued simple features from the default build
|
|
local multiple = [ distribute-feature $(p) ] ;
|
|
|
|
# concatenation produces a product, so the tree branches for each
|
|
# multi-valued simple feature.
|
|
result = $(result)/$(multiple) ;
|
|
result ?= $(multiple) ; # this trick allows us to get started
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# make-path-property-sets base-path : common-properties : property-sets
|
|
#
|
|
# Returns a list of paths where the initial ungristed part of each element is a
|
|
# relative path to a subvariant directory from a target's build root and the
|
|
# rest of the element is a slash-separated property set describing the
|
|
# properties of the target to be built.
|
|
#
|
|
# Each path returned is base-path extended by one of the ungristed property-sets
|
|
# (or just the base-path if no property-sets are supplied). Each property set
|
|
# returned is formed by extending common-properties with one of the property-sets.
|
|
#
|
|
# For example,
|
|
#
|
|
# make-path-property-sets gcc/release : <p1>v1 : <p2>v2/<p3>v3
|
|
#
|
|
# returns this single-element list:
|
|
#
|
|
# gcc/release/p2-v2/p3-v3/<p1>v1/<p2>v2/<p3>v3
|
|
# |<-- subvariant path -->|<-- property-set -->|
|
|
rule make-path-property-sets
|
|
{
|
|
local result ;
|
|
local s ;
|
|
for s in $(3)
|
|
{
|
|
result += [ join
|
|
$(<) [ ungrist-properties [ split-path $(s) ] ] # directory components
|
|
$(>) $(s) : $(SLASH) ] ; # common properties + property set
|
|
}
|
|
|
|
# if there were no overrides, just add the base variant and properties
|
|
if ! $(result)
|
|
{
|
|
result = [ join $(<) $(>) : $(SLASH) ] ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# segregate-overrides override-var base-var
|
|
#
|
|
# removes elements of $(base-var) from $(override-var), and removes elements
|
|
# whose grist is in $(override-var:G) from $(base-var).
|
|
rule segregate-overrides
|
|
{
|
|
$(<) = [ difference $($(<)) : $($(>)) ] ;
|
|
|
|
# Which features, and thus properties, of the base variant are we keeping?
|
|
local kept-features = [ difference $($(>):G) : $($(<):G) ] ;
|
|
$(>) = [ get-properties $(kept-features) : $($(>)) ] ;
|
|
}
|
|
|
|
# report-free-property-conflicts free-property... : target
|
|
#
|
|
# If any single-valued free-feature appears more than once in free-property...,
|
|
# exit with an appropriate error message.
|
|
rule report-free-property-conflicts
|
|
{
|
|
local p = [ get-properties $(gSINGLE_VALUED_FREE_FEATURES) $(<) ] ;
|
|
local f = [ unique $(p:G) ] ;
|
|
if $(p:G) != $(f)
|
|
{
|
|
EXIT $(>): multiple values for single-valued free feature(s)
|
|
[ difference $(p:G) $(f) ] requested ;
|
|
}
|
|
}
|
|
|
|
# expand-build-request
|
|
# toolset variant target-name : requirements : build-request
|
|
#
|
|
# Returns a list of path-property-sets (see make-path-property-sets above) for
|
|
# all build configurations based on the given toolset, requirements, and
|
|
# build-request. Target-name is just used for error reporting.
|
|
rule expand-build-request
|
|
{
|
|
local toolset = $(<[1]) ;
|
|
local variant = $(<[2]) ;
|
|
|
|
# grab the requirements and BUILD-request relevant to this toolset and variant
|
|
local requirements = [ select-properties $(toolset) $(variant) : $(>) ] ;
|
|
local build-request = [ select-properties $(toolset) $(variant) : $(3) ] ;
|
|
|
|
# Separate the free features (e.g. <define>, <undef>, <include>) from the others
|
|
local free-properties = [ segregate-free-properties requirements build-request ] ;
|
|
|
|
# Check for conflicts
|
|
report-free-property-conflicts $(free-properties) : $(<[3]) ;
|
|
report-any-incompatible-properties $(requirements) : $(build-request) : $(<[3]) ;
|
|
|
|
# Get the base variant for the toolset. Includes free features
|
|
local base-properties = $(gBASE_PROPERTIES($(toolset),$(variant))) ;
|
|
|
|
# Which properties will override settings in the base variant?
|
|
local override-properties = [ unique $(requirements) $(build-request) ] ;
|
|
segregate-overrides override-properties : base-properties ;
|
|
|
|
# Which features will pick up a default value because they are not in
|
|
# the base variant or in the overrides?
|
|
local relevant_features = [ relevant-features $(toolset) ] ;
|
|
local defaulted-features = [ difference $(relevant_features)
|
|
: $(override-properties:G) $(base-properties:G) ] ;
|
|
local defaulted-properties = [ feature-default $(defaulted-features) ] ;
|
|
# VP: defaulted-properties have the form <feature>value and there's 1 value.
|
|
# Hence, each element of defaulted-properties will be part of each
|
|
# component of override-sets and will be a part of each property-set
|
|
# returned. By segregating them, the result is changed in only one
|
|
# way: free properties does not show up in target path.
|
|
local defaulted-free-properties = [ segregate-free-properties defaulted-properties ] ;
|
|
|
|
|
|
# form override property sets of the form (property1[/property2...] )+,
|
|
# sorted in feature order. These represent the properties of subvariants
|
|
# that differ from the base variant
|
|
local override-sets
|
|
= [ multiply-property-sets $(override-properties) $(defaulted-properties) ] ;
|
|
|
|
# return path-property-sets corresponding to each (sub)variant build
|
|
# described.
|
|
return [ make-path-property-sets $(toolset)$(SLASH)$(variant)
|
|
: [ fixup-path-properties $(base-properties) $(free-properties)
|
|
$(defaulted-free-properties) ]
|
|
: $(override-sets) ] ;
|
|
}
|
|
|
|
# split-path-at-grist path
|
|
#
|
|
# Breaks path at each $(SLASH) that is followed by grist. This can be used to
|
|
# break apart property sets, particularly where the <include> feature is used,
|
|
# since its value is typically a path.
|
|
rule split-path-at-grist
|
|
{
|
|
local full-split = [ split-path $(<) ] ;
|
|
local last ;
|
|
local result x ;
|
|
for x in $(full-split)
|
|
{
|
|
if $(x:G)
|
|
{
|
|
result += $(last) ;
|
|
last = $(x) ;
|
|
}
|
|
else
|
|
{
|
|
last = $(last)$(SLASH)$(x) ;
|
|
last ?= $(x) ;
|
|
}
|
|
}
|
|
return $(result) $(last) ;
|
|
}
|
|
|
|
# declare-local-target name : sources : requirements : local-BUILD : target-type
|
|
#
|
|
# declares a subproject-local target of the given name and target-type. This is
|
|
# all top-level rules which declare targets should eventually go through here.
|
|
rule declare-local-target
|
|
{
|
|
# We add SOURCE_GRIST the base target name here because we're referring the
|
|
# abstract target which generates all of the actual builds. We need a way to
|
|
# distinguish targets of the same name from different subprojects.
|
|
local target-id = [ FGristFiles $(<) ] ;
|
|
|
|
if ! $(5)
|
|
{
|
|
EXIT No target type given for "$(<)" ;
|
|
}
|
|
|
|
if ! $(gTARGET_TYPE($(target-id)))
|
|
{
|
|
gTARGET_TYPE($(target-id)) = $(5) ;
|
|
|
|
# Add the specified requirements to any requirements given by the target
|
|
# type, and the corresponding <target-type> property.
|
|
gTARGET_REQUIREMENTS($(target-id))
|
|
= $(3) $(gTARGET_TYPE_REQUIREMENTS($(5))) <target-type>$(5) ;
|
|
gTARGET_LIBS($(target-id)) = [ get-values <lib> : $(>) ] ;
|
|
|
|
gTARGET_SOURCES($(target-id))
|
|
= [ FGristFiles
|
|
[ difference $(>:G=) : $(gTARGET_LIBS($(target-id))) ] ] ;
|
|
|
|
}
|
|
else if $(gTARGET_TYPE($(target-id))) != $(5)
|
|
{
|
|
EXIT conflicting target types for "$(<)":
|
|
"$(gTARGET_TYPE($(target-id)))" "$(5)" ;
|
|
}
|
|
|
|
# Just gather information if we are including a library's Jamfile for a
|
|
# dependent target. Don't generate build instructions here.
|
|
if ! $(gIN_LIB_INCLUDE)
|
|
{
|
|
main-target $(target-id) : $(4) ;
|
|
}
|
|
return $(gTARGET_FILES($(target-id))) ;
|
|
}
|
|
|
|
# directory-of files...
|
|
#
|
|
# Returns a list of the directories containing each element of files
|
|
rule directory-of
|
|
{
|
|
local result d ;
|
|
for d in $(<:D)
|
|
{
|
|
if $(d) = ""
|
|
{
|
|
result += $(DOT) ;
|
|
}
|
|
else
|
|
{
|
|
result += $(d) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# top-relative-tokens path
|
|
#
|
|
# Returns a list of path elements which form the relative path from TOP to path,
|
|
# which is expected to be given relative to the current subproject.
|
|
rule top-relative-tokens
|
|
{
|
|
return [ simplify-path-tokens $(SUBDIR_TOKENS) [ split-path $(<) ] ] ;
|
|
}
|
|
|
|
# dependent-include target-path...
|
|
#
|
|
# For each target-path, ensure that the appropriate Jamfile has been
|
|
# included. Used when a target declares its dependency on another target.
|
|
rule dependent-include
|
|
{
|
|
local target ;
|
|
for target in $(<)
|
|
{
|
|
# compute the path to the Jamfile containing target. This path must be
|
|
# relative to the directory of Jam's invocation in order for the include
|
|
# rule to find it.
|
|
|
|
local jamfile-path
|
|
= [ tokens-to-simple-path
|
|
$(RELATIVE_SUBDIR_TOKENS) [ directory-of $(target) ] $(JAMFILE) ] ;
|
|
|
|
if ! $(gINCLUDED($(jamfile-path)))
|
|
{
|
|
# protect variables from being permanently set by SubDir invocations
|
|
# in included files.
|
|
local [ protect-subdir ] ;
|
|
|
|
# this stack allows us to avoid making dependee libraries part of
|
|
# the "type" targets, e.g. all, exe, obj. See rule type-DEPENDS.
|
|
local gIN_LIB_INCLUDE = 1 ;
|
|
|
|
include $(jamfile-path) ;
|
|
gINCLUDED($(jamfile-path)) = true ;
|
|
}
|
|
}
|
|
}
|
|
|
|
# segregate-free-properties variable1 variable2...
|
|
#
|
|
# returns the and removes the unique list of free properties from
|
|
# $(variable1) $(variable2)...
|
|
rule segregate-free-properties
|
|
{
|
|
local free-properties = [ unique [ get-properties $(gFREE_FEATURES) : $($(<)) ] ] ;
|
|
local v ;
|
|
for v in $(<)
|
|
{
|
|
$(v) = [ difference $($(v)) : $(free-properties) ] ;
|
|
}
|
|
return $(free-properties) ;
|
|
}
|
|
|
|
# is-link-compatible feature : value1 : value2
|
|
#
|
|
# return non-empty iff a library built with <feature>value1 can be linked into a
|
|
# target with <feature>value2, empty otherwise
|
|
rule is-link-compatible
|
|
{
|
|
return [ intersection
|
|
$(<) $(>:G=$(<)) $(>:G=$(<))$(SLASH)$(3:G=$(<)) : $(gLINK_COMPATIBLE) ] ;
|
|
}
|
|
|
|
# find-compatible-subvariant main-target : toolset variant : dependent-simple-properties
|
|
rule find-compatible-subvariant ( main-target : toolset variant : dependent-simple-properties * )
|
|
{
|
|
local requirements = [ select-properties $(toolset) $(variant)
|
|
: $(gTARGET_REQUIREMENTS($(main-target))) ] ;
|
|
|
|
local free-properties = [ segregate-free-properties requirements ] ;
|
|
|
|
# begin with the properties overridden by the target requirements
|
|
local override-properties = $(requirements) ;
|
|
|
|
# add properties from build-request, checking for compatibility
|
|
local p ;
|
|
for p in [ difference $(dependent-simple-properties) : $(requirements) ]
|
|
{
|
|
local f = $(p:G) ;
|
|
if $(f) in $(requirements:G)
|
|
{
|
|
local required-value
|
|
= [ get-values $(f) : $(override-properties) ] ;
|
|
|
|
if ! [ is-link-compatible $(f) : $(required-value) : $(p:G=) ]
|
|
{
|
|
EXIT $(main-target): required property $(f)$(required-value)
|
|
incompatible with requested $(p) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
override-properties += $(p) ;
|
|
}
|
|
}
|
|
|
|
local base-properties = $(gBASE_PROPERTIES($(toolset),$(variant))) ;
|
|
segregate-overrides override-properties : base-properties ;
|
|
|
|
local all-properties = $(base-properties) $(free-properties) ;
|
|
|
|
local rules = [ select-ungristed $(gTARGET_REQUIREMENTS($(<))) ] ;
|
|
for local r in $(rules)
|
|
{
|
|
all-properties = [ $(r) $(toolset) $(variant) : $(all-properties) ] ;
|
|
}
|
|
|
|
# build the path identifying the subvariant
|
|
local subvariant-id
|
|
= [ join $(toolset) $(variant)
|
|
[ ungrist-properties [ sort $(override-properties) ] ]
|
|
: $(SLASH) ] ;
|
|
|
|
return $(subvariant-id)
|
|
[ fixup-path-properties $(all-properties) ]
|
|
$(override-properties) ;
|
|
}
|
|
|
|
|
|
# link-libraries libs... : toolset variant : dependent-simple-properties
|
|
#
|
|
# For each target specified in libs, generate build instructions
|
|
# for a subvariant that can be linked with a dependent target with
|
|
# dependent-properties, returning a list of the linkable targets.
|
|
rule link-libraries
|
|
{
|
|
local lib-path result ;
|
|
for lib-path in $(<)
|
|
{
|
|
local new-subdir = TOP [ top-relative-tokens [ directory-of $(lib-path) ] ] ;
|
|
|
|
# protect global variables from being permanently set by SubDir
|
|
local [ protect-subdir ] ;
|
|
|
|
# Enter the dependee subproject
|
|
SubDir $(new-subdir) ;
|
|
|
|
local lib-target = [ FGristFiles $(lib-path:D=) ] ;
|
|
local lib-subvariant = [ find-compatible-subvariant $(lib-target) : $(>) : $(3) ] ;
|
|
|
|
# Generate build instructions for the library target
|
|
local lib-files
|
|
= [ subvariant-target $(lib-target) : $(lib-subvariant) : $(>) ] ;
|
|
|
|
# Add the name of the linkable product to the result.
|
|
local type = $(gTARGET_TYPE($(lib-target))) ;
|
|
local index = $(gLINKABLE_PRODUCT_INDEX($(type))) ;
|
|
index ?= 1 ;
|
|
result += $(lib-files[$(index)]) ;
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
# Which configuration(s) to build if nothing is explicitly specified
|
|
DEFAULT_BUILD ?= debug ;
|
|
|
|
# get-BUILD [target-default-build]
|
|
#
|
|
# pick the first of ($(BUILD), $(>), $(DEFAULT_BUILD)) which is set. If it
|
|
# contains no variants, add variants from $(DEFAULT_BUILD).
|
|
rule get-BUILD
|
|
{
|
|
local build = $(BUILD) ;
|
|
build ?= $(<) ;
|
|
build ?= $(DEFAULT_BUILD) ;
|
|
local variants = [ select-ungristed $(build) ] ;
|
|
if ! $(variants)
|
|
{
|
|
build += [ select-ungristed $(DEFAULT_BUILD) ] ;
|
|
}
|
|
return $(build) ;
|
|
}
|
|
|
|
BIN_DIRECTORY ?= bin ;
|
|
|
|
# declare-fake-targets abstract-target : target-file
|
|
#
|
|
#
|
|
rule declare-fake-targets
|
|
{
|
|
# make a fake target so that it can be built without knowing the suffix
|
|
# Since executables under *NIX have no suffix, we'd better check
|
|
if $(>) != $(<)
|
|
{
|
|
DEPENDS $(<) : $(>) ;
|
|
NOTFILE $(<) ;
|
|
}
|
|
|
|
# The following checks that we're in the subdirectory of Jam's invocation
|
|
# so that we can arrange for ungristed target names to be built from the
|
|
# command-line.
|
|
if $(<:G) && [ in-invocation-subdir ]
|
|
{
|
|
DEPENDS $(<:G=) : $(<) ; # allows $(<:G=) to be used to build all variants
|
|
NOTFILE $(<:G=) ;
|
|
}
|
|
}
|
|
|
|
# declare-target-type TYPE : [[<compiler>]<variant>]<feature>value...
|
|
rule declare-target-type
|
|
{
|
|
gTARGET_TYPE_REQUIREMENTS($(<)) = $(>) ;
|
|
}
|
|
|
|
declare-target-type DLL : <shared-linkable>true ;
|
|
|
|
if $(NT)
|
|
{
|
|
gIMPORT_SUFFIX(DLL) = .lib ;
|
|
gIMPORT_SUFFIX(LIB) = .lib ;
|
|
gEXPORT_SUFFIX(DLL) = .lib ;
|
|
}
|
|
else
|
|
{
|
|
gIMPORT_SUFFIX(DLL) = .so ;
|
|
gIMPORT_SUFFIX(LIB) = .a ;
|
|
}
|
|
|
|
# depend-on-libraries target-files : library-targets
|
|
rule depend-on-libraries
|
|
{
|
|
NEEDLIBS += $(>) ;
|
|
NEEDLIBS on $(<) += $(>) ;
|
|
DEPENDS $(<) : $(>) ;
|
|
# To run these targets, we need everything needed to run the libraries
|
|
gRUN_PATH($(<)) = [ unique $(gRUN_PATH($(<))) $(gRUN_PATH($(>))) ] ;
|
|
gRUN_LD_LIBRARY_PATH($(<)) = [ unique $(gRUN_LD_LIBRARY_PATH($(<))) $(gRUN_LD_LIBRARY_PATH($(>))) ] ;
|
|
}
|
|
|
|
# subvariant-target target : subvariant-id build-properties : toolset variant
|
|
#
|
|
# Given target, a main target name gristed with $(SOURCE_GRIST), generate build
|
|
# instructions for a subvariant target using the given toolset, variant, etc.
|
|
#
|
|
# RETURNS: the a list of target names for the files built by the subvariant. If
|
|
# the target is a library, the first filename is the one that should be linked
|
|
# into a dependent target.
|
|
rule subvariant-target
|
|
{
|
|
# SOURCE_GRIST identifies the subproject directory; TARGET_GRIST will identify
|
|
# the target and subvariant, since unique versions of files will be built for
|
|
# that combination.
|
|
local TARGET_GRIST = [ join-path $(SOURCE_GRIST) $(<:G=) $(>[1]) ] ;
|
|
local subvariant = $(<:G=$(TARGET_GRIST)) ;
|
|
|
|
# Do nothing if build instructions and dependencies for this target have
|
|
# already been generated.
|
|
if ! $(TARGET_GRIST) in $(gDECLARED_TARGETS)
|
|
{
|
|
gDECLARED_TARGETS += $(TARGET_GRIST) ;
|
|
|
|
local target-type = $(gTARGET_TYPE($(<))) ;
|
|
if ! $(target-type)
|
|
{
|
|
EXIT unknown target type for $(<) ;
|
|
}
|
|
|
|
# LOCATE_TARGET affects where built targets are generated. We move it
|
|
# relative to the default location based on the subvariant
|
|
local LOCATE_TARGET
|
|
= [ join-path $(LOCATE_TARGET) $(BIN_DIRECTORY) $(<:G=) $(>[1]) ] ;
|
|
|
|
local target-files = [ FAppendSuffix $(subvariant) : $(SUF$(target-type)) ] ;
|
|
if $(gNAME_ADJUST($(target-type)))
|
|
{
|
|
target-files = [ $(gNAME_ADJUST($(target-type))) $(target-files) : $(2) : $(3) ] ;
|
|
}
|
|
|
|
gTARGET_FILES($(subvariant)) = $(target-files) ;
|
|
gTARGET_FILES($(<)) += $(target-files) ;
|
|
|
|
# Remember the path from the build root to the subvariant directory
|
|
gSUBVARIANT_PATH($(subvariant)) = $(>[1]) ;
|
|
|
|
declare-fake-targets $(<) : $(target-files) ;
|
|
|
|
# set up gBUILD_PROPERTIES for include-tools (below)
|
|
local gBUILD_PROPERTIES = $(>[2-]) ;
|
|
|
|
# Include the toolset specification. This will set up the global flags
|
|
# variables in a way appropriate to this build.
|
|
|
|
include-tools $(3[1]) ;
|
|
|
|
# headers should be identified specific to the target, since search paths
|
|
# may differ for different subvariants. The same header name or relative
|
|
# path may refer to different files.
|
|
local HDRGRIST = [ join $(SOURCE_GRIST) $(HDRS) $(STDHDRS) : "#" ] ;
|
|
|
|
# transfer target variables to the target file.
|
|
set-target-variables $(target-files) ;
|
|
|
|
if $(gTARGET_LIBS($(<)))
|
|
{
|
|
local libs ;
|
|
{
|
|
# Protect target variables against modification while lib dependencies
|
|
# are built. They will be made empty here, and restored when this scope exits
|
|
local $(gTARGET_VARIABLES) ;
|
|
|
|
# extract the simple properties from dependent-properties
|
|
local simple-properties = $(gBUILD_PROPERTIES) ;
|
|
segregate-free-properties simple-properties ;
|
|
|
|
# generate library build instructionsn
|
|
libs = [ link-libraries $(gTARGET_LIBS($(<))) : $(3) : $(simple-properties) ] ;
|
|
}
|
|
depend-on-libraries $(target-files) : $(libs) ;
|
|
}
|
|
|
|
# dispatch to the appropriate declaration function. Here we are using an
|
|
# FTJam-only feature (thanks, David Turner!)
|
|
local ignored = [ $(gGENERATOR_FUNCTION($(target-type))) $(target-files)
|
|
: $(gTARGET_SOURCES($(<))) ] ;
|
|
|
|
$(gTARGET_VARIABLES) = ; # Be sure that we don't mask bugs with lingering target variables
|
|
}
|
|
return $(gTARGET_FILES($(subvariant))) ;
|
|
}
|
|
|
|
# main-target target : local-build
|
|
#
|
|
# Generates requested subvariant build instructions for the given main target
|
|
rule main-target
|
|
{
|
|
local BUILD = [ get-BUILD $(>) ] ;
|
|
local variants = [ select-ungristed $(BUILD) ] ;
|
|
local build-request = [ difference $(BUILD) : $(variants) ] ;
|
|
|
|
# include each jamfile describing a dependee target.
|
|
dependent-include $(gTARGET_LIBS($(<))) ;
|
|
|
|
local toolset ;
|
|
for toolset in $(TOOLS)
|
|
{
|
|
local v ;
|
|
for v in $(variants)
|
|
{
|
|
local rules = [ select-ungristed $(gTARGET_REQUIREMENTS($(<))) ] ;
|
|
local requirements = [ select-gristed $(gTARGET_REQUIREMENTS($(<))) ] ;
|
|
|
|
local expanded
|
|
= [ expand-build-request $(toolset) $(v) $(<)
|
|
: $(requirements) : $(build-request) ] ;
|
|
|
|
for local x in $(expanded)
|
|
{
|
|
local properties = [ split-path-at-grist $(x) ] ;
|
|
for local r in $(rules)
|
|
{
|
|
properties = [ $(r) $(toolset) $(v) : $(properties) ] ;
|
|
}
|
|
|
|
subvariant-target $(<)
|
|
: $(properties) : $(toolset) $(v) ;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gGENERATOR_FUNCTION(EXE) = executable-file ;
|
|
# exe target : sources : requirements : local-build
|
|
#
|
|
# Declare an executable target.
|
|
rule exe
|
|
{
|
|
declare-local-target $(<) : $(2) : $(3) : $(4) : EXE ;
|
|
}
|
|
|
|
gGENERATOR_FUNCTION(DLL) = dll-files ;
|
|
# dll target : sources : requirements : local-build
|
|
#
|
|
# Declare a shared library target.
|
|
rule dll
|
|
{
|
|
declare-local-target $(<) : $(2) : $(3) : $(4) : DLL ;
|
|
}
|
|
|
|
gGENERATOR_FUNCTION(LIB) = library-file ;
|
|
# lib target : sources : requirements : local-build
|
|
#
|
|
# Declare a statically-linked library target.
|
|
rule lib
|
|
{
|
|
local suppress = [ get-values <suppress> : $(4) ] ;
|
|
if $(suppress)
|
|
{
|
|
local gSUPPRESS_FAKE_TARGETS = $(suppress[1]) ;
|
|
declare-local-target $(<) : $(2) : $(3) :
|
|
[ difference $(4) : [ get-properties <suppress> : $(4) ] ] : LIB ;
|
|
}
|
|
else
|
|
{
|
|
declare-local-target $(<) : $(2) : $(3) : $(4) : LIB ;
|
|
}
|
|
}
|
|
|
|
# unit-test target : sources : requirements : local-build
|
|
#
|
|
# Declare an executable target, to be run by tests.
|
|
rule unit-test
|
|
{
|
|
|
|
local files = [ exe $(<) : $(2) : $(3) : $(4) ] ;
|
|
type-DEPENDS test : $(files) ;
|
|
|
|
COMMAND-LINE on $(files) = $(5) ;
|
|
|
|
for local file in $(files)
|
|
{
|
|
Run $(file) ;
|
|
}
|
|
}
|
|
|
|
# Used to build command files from a list of sources.
|
|
rule build-command-file ( command : sources * )
|
|
{
|
|
DEPENDS $(command) : $(sources) ;
|
|
|
|
# Check whether there's anything to dump, so that we don't end up
|
|
# executing a line of the form:
|
|
#
|
|
# echo > file.CMD
|
|
#
|
|
# on Windows this writes "echo is on." into the command-file,
|
|
# which then breaks the link.
|
|
|
|
if $(sources[1])
|
|
{
|
|
# Handle the first target specially, so that the first source file
|
|
# will clear the command file
|
|
command-file-dump-1st $(command) : $(sources[1]) ;
|
|
}
|
|
|
|
if $(sources[2])
|
|
{
|
|
# Then fill the rest up piecemeal
|
|
command-file-dump-rest $(command) : $(sources[2-]) ;
|
|
}
|
|
}
|
|
|
|
# command-file-dump-1st: dump the first source path into the target
|
|
actions quietly command-file-dump-1st
|
|
{
|
|
echo "$(>)" > "$(<)"
|
|
}
|
|
|
|
# command-file-dump: dump the remaining source paths into the target
|
|
actions quietly piecemeal command-file-dump-rest
|
|
{
|
|
echo "$(>)" >> "$(<)"
|
|
}
|
|
|
|
# Clean up the temporary COMMAND-FILE used to build TARGETS.
|
|
rule remove-command-file ( targets + : command-file )
|
|
{
|
|
TEMPORARY $(command-file) ;
|
|
Clean clean : $(command-file) ; # Mark the file for removal via clean
|
|
}
|
|
actions ignore quietly piecemeal together remove-command-file
|
|
{
|
|
$(RM) $(>)
|
|
}
|
|
|
|
# build TARGETS from SOURCES using a command-file, where RULE-NAME is
|
|
# used to generate the build instructions from the command-file to
|
|
# TARGETS
|
|
rule with-command-file ( rule-name targets * : sources * )
|
|
{
|
|
# create a command-file target and place it where the first target
|
|
# will be built
|
|
local command-file = $(<[2]:S=.CMD) ;
|
|
LOCATE on $(command-file) = $(gLOCATE($(targets[1]))) ;
|
|
build-command-file $(command-file) : $(sources) ;
|
|
|
|
# Build the targets from the command-file instead of the sources
|
|
DEPENDS $(targets) : $(command-file) ;
|
|
local result = [ $(rule-name) $(targets) : $(command-file) ] ;
|
|
|
|
# clean up afterwards
|
|
remove-command-file $(targets) : $(command-file) ;
|
|
return result ;
|
|
} |