2
0
mirror of https://github.com/boostorg/build.git synced 2026-02-17 01:32:12 +00:00
Files
build/v2/tools/builtin.jam
Vladimir Prus 9dda3d8f84 Add/clarify comments.
[SVN r18496]
2003-05-22 11:50:10 +00:00

687 lines
21 KiB
Plaintext

# Copyright (C) Vladimir Prus 2002. 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.
# Defines standard features and rules.
import class : class new ;
import feature : feature compose ;
import toolset : flags ;
import errors : error ;
import type ;
import scanner ;
import generators ;
import regex ;
import virtual-target ;
import os ;
import prebuilt ;
import symlink ;
import alias ;
import property ;
import print ;
# This feature is used to determine which OS we're on.
# In future, this may become <target-os> and <host-os>
local os = [ modules.peek : OS ] ;
feature os : $(os) : propagated link-incompatible ;
feature toolset : : implicit propagated link-incompatible symmetric ;
feature stdlib : native : propagated link-incompatible ;
feature link : shared static : propagated ;
feature link-runtime : shared static : propagated ;
feature runtime-debugging : on off : propagated ;
feature optimization : off speed space : propagated ;
feature inlining : off on full : propagated ;
feature threading : single multi : link-incompatible propagated ;
feature rtti : on off : link-incompatible propagated ;
feature exception-handling : on off : propagated ;
feature debug-symbols : on off : propagated ;
feature define : : free ;
feature "include" : : free path ;
feature cxxflags : : free ;
feature linkflags : : free ;
feature version : : free ;
feature dependency : : free dependency ;
feature library : : free dependency ;
feature find-shared-library : : free ;
feature find-static-library : : free ;
feature library-path : : free path ;
feature library-file : : free path ;
feature uses : : free ;
feature name : : free ;
feature search : : free path ;
feature location : : free path ;
feature dll-path : : free path ;
feature hardcode-dll-paths : false true : incidental propagated ;
# Windows-specific features
feature user-interface : console gui wince native auto : propagated ;
feature variant : : implicit composite propagated symmetric ;
# Declares a new variant.
# First determines explicit properties for this variant, by
# refining parents' explicit properties with the passed explicit
# properties. The result is remembered and will be used if
# this variant is used as parent.
#
# Second, determines the full property set for this variant by
# adding to the explicit properties default values for all properties
# which neither present nor are symmetric.
#
# Lastly, makes appropriate value of 'variant' property expand
# to the full property set.
rule variant ( name # Name of the variant
: parents-or-properties * # Specifies parent variants, if
# 'explicit-properties' are given,
# and explicit-properties otherwise.
: explicit-properties * # Explicit properties.
)
{
local parents ;
if ! $(explicit-properties)
{
if $(parents-or-properties[1]:G)
{
explicit-properties = $(parents-or-properties) ;
}
else
{
parents = $(parents-or-properties) ;
}
}
else
{
parents = $(parents-or-properties) ;
}
# The problem is that we have to check for conflicts
# between base variants.
if $(parents[2])
{
error "multiple base variants are not yet supported" ;
}
local inherited ;
# Add explicitly specified properties for parents
for local p in $(parents)
{
# TODO: the check may be sticter
if ! [ feature.is-implicit-value $(p) ]
{
error "Invalid base varaint" $(p) ;
}
inherited += $(.explicit-properties.$(p)) ;
}
property.validate $(explicit-properties) ;
explicit-properties = [ property.refine $(inherited) : $(explicit-properties) ] ;
# Record explicitly specified properties for this variant
# We do this after inheriting parents' properties, so that
# they affect other variants, derived from this one.
.explicit-properties.$(name) = $(explicit-properties) ;
feature.extend variant : $(name) ;
feature.compose <variant>$(name) : $(explicit-properties) ;
}
IMPORT $(__name__) : variant : : variant ;
variant debug : <optimization>off <debug-symbols>on <inlining>off <runtime-debugging>on ;
variant release : <optimization>speed <debug-symbols>off <inlining>full <runtime-debugging>off ;
# When <optimization>speed is specified, we need to add <define>NDEBUG
# It is done via 'active' features, because it should be done for
# all targets built with <optimization>speed. Since <define> is free, it is
# not propagated, we can't just add it to 'release'. And we cannot make
# <define> propagated, because (i) free features cannot be propagated and
# (ii) this is dangerous.
rule handle-ndebug ( property : properties * )
{
return <define>NDEBUG ;
}
feature.action <optimization>speed : handle-ndebug ;
rule searched-lib-target ( name
: project
: shared ?
: real-name ?
: search *
)
{
abstract-file-target.__init__ $(name) : SEARCHED_LIB : $(project) ;
self.shared = $(shared) ;
self.real-name = $(real-name) ;
self.real-name ?= $(name) ;
self.search = $(search) ;
rule shared ( )
{
return $(self.shared) ;
}
rule real-name ( )
{
return $(self.real-name) ;
}
rule search ( )
{
return $(self.search) ;
}
rule actualize-location ( target )
{
NOTFILE $(target) ;
}
rule path ( )
{
}
}
class searched-lib-target : abstract-file-target ;
type.register LIB : : : main ;
# register the given type on the specified OSes, or on remaining OSes
# if os is not specified.
local rule declare-type ( os * : type : suffixes * : base-type ? : main ? )
{
if ! [ type.registered $(type) ]
{
if ( ! $(os) ) || [ os.name ] in $(os)
{
type.register $(type) : $(suffixes) : $(base-type) : $(main) ;
}
}
}
#
# Common target types.
#
declare-type NT CYGWIN : OBJ : obj : : main ;
declare-type : OBJ : o : : main ;
declare-type NT CYGWIN : STATIC_LIB : lib : LIB : main ;
declare-type : STATIC_LIB : a : LIB : main ;
declare-type : IMPORT_LIB : : STATIC_LIB : main ;
type.set-generated-target-suffix IMPORT_LIB : : lib ;
declare-type NT CYGWIN : SHARED_LIB : dll : LIB : main ;
declare-type : SHARED_LIB : so : LIB : main ;
declare-type : SEARCHED_LIB : : LIB : main ;
declare-type NT CYGWIN : EXE : exe : : main ;
declare-type : EXE : : : main ;
declare-type : PYTHON_EXTENSION : : SHARED_LIB : main ;
# We can't give "dll" suffix to PYTHON_EXTENSION, because
# we would not know what "a.dll" is: python extenstion or
# ordinary library. Therefore, we specify only suffixes
# used for generation of targets.
type.set-generated-target-suffix PYTHON_EXTENSION : : so ;
type.set-generated-target-suffix PYTHON_EXTENSION : <os>NT : so ;
type.set-generated-target-suffix PYTHON_EXTENSION : <os>CYGWIN : dll ;
type.register CPP : cpp cxx ;
import stage ;
#
# Response files -
#
# Because of line-length limitations in the Windows NT command-shell,
# we use the "response file" feature of many toolsets, which allow us
# to write sources into a file and insert the file into the
# command-line.
#
# response-file generation is broken up into two phases, the first of
# which overwrites any existing file and the second of which appends
# to the file, piecemeal, so that no command-line is too long.
rule response-file ( target : sources * : properties * )
{
# Add libraries from <library> property to the list of sources.
local libraries ;
for local p in $(properties)
{
if $(p:G) = <library> &&
! [ type.is-derived [ $(p:G=).type ] SHARED_LIB ]
{
libraries += $(p:G=) ;
}
}
# Get real jam targets
local xlibraries ;
for local l in $(libraries)
{
xlibraries += [ $(l).actualize ] ;
}
sources += $(xlibraries) ;
response-file-1 $(target) : $(sources[1]) ;
if $(sources[2-])
{
response-file-2 $(target) : $(sources[2-]) ;
}
print.output $(target) ;
print.text [ on $(target)
return "$(LIBRARY_PATH_OPTION)$(LIBRARY_PATH)"
"$(LIBRARY_OPTION)$(FINDLIBS_ST:S=.lib)"
"$(LIBRARY_OPTION)$(FINDLIBS_SA:S=.lib)"
] ;
}
actions quietly response-file-1
{
echo "$(>)" > "$(<)"
}
actions quietly piecemeal response-file-2
{
echo "$(>)" >> "$(<)"
}
#####
rule c-scanner ( includes * )
{
scanner.__init__ ;
import regex virtual-target path scanner ;
self.includes = $(includes) ;
rule pattern ( )
{
return "#include[ ]*(<(.*)>|\"(.*)\")" ;
}
rule process ( target : matches * )
{
local angle = [ regex.transform $(matches) : "<(.*)>" ] ;
local quoted = [ regex.transform $(matches) : "\"(.*)\"" ] ;
# CONSIDER: the new scoping rule seem to defeat "on target" variables.
local g = [ on $(target) return $(HDRGRIST) ] ;
local b = [ path.native [ path.parent [ path.make
[ virtual-target.binding $(target) ] ] ] ] ;
# Attach binding of including file to included targets.
# When target is directly created from virtual target
# this extra information is unnecessary. But in other
# cases, it allows to distinguish between two headers of the
# same name included from different places.
# We don't need this extra information for angle includes,
# since they should not depend on including file (we can't
# get literal "." in include path).
local g2 = $(g)"#"$(b) ;
angle = $(angle:G=$(g)) ;
quoted = $(quoted:G=$(g2)) ;
for local i in $(angle)
{
local i2 = [ SEARCH_FOR_TARGET $(i) : $(self.includes:G=) ] ;
INCLUDES $(target) : $(i2) ;
if $(i2) = $(i)
{
NOCARE $(i) ;
SEARCH on $(i) = $(self.includes:G=) ;
}
}
for local i in $(quoted)
{
local path = $(b) $(self.includes:G=) ;
local i2 = [ SEARCH_FOR_TARGET $(i) : $(path) ] ;
INCLUDES $(target) : $(i2) ;
if $(i2) = $(i)
{
NOCARE $(i) ;
SEARCH on $(i) = $(path) ;
}
}
BINDRULE on $(angle) $(quoted) = virtual-target.remember-binding ;
# Just propagate current scanner to includes, in a hope
# that includes do not change scanners.
for local a in $(angle) $(quoted)
{
scanner.install $(__name__) : $(a) : $(target) ;
}
}
}
class c-scanner : scanner ;
scanner.register c-scanner : include ;
type.set-scanner CPP : c-scanner ;
type.register H : h hpp ;
type.register C : c ;
# Generator for 'lib' target, which relays to generators for either
# "STATIC_LIB" or "SHARED_LIB", depending on the value of
# "shared" feature.
rule lib-generator ( )
{
generator.__init__ lib-generator true : : LIB : <main-target-type>LIB ;
rule run ( project name ? : property-set : sources * )
{
local properties = [ $(property-set).raw ] ;
# Determine the needed target type
local actual-type ;
if <search> in $(properties:G) || <name> in $(properties:G)
{
actual-type = SEARCHED_LIB ;
}
else if <link>shared in $(properties)
{
actual-type = SHARED_LIB ;
}
else
{
actual-type = STATIC_LIB ;
}
# Construct the target.
return [ generators.construct $(project) $(name) : $(actual-type)
: $(property-set) : $(sources) ] ;
}
}
class lib-generator : generator ;
generators.register [ new lib-generator ] ;
rule searched-lib-generator ( )
{
# The requirements cause the generators to be tried *only* when we're building
# lib target and there's 'search' feature. This seems ugly --- all we want
# is make sure searched-lib-generator is not invoced deep in transformation
# search.
generator.__init__ searched-lib-generator : : SEARCHED_LIB ;
rule run ( project name ? : property-set : sources * : multiple ? )
{
if $(name)
{
# If name is empty, it means we're called not from top-level.
# In this case, we just fail immediately, because searched-lib-generator
# cannot be used to produce intermediate targets.
local properties = [ $(property-set).raw ] ;
local shared ;
if <link>shared in $(properties)
{
shared = true ;
}
local t = [ new searched-lib-target $(name) : $(project) : $(shared)
: [ feature.get-values <name> : $(properties) ]
: [ feature.get-values <search> : $(properties) ]
] ;
# attach an action and properties to the target
a = [ new null-action $(t) : $(property-set) ] ;
$(t).action $(a) ;
return [ virtual-target.register $(t) ] ;
}
}
}
class searched-lib-generator : generator ;
generators.register [ new searched-lib-generator ] ;
rule compile-action ( targets + : sources * : action-name : properties * )
{
action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ;
import sequence ;
# For all virtual targets for the same dependency graph as self,
# i.e. which belong to the same main target, add their directories
# to include path.
rule adjust-properties ( properties * )
{
local dg = [ $(self.targets[1]).dg ] ;
local target-paths = [ $(dg).all-target-directories ] ;
target-paths = [ sequence.unique $(target-paths) ] ;
# Note that target-paths here are already relative to invocation
# directory, and can be used as-is.
return $(properties) $(target-paths:G=include) ;
}
}
class compile-action : action ;
rule C-compiling-generator ( id : source-types + : target-types + :
requirements * )
{
generator.__init__ $(id) : $(source-types) : $(target-types) :
$(requirements) ;
rule action-class ( )
{
return compile-action ;
}
}
class C-compiling-generator : generator ;
rule register-c-compiler ( id : source-types + : target-types + :
requirements * )
{
local g = [ new C-compiling-generator $(id) : $(source-types)
: $(target-types) : $(requirements) ] ;
generators.register $(g) ;
}
# FIXME: this is ugly, should find a better way (we'd want client code to
# register all generators as "generator.some-rule", not with "some-module.some-rule".)
IMPORT $(__name__) : register-c-compiler : : generators.register-c-compiler ;
rule link-action ( targets + : sources * : action-name : properties * )
{
action.__init__ $(targets) : $(sources) : $(action-name) : $(properties) ;
import path ;
import sequence ;
# Find all libraries in sources, and <library> properties
# For each source/property-value, which is instance of searched-lib-target,
# add appropriate <find-shared-library> or <find-static-library> property.
# (replacing the origianal <library> is needed)
# Convert library sources into <library> properties.
# If <hardcode-dll-paths>true is in properties, for each library source
# add <dll-path> property with the absolute path to that library.
rule adjust-properties ( properties * )
{
# Identify all library sources and all <library> properties
# Remove that latter from 'properties'
local libraries ;
for local s in $(self.sources)
{
if [ type.is-derived [ $(s).type ] LIB ]
{
libraries += $(s) ;
}
}
local properties2 ;
for local p in $(properties)
{
if $(p:G) = <library>
{
libraries += $(p:G=) ;
}
else
{
properties2 += $(p) ;
}
}
local hardcore-rpath ;
if <hardcode-dll-paths>true in $(properties)
{
hardcore-rpath = true ;
}
# Add needed properties
local pwd = [ path.pwd ] ;
local rpaths ;
for local s in $(libraries)
{
if [ class.is-a $(s) : searched-lib-target ]
{
local name = [ $(s).real-name ] ;
local search = [ $(s).search ] ;
if [ $(s).shared ]
{
properties2 += <find-shared-library>$(name) ;
if $(hardcore-rpath)
{
rpaths += $(search) ;
}
}
else
{
properties2 += <find-static-library>$(name) ;
}
properties2 += <library-path>$(search) ;
}
else
{
if $(hardcore-rpath) &&
[ type.is-derived [ $(s).type ] SHARED_LIB ]
{
rpaths += [ path.root [ $(s).path ] $(pwd) ] ;
}
properties2 += <library>$(s) ;
}
}
if $(hardcore-rpath)
{
rpaths = [ sequence.unique $(rpaths) ] ;
properties2 += <dll-path>$(rpaths) ;
}
return $(properties2) ;
}
# Filters out all sources which are of LIB type and actualizes the remaining
# sources by calling base method.
# Library sources are handled by "adjust-properties" above.
rule actualize-sources ( sources * )
{
local real-sources ;
for local s in $(sources)
{
if ! [ type.is-derived [ $(s).type ] LIB ]
{
real-sources += $(s) ;
}
else
{
self.dependency-only-sources += [ $(s).actualize ] ;
}
}
action.actualize-sources $(real-sources) ;
}
}
class link-action : action ;
rule linking-generator ( id
composing ? : # Specify if generator is composing. The generator will be
# composing if non-empty string is passed, or parameter is
# not given. To make generator non-composing, pass empty
# string ("")
source-types + : target-types + :
requirements * )
{
composing ?= true ;
generator.__init__ $(id) $(composing) : $(source-types) : $(target-types) :
$(requirements) ;
rule run ( project name ? : property-set : sources + : multiple ? )
{
local result = [ generator.run $(project) $(name) : $(property-set)
: $(sources) : $(multiple) ] ;
if $(result)
{
# Explicitly set dependency on all <library> features.
local libs = [ feature.get-values <library> :
[ $(property-set).raw ] ] ;
if $(libs)
{
for local t in $(result)
{
$(t).depends $(libs:G=) ;
}
}
}
return $(result) ;
}
rule action-class ( )
{
return link-action ;
}
}
class linking-generator : generator ;
rule register-linker ( id composing ? : source-types + : target-types + :
requirements * )
{
local g = [ new linking-generator $(id) $(composing) : $(source-types)
: $(target-types) : $(requirements) ] ;
generators.register $(g) ;
}
IMPORT $(__name__) : register-linker : : generators.register-linker ;
declare-type : RSP : rsp ;
flags builtin.response-file FINDLIBS_ST <find-static-library> ;
flags builtin.response-file FINDLIBS_SA <find-shared-library> ;
flags builtin.response-file LIBRARY_PATH <library-path> ;
register-linker builtin.response-file : OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : RSP ;