mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
Add files that recent merge of Boost.Build missed
[SVN r68439]
This commit is contained in:
46
v2/Jamroot.jam
Normal file
46
v2/Jamroot.jam
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
path-constant SELF : . ;
|
||||
|
||||
import path ;
|
||||
import package ;
|
||||
import os ;
|
||||
|
||||
local ext = "" ;
|
||||
if [ os.on-windows ]
|
||||
{
|
||||
ext = ".exe" ;
|
||||
}
|
||||
|
||||
|
||||
package.install boost-build-engine boost-build
|
||||
: # properties
|
||||
: # binaries
|
||||
bjam$(ext)
|
||||
;
|
||||
|
||||
local e1 = [ path.glob-tree $(SELF)/example : * : . .svn ] ;
|
||||
local e2 ;
|
||||
for e in $(e1)
|
||||
{
|
||||
if [ CHECK_IF_FILE $(e) ]
|
||||
{
|
||||
e2 += $(e) ;
|
||||
}
|
||||
}
|
||||
|
||||
package.install-data boost-build-core
|
||||
: # Which subdir of $prefix/share
|
||||
boost-build
|
||||
: # What to install
|
||||
$(SELF)/boost-build.jam
|
||||
$(SELF)/build-system.jam
|
||||
[ path.glob-tree $(SELF)/build : *.jam *.py ]
|
||||
[ path.glob-tree $(SELF)/kernel : *.jam *.py ]
|
||||
[ path.glob-tree $(SELF)/util : *.jam *.py ]
|
||||
[ path.glob-tree $(SELF)/tools : *.jam *.py ]
|
||||
$(e2)
|
||||
: # What is the root of the directory
|
||||
<install-source-root>.
|
||||
;
|
||||
|
||||
alias install : boost-build-engine boost-build-core ;
|
||||
47
v2/bootstrap.bat
Normal file
47
v2/bootstrap.bat
Normal file
@@ -0,0 +1,47 @@
|
||||
@ECHO OFF
|
||||
|
||||
REM Copyright (C) 2009 Vladimir Prus
|
||||
REM
|
||||
REM Distributed under the Boost Software License, Version 1.0.
|
||||
REM (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
ECHO Bootstrapping the build engine
|
||||
if exist ".\engine\src\bin.ntx86\bjam.exe" del engine\src\bin.ntx86\bjam.exe
|
||||
if exist ".\engine\src\bin.ntx86_64\bjam.exe" del engine\src\bin.ntx86_64\bjam.exe
|
||||
cd engine\src
|
||||
|
||||
call .\build.bat %* > ..\..\bootstrap.log
|
||||
@ECHO OFF
|
||||
cd ..\..
|
||||
|
||||
if exist ".\engine\src\bin.ntx86\bjam.exe" (
|
||||
copy .\engine\src\bin.ntx86\bjam.exe . > nul
|
||||
goto :bjam_built)
|
||||
|
||||
if exist ".\engine\src\bin.ntx86_64\bjam.exe" (
|
||||
copy .\engine\src\bin.ntx86_64\bjam.exe . > nul
|
||||
goto :bjam_built)
|
||||
|
||||
goto :bjam_failure
|
||||
|
||||
:bjam_built
|
||||
|
||||
ECHO.
|
||||
ECHO Bootstrapping is done. To build, run:
|
||||
ECHO.
|
||||
ECHO .\bjam --prefix=DIR install
|
||||
ECHO.
|
||||
|
||||
goto :end
|
||||
|
||||
:bjam_failure
|
||||
|
||||
ECHO.
|
||||
ECHO Failed to bootstrap the build engine
|
||||
ECHO Please consult bootstrap.log for furter diagnostics.
|
||||
ECHO.
|
||||
|
||||
|
||||
goto :end
|
||||
|
||||
:end
|
||||
119
v2/bootstrap.sh
Executable file
119
v2/bootstrap.sh
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/bin/sh
|
||||
# Copyright (C) 2005, 2006 Douglas Gregor.
|
||||
# Copyright (C) 2006 The Trustees of Indiana University
|
||||
# Copyright (C) 2010 Bryce Lelbach
|
||||
#
|
||||
# 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)
|
||||
|
||||
# boostinspect:notab - Tabs are required for the Makefile.
|
||||
|
||||
BJAM=""
|
||||
TOOLSET=""
|
||||
BJAM_CONFIG=""
|
||||
|
||||
for option
|
||||
do
|
||||
case $option in
|
||||
|
||||
-help | --help | -h)
|
||||
want_help=yes ;;
|
||||
|
||||
-with-toolset=* | --with-toolset=* )
|
||||
TOOLSET=`expr "x$option" : "x-*with-toolset=\(.*\)"`
|
||||
;;
|
||||
|
||||
-*)
|
||||
{ echo "error: unrecognized option: $option
|
||||
Try \`$0 --help' for more information." >&2
|
||||
{ (exit 1); exit 1; }; }
|
||||
;;
|
||||
|
||||
esac
|
||||
done
|
||||
|
||||
if test "x$want_help" = xyes; then
|
||||
cat <<EOF
|
||||
\`./bootstrap.sh' creates minimal Boost.Build, which can install itself.
|
||||
|
||||
Usage: $0 [OPTION]...
|
||||
|
||||
Defaults for the options are specified in brackets.
|
||||
|
||||
Configuration:
|
||||
-h, --help display this help and exit
|
||||
--with-bjam=BJAM use existing Boost.Jam executable (bjam)
|
||||
[automatically built]
|
||||
--with-toolset=TOOLSET use specific Boost.Build toolset
|
||||
[automatically detected]
|
||||
EOF
|
||||
fi
|
||||
test -n "$want_help" && exit 0
|
||||
|
||||
# TBD: Determine where the script is located
|
||||
my_dir="."
|
||||
|
||||
# Determine the toolset, if not already decided
|
||||
if test "x$TOOLSET" = x; then
|
||||
guessed_toolset=`$my_dir/engine/src/build.sh --guess-toolset`
|
||||
case $guessed_toolset in
|
||||
acc | darwin | gcc | como | mipspro | pathscale | pgi | qcc | vacpp )
|
||||
TOOLSET=$guessed_toolset
|
||||
;;
|
||||
|
||||
intel-* )
|
||||
TOOLSET=intel
|
||||
;;
|
||||
|
||||
mingw )
|
||||
TOOLSET=gcc
|
||||
;;
|
||||
|
||||
clang* )
|
||||
TOOLSET=clang
|
||||
;;
|
||||
|
||||
sun* )
|
||||
TOOLSET=sun
|
||||
;;
|
||||
|
||||
* )
|
||||
# Not supported by Boost.Build
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case $TOOLSET in
|
||||
clang*)
|
||||
TOOLSET=clang
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
rm -f config.log
|
||||
|
||||
# Build bjam
|
||||
if test "x$BJAM" = x; then
|
||||
echo -n "Bootstrapping the build engine with toolset $TOOLSET... "
|
||||
pwd=`pwd`
|
||||
(cd "$my_dir/engine/src" && ./build.sh "$TOOLSET") > bootstrap.log 2>&1
|
||||
if [ $? -ne 0 ]; then
|
||||
echo
|
||||
echo "Failed to bootstrap the build engine"
|
||||
echo "Consult 'bootstrap.log' for more details"
|
||||
exit 1
|
||||
fi
|
||||
cd "$pwd"
|
||||
arch=`cd $my_dir/engine/src && ./bootstrap/jam0 -d0 -f build.jam --toolset=$TOOLSET --toolset-root= --show-locate-target && cd ..`
|
||||
BJAM="$my_dir/engine/src/$arch/bjam"
|
||||
echo "engine/src/$arch/bjam"
|
||||
cp "$BJAM" .
|
||||
fi
|
||||
|
||||
cat << EOF
|
||||
|
||||
Bootstrapping is done. To build and install, run:
|
||||
|
||||
./bjam install --prefix=<DIR>
|
||||
|
||||
EOF
|
||||
198
v2/build/ac.jam
Normal file
198
v2/build/ac.jam
Normal file
@@ -0,0 +1,198 @@
|
||||
# Copyright (c) 2010 Vladimir Prus.
|
||||
#
|
||||
# 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)
|
||||
|
||||
import property-set ;
|
||||
import path ;
|
||||
import modules ;
|
||||
import "class" ;
|
||||
import errors ;
|
||||
import configure ;
|
||||
|
||||
rule find-include-path ( variable : properties : header
|
||||
: provided-path ? )
|
||||
{
|
||||
# FIXME: document which properties affect this function by
|
||||
# default.
|
||||
local target-os = [ $(properties).get <target-os> ] ;
|
||||
properties = [ property-set.create <target-os>$(toolset) ] ;
|
||||
if $($(variable)-$(properties))
|
||||
{
|
||||
return $($(variable)-$(properties)) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
provided-path ?= [ modules.peek : $(variable) ] ;
|
||||
includes = $(provided-path) ;
|
||||
includes += [ $(properties).get <include> ] ;
|
||||
if [ $(properties).get <target-os> ] != windows
|
||||
{
|
||||
# FIXME: use sysroot
|
||||
includes += /usr/include ;
|
||||
}
|
||||
|
||||
local result ;
|
||||
while ! $(result) && $(includes)
|
||||
{
|
||||
local f = [ path.root $(header) $(includes[1]) ] ;
|
||||
ECHO "Checking " $(f) ;
|
||||
if [ path.exists $(f) ]
|
||||
{
|
||||
result = $(includes[1]) ;
|
||||
}
|
||||
else if $(provided-path)
|
||||
{
|
||||
errors.user-error "Could not find header" $(header)
|
||||
: "in the user-specified directory" $(provided-path) ;
|
||||
}
|
||||
includes = $(includes[2-]) ;
|
||||
}
|
||||
$(variable)-$(properties) = $(result) ;
|
||||
return $(result) ;
|
||||
}
|
||||
}
|
||||
|
||||
rule find-library ( variable : properties : names + : provided-path ? )
|
||||
{
|
||||
local target-os = [ $(properties).get <target-os> ] ;
|
||||
properties = [ property-set.create <target-os>$(toolset) ] ;
|
||||
if $($(variable)-$(properties))
|
||||
{
|
||||
return $($(variable)-$(properties)) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
provided-path ?= [ modules.peek : $(variable) ] ;
|
||||
paths = $(provided-path) ;
|
||||
paths += [ $(properties).get <library-path> ] ;
|
||||
if [ $(properties).get <target-os> ] != windows
|
||||
{
|
||||
paths += /usr/lib /usr/lib32 /usr/lib64 ;
|
||||
}
|
||||
|
||||
local result ;
|
||||
while ! $(result) && $(paths)
|
||||
{
|
||||
while ! $(result) && $(names)
|
||||
{
|
||||
local f ;
|
||||
if $(target-os) = windows
|
||||
{
|
||||
f = $(paths[1])/$(names[1]).lib ;
|
||||
if [ path.exists $(f) ]
|
||||
{
|
||||
result = $(f) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
# FIXME: check for .a as well, depending on
|
||||
# the 'link' feature.
|
||||
f = $(paths[1])/lib$(names[1]).so ;
|
||||
ECHO "CHECKING $(f) " ;
|
||||
if [ path.exists $(f) ]
|
||||
{
|
||||
result = $(f) ;
|
||||
}
|
||||
}
|
||||
if ! $(result) && $(provided-path)
|
||||
{
|
||||
errors.user-error "Could not find either of: " $(names)
|
||||
: "in the user-specified directory" $(provided-path) ;
|
||||
|
||||
}
|
||||
names = $(names[2-]) ;
|
||||
}
|
||||
paths = $(paths[2-]) ;
|
||||
}
|
||||
$(variable)-$(properties) = $(result) ;
|
||||
return $(result) ;
|
||||
}
|
||||
}
|
||||
|
||||
class ac-library : basic-target
|
||||
{
|
||||
import errors ;
|
||||
import indirect ;
|
||||
import virtual-target ;
|
||||
import ac ;
|
||||
import configure ;
|
||||
|
||||
rule __init__ ( name : project : * : * )
|
||||
{
|
||||
basic-target.__init__ $(name) : $(project) : $(sources)
|
||||
: $(requirements) ;
|
||||
|
||||
reconfigure $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
||||
}
|
||||
|
||||
rule set-header ( header )
|
||||
{
|
||||
self.header = $(header) ;
|
||||
}
|
||||
|
||||
rule set-default-names ( names + )
|
||||
{
|
||||
self.default-names = $(names) ;
|
||||
}
|
||||
|
||||
rule reconfigure ( * : * )
|
||||
{
|
||||
ECHO "XXX" $(1) ;
|
||||
if ! $(1)
|
||||
{
|
||||
# This is 'using xxx ;'. Nothing to configure, really.
|
||||
}
|
||||
else
|
||||
{
|
||||
for i in 1 2 3 4 5 6 7 8 9
|
||||
{
|
||||
# FIXME: this naming is inconsistent with XXX_INCLUDE/XXX_LIBRARY
|
||||
if ! ( $($(i)[1]) in root include-path library-path library-name condition )
|
||||
{
|
||||
errors.user-error "Invalid named parameter" $($(i)[1]) ;
|
||||
}
|
||||
local name = $($(i)[1]) ;
|
||||
local value = $($(i)[2-]) ;
|
||||
if $($(name)) && $($(name)) != $(value)
|
||||
{
|
||||
errors.user-error "Attempt to change value of '$(name)'" ;
|
||||
}
|
||||
$(name) = $(value) ;
|
||||
}
|
||||
|
||||
include-path ?= $(root)/include ;
|
||||
library-path ?= $(root)/lib ;
|
||||
}
|
||||
}
|
||||
|
||||
rule construct ( name : sources * : property-set )
|
||||
{
|
||||
# FIXME: log results.
|
||||
local libnames = $(library-name) ;
|
||||
if ! $(libnames) && ! $(include-path) && ! $(library-path)
|
||||
{
|
||||
libnames = [ modules.peek : $(name:U)_NAME ] ;
|
||||
# Backward compatibility only.
|
||||
libnames ?= [ modules.peek : $(name:U)_BINARY ] ;
|
||||
}
|
||||
libnames ?= $(self.default-names) ;
|
||||
|
||||
local includes = [
|
||||
ac.find-include-path $(name:U)_INCLUDE : $(property-set) : $(self.header) : $(include-path) ] ;
|
||||
local library = [ ac.find-library $(name:U)_LIBRARY : $(property-set) : $(libnames) : $(library-path) ] ;
|
||||
if $(includes) && $(library)
|
||||
{
|
||||
library = [ virtual-target.from-file $(library) : . : $(self.project) ] ;
|
||||
configure.log-library-search-result $(name) : "found" ;
|
||||
return [ property-set.create <include>$(includes) <source>$(library) ] ;
|
||||
}
|
||||
else
|
||||
{
|
||||
configure.log-library-search-result $(name) : "no found" ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
164
v2/build/configure.py
Normal file
164
v2/build/configure.py
Normal file
@@ -0,0 +1,164 @@
|
||||
# Status: ported.
|
||||
# Base revison: 64488
|
||||
#
|
||||
# Copyright (c) 2010 Vladimir Prus.
|
||||
#
|
||||
# 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)
|
||||
|
||||
# This module defines function to help with two main tasks:
|
||||
#
|
||||
# - Discovering build-time configuration for the purposes of adjusting
|
||||
# build process.
|
||||
# - Reporting what is built, and how it is configured.
|
||||
|
||||
import b2.build.property as property
|
||||
import b2.build.property_set as property_set
|
||||
|
||||
import b2.build.targets
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util.sequence import unique
|
||||
from b2.util import bjam_signature, value_to_jam
|
||||
|
||||
import bjam
|
||||
import os
|
||||
|
||||
__width = 30
|
||||
|
||||
def set_width(width):
|
||||
global __width
|
||||
__width = 30
|
||||
|
||||
__components = []
|
||||
__built_components = []
|
||||
__component_logs = {}
|
||||
__announced_checks = False
|
||||
|
||||
__log_file = None
|
||||
__log_fd = -1
|
||||
|
||||
def register_components(components):
|
||||
"""Declare that the components specified by the parameter exist."""
|
||||
__components.extend(components)
|
||||
|
||||
def components_building(components):
|
||||
"""Declare that the components specified by the parameters will be build."""
|
||||
__built_components.extend(components)
|
||||
|
||||
def log_component_configuration(component, message):
|
||||
"""Report something about component configuration that the user should better know."""
|
||||
__component_logs.setdefault(component, []).append(message)
|
||||
|
||||
def log_check_result(result):
|
||||
global __announced_checks
|
||||
if not __announced_checks:
|
||||
print "Performing configuration checks"
|
||||
__announced_checks = True
|
||||
|
||||
print result
|
||||
|
||||
def log_library_search_result(library, result):
|
||||
log_check_result((" - %(library)s : %(result)s" % locals()).rjust(width))
|
||||
|
||||
|
||||
def print_component_configuration():
|
||||
|
||||
print "\nComponent configuration:"
|
||||
for c in __components:
|
||||
if c in __built_components:
|
||||
s = "building"
|
||||
else:
|
||||
s = "not building"
|
||||
message = " - %s)" % c
|
||||
message = message.rjust(__width)
|
||||
message += " : " + s
|
||||
for m in __component_logs.get(c, []):
|
||||
print " -" + m
|
||||
print ""
|
||||
|
||||
__builds_cache = {}
|
||||
|
||||
def builds(metatarget_reference, project, ps, what):
|
||||
# Attempt to build a metatarget named by 'metatarget-reference'
|
||||
# in context of 'project' with properties 'ps'.
|
||||
# Returns non-empty value if build is OK.
|
||||
|
||||
result = []
|
||||
|
||||
existing = __builds_cache.get((what, ps), None)
|
||||
if existing is None:
|
||||
|
||||
result = False
|
||||
__builds_cache[(what, ps)] = False
|
||||
|
||||
targets = b2.build.targets.generate_from_reference(
|
||||
metatarget_reference, project, ps).targets()
|
||||
jam_targets = []
|
||||
for t in targets:
|
||||
jam_targets.append(t.actualize())
|
||||
|
||||
x = (" - %s" % what).rjust(__width)
|
||||
if bjam.call("UPDATE_NOW", jam_targets, str(__log_fd), "ignore-minus-n"):
|
||||
__builds_cache[(what, ps)] = True
|
||||
result = True
|
||||
log_check_result("%s: yes" % x)
|
||||
else:
|
||||
log_check_result("%s: no" % x)
|
||||
|
||||
return result
|
||||
else:
|
||||
return existing
|
||||
|
||||
def set_log_file(log_file_name):
|
||||
# Called by Boost.Build startup code to specify name of a file
|
||||
# that will receive results of configure checks. This
|
||||
# should never be called by users.
|
||||
global __log_file, __log_fd
|
||||
dirname = os.path.dirname(log_file_name)
|
||||
if not os.path.exists(dirname):
|
||||
os.makedirs(dirname)
|
||||
# Make sure to keep the file around, so that it's not
|
||||
# garbage-collected and closed
|
||||
__log_file = open(log_file_name, "w")
|
||||
__log_fd = __log_file.fileno()
|
||||
|
||||
# Frontend rules
|
||||
|
||||
class CheckTargetBuildsWorker:
|
||||
|
||||
def __init__(self, target, true_properties, false_properties):
|
||||
self.target = target
|
||||
self.true_properties = property.create_from_strings(true_properties, True)
|
||||
self.false_properties = property.create_from_strings(false_properties, True)
|
||||
|
||||
def check(self, ps):
|
||||
|
||||
# FIXME: this should not be hardcoded. Other checks might
|
||||
# want to consider different set of features as relevant.
|
||||
toolset = ps.get('toolset')[0]
|
||||
toolset_version_property = "<toolset-" + toolset + ":version>" ;
|
||||
relevant = ps.get_properties('target-os') + \
|
||||
ps.get_properties("toolset") + \
|
||||
ps.get_properties(toolset_version_property) + \
|
||||
ps.get_properties("address-model") + \
|
||||
ps.get_properties("architecture")
|
||||
rps = property_set.create(relevant)
|
||||
t = get_manager().targets().current()
|
||||
p = t.project()
|
||||
if builds(self.target, p, rps, "%s builds" % self.target):
|
||||
choosen = self.true_properties
|
||||
else:
|
||||
choosen = self.false_properties
|
||||
return property.evaluate_conditionals_in_context(choosen, ps)
|
||||
|
||||
@bjam_signature((["target"], ["true_properties", "*"], ["false_properties", "*"]))
|
||||
def check_target_builds(target, true_properties, false_properties):
|
||||
worker = CheckTargetBuildsWorker(target, true_properties, false_properties)
|
||||
value = value_to_jam(worker.check)
|
||||
return "<conditional>" + value
|
||||
|
||||
get_manager().projects().add_rule("check-target-builds", check_target_builds)
|
||||
|
||||
|
||||
1696
v2/doc/bjam.qbk
Normal file
1696
v2/doc/bjam.qbk
Normal file
File diff suppressed because it is too large
Load Diff
377
v2/doc/history.qbk
Normal file
377
v2/doc/history.qbk
Normal file
@@ -0,0 +1,377 @@
|
||||
[variablelist
|
||||
|
||||
[[3.1.18] [
|
||||
|
||||
After years of bjam developments.. This is going to be the last unbundled release of the
|
||||
3.1.x series. From this point forward bjam will only be bundled as part of the larger
|
||||
Boost Build system. And hence will likely change name at some point. As a side effect
|
||||
of this move people will get more frequent release of bjam (or whatever it ends up being
|
||||
called).
|
||||
|
||||
[list
|
||||
[li New built-ins, MD5, SPLIT_BY_CHARACTERS, PRECIOUS, PAD, FILE_OPEN, and UPDATE_NOW.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Ensure all file descriptors are closed when executing actions complete on *nix.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Fix warnings, patch from Mateusz Loskot.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Add KEEP_GOING var to programatically override the '-q' option.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Add more parameters, up to 19 from 9, to rule invocations. Patch from
|
||||
Jonathan Biggar.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Print failed command output even if the normally quite '-d0' option.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Build of bjam with vc10, aka Visual Studio 2010.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li More macros for detection of OSPLAT, patch from John W. Bito.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Add PARALLELISM var to programatically override the '-j' option.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Tweak doc building to allow for PDF generation of docs.
|
||||
-- ['John M.]
|
||||
]
|
||||
]
|
||||
|
||||
]]
|
||||
|
||||
[[3.1.17] [
|
||||
|
||||
A year in the making this release has many stability improvements and various performance
|
||||
improvements. And because of the efforts of Jurko the code is considerably more readable!
|
||||
|
||||
[list
|
||||
[li Reflect the results of calling bjam from Python.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li For building on Windows: Rework how arguments are parsed and tested to fix handling
|
||||
of quoted arguments, options arguments, and arguments with "=".
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Try to work around at least one compiler bug with GCC and variable aliasing that
|
||||
causes crashes with hashing file cache entries.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add -Wc,-fno-strict-aliasing for QCC/QNX to avoid the same aliasing crashes as in
|
||||
the general GCC 4.x series (thanks to Niklas Angare for the fix).
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li On Windows let the child bjam commands inherit stdin, as some commands assume
|
||||
it's available.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li On Windows don't limit bjam output to ASCII as some tools output characters in
|
||||
extended character sets.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Isolate running of bjam tests to individual bjam instances to prevent possible
|
||||
spillover errors from one test affecting another test. Separate the bjam used to run
|
||||
the tests vs. the bjam being tested. And add automatic re-building of the bjam being
|
||||
tested.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Fix some possible overrun issues revealed by Fortify build. Thanks to Steven Robbins
|
||||
for pointing out the issues.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Handle \\n and \\r escape sequences.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Minor edits to remove -Wall warnings.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Dynamically adjust pwd buffer query size to allow for when PATH_MAX is default
|
||||
defined instead of being provided by the system C library.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Minor perf improvement for bjam by replacing hash function with faster version. Only
|
||||
1% diff for Boost tree.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Updated Boost Jam's error location reporting when parsing Jamfiles. Now it reports
|
||||
the correct error location information when encountering an unexpected EOF. It now
|
||||
also reports where an invalid lexical token being read started instead of finished
|
||||
which makes it much easier to find errors like unclosed quotes or curly braces.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Removed the -xarch=generic architecture from build.jam
|
||||
as this option is unknown so the Sun compilers on Linux.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Fixed a bug with T_FATE_ISTMP getting reported as T_FATE_ISTMP & T_FATE_NEEDTMP at
|
||||
the same time due to a missing break in a switch statement.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Fixed a Boost Jam bug causing it to sometimes trigger actions depending on targets
|
||||
that have not been built yet.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Added missing documentation for Boost Jam's :T variable expansion modifier which
|
||||
converts all back-slashes ('\\') to forward slashed ('/').
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Added Boost Jam support for executing command lines longer than 2047 characters (up
|
||||
to 8191) characters when running on Windows XP or later OS version.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Fixed a Boost Jam bug on Windows causing its SHELL command not to work correctly with
|
||||
some commands containing quotes.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Corrected a potential memory leak in Boost Jam's builtin_shell() function that would
|
||||
appear should Boost Jam ever start to release its allocated string objects.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Made all Boost Jam's ECHO commands automatically flush the standard output to make
|
||||
that output more promptly displayed to the user.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Made Boost Jam tests quote their bjam executable name when calling it allowing those
|
||||
executables to contain spaces in their name and/or path.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Change execunix.c to always use fork() instead of
|
||||
vfork() on the Mac. This works around known issues
|
||||
with bjam on PPC under Tiger and a problem reported
|
||||
by Rene with bjam on x86 under Leopard.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Corrected a bug in Boost Jam's base Jambase script causing it to trim the error
|
||||
message displayed when its boost-build rule gets called multiple times.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li When importing from Python into an module with empty string as name,
|
||||
import into root module.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Patch for the NORMALIZE_PATH builtin Boost Jam rule as well as an appropriate update
|
||||
for the path.jam Boost Build module where that rule was being used to implement path
|
||||
join and related operations.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Fixed a bug causing Boost Jam not to handle target file names specified as both short
|
||||
and long file names correctly.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Relaxed test, ignoring case of drive letter.
|
||||
-- ['Roland S.]
|
||||
]
|
||||
[li Implemented a patch contributed by Igor Nazarenko reimplementing the list_sort()
|
||||
function to use a C qsort() function instead of a hand-crafted merge-sort algorithm.
|
||||
Makes some list sortings (e.g. 1,2,1,2,1,2,1,2, \.\.\.) extremely faster, in turn
|
||||
significantly speeding up some project builds.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Fixed a bug with bjam not handling the '\' root Windows path correctly without its
|
||||
drive letter being specified.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Solved the problem with child process returning the value 259 (Windows constant
|
||||
STILL_ACTIVE) causing bjam never to detect that it exited and therefore keep running
|
||||
in an endless loop.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Solved the problem with bjam going into an active wait state, hogging up processor
|
||||
resources, when waiting for one of its child processes to terminate while not all of
|
||||
its available child process slots are being used.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Solved a race condition between bjam's output reading/child process termination
|
||||
detection and the child process's output generation/termination which could have
|
||||
caused bjam not to collect the terminated process's final output.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Change from vfork to fork for executing actions on Darwin to improve stability.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Code reformatting and cleanups.
|
||||
-- ['Jurko G.]
|
||||
]
|
||||
[li Implement ISFILE built-in.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
]
|
||||
|
||||
]]
|
||||
|
||||
[[3.1.16] [
|
||||
|
||||
This is mostly a bug fix release.
|
||||
|
||||
[list
|
||||
[li Work around some Windows CMD.EXE programs that will fail executing a totally
|
||||
empty batch file.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add support for detection and building with =vc9=.
|
||||
-- ['John P.]
|
||||
]
|
||||
[li Plug memory leak when closing out actions. Thanks to Martin Kortmann for finding this.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Various improvements to =__TIMING_RULE__= and =__ACTION_RULE__= target variable
|
||||
hooks.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Change [^JAMDATE] to use common ISO date format.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add test for result status values of simple actions, i.e. empty actions.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Fix buffer overrun bug in expanding [^@()] subexpressions.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Check empty string invariants, instead of assuming all strings are allocated.
|
||||
And reset strings when they are freed.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add [^OSPLAT=PARISC] for HP-UX PA-RISC.
|
||||
-- ['Boris G.]
|
||||
]
|
||||
[li Make quietly actions really quiet by not printing the command output. The
|
||||
output for the quietly actions is still available through =__ACTION_RULE__=.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Switch intel-win32 to use static multi thread runtime since the single
|
||||
thread static runtime is no longer available.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li When setting =OSPLAT=, check =__ia64= macro.
|
||||
-- ['Boris G.]
|
||||
]
|
||||
[li Get the unix timing working correctly.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Add =-fno-strict-aliasing= to compilation with gcc. Which works around
|
||||
GCC-4.2 crash problems.
|
||||
-- ['Boris G.]
|
||||
]
|
||||
[li Increased support for Python integration.
|
||||
-- ['Vladimir P.], ['Daniel W.]
|
||||
]
|
||||
[li Allow specifying options with quotes, i.e. [^--with-python=xyz], to work
|
||||
around the CMD shell using [^=] as an argument separator.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add values of variables specified with -s to .EVNRION
|
||||
module, so that we can override environment on
|
||||
command line.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Make NORMALIZE_PATH convert \\ to /.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
]
|
||||
|
||||
]]
|
||||
|
||||
[[3.1.15] [
|
||||
|
||||
This release sees a variety of fixes for long standing Perforce/Jam problems. Most of
|
||||
them relating to running actions in parallel with the -jN option. The end result of the
|
||||
changes is that running parallel actions is now reliably possible in Unix and Windows
|
||||
environments. Many thanks to Noel for joining the effort, to implement and fix the Unix
|
||||
side of stuff.
|
||||
|
||||
[list
|
||||
[li Add support for building bjam with pgi and pathscale toolsets.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Implement running action commands through pipes (-p option) to fix jumbled
|
||||
output when using parallel execution with -j option. This is implemented
|
||||
for Unix variants, and Windows (Win32/NT).
|
||||
-- ['Rene R.], ['Noel B.]
|
||||
]
|
||||
[li Add "sun" as alias to Sun Workshop compiler tools.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Set MAXLINE in jam.h to 23k bytes for AIX. The piecemeal archive action
|
||||
was broken with the default MAXLINE of 102400. Because the AIX shell uses
|
||||
some of the 24k default buffer size for its own use, I reduced it to 23k.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Make use of output dir options of msvc to not polute src dir with compiled files.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li A small fix, so -d+2 will always show the "real" commands being executed
|
||||
instead of casually the name of a temporary batch file.
|
||||
-- ['Roland S.]
|
||||
]
|
||||
[li Add test to check 'bjam -n'.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add test to check 'bjam -d2'.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Bring back missing output of -n option. The -o option continues to be
|
||||
broken as it has been for a long time now because of the @ file feature.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Update GC support to work with Boehm GC 7.0.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Revert the BOOST_BUILD_PATH change, since the directory passed to
|
||||
boost-build should be first in searched paths, else project local
|
||||
build system will not be picked correctly. The order had been changed to
|
||||
allow searching of alternate user-config.jam files from boost build. This
|
||||
better should be done with --user-config= switch or similar.
|
||||
-- ['Roland S.]
|
||||
]
|
||||
[li Initial support for defining action body from Python.
|
||||
-- ['Vladimir P.]
|
||||
]
|
||||
[li Implement @() expansion during parse phase.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Define OSPLAT var unconditionally, and more generically, when possible.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Fix undeclared INT_MAX on some platforms, i.e. Linux.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Modified execunix.c to add support for terminating
|
||||
processes that consume too much cpu or that hang and
|
||||
fail to consume cpu at all. This in support of the
|
||||
bjam -lx option.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Add internal dependencies for multi-file generating actions to indicate
|
||||
that the targets all only appear when the first target appears. This fixes
|
||||
the long standing problem Perforce/Jam has with multi-file actions and
|
||||
parallel execution (-jN).
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add test of -l limit option now that it's implemented on windows and unix.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Add test for no-op @() expansion.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Handle invalid formats of @() as doing a straight substitution instead of
|
||||
erroring out.
|
||||
-- ['Rene R.]
|
||||
]
|
||||
[li Various fixes to compile on SGI/Irix.
|
||||
-- ['Noel B.]
|
||||
]
|
||||
[li Add output for when actions timeout with -lN option.
|
||||
-- ['Rene R.], ['Noel B.]
|
||||
]
|
||||
[li Add needed include (according to XOPEN) for definition of WIFEXITED and WEXITSTATUS.
|
||||
-- ['Markus S.]
|
||||
]
|
||||
]
|
||||
|
||||
]]
|
||||
|
||||
]
|
||||
1
v2/engine/boost-no-inspect
Normal file
1
v2/engine/boost-no-inspect
Normal file
@@ -0,0 +1 @@
|
||||
this really out of our hands, so tell inspect to ignore directory
|
||||
47
v2/example/customization/verbatim.py
Normal file
47
v2/example/customization/verbatim.py
Normal file
@@ -0,0 +1,47 @@
|
||||
# Copyright 2010 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 file is only used with Python port of Boost.Build
|
||||
|
||||
# This file shows some of the primary customization mechanisms in Boost.Build V2
|
||||
# and should serve as a basic for your own customization.
|
||||
# Each part has a comment describing its purpose, and you can pick the parts
|
||||
# which are relevant to your case, remove everything else, and then change names
|
||||
# and actions to taste.
|
||||
|
||||
# Declare a new target type. This allows Boost.Build to do something sensible
|
||||
# when targets with the .verbatim extension are found in sources.
|
||||
import b2.build.type as type
|
||||
type.register("VERBATIM", ["verbatim"])
|
||||
|
||||
# Declare a dependency scanner for the new target type. The
|
||||
# 'inline-file.py' script does not handle includes, so this is
|
||||
# only for illustraction.
|
||||
import b2.build.scanner as scanner;
|
||||
# First, define a new class, derived from 'common-scanner',
|
||||
# that class has all the interesting logic, and we only need
|
||||
# to override the 'pattern' method which return regular
|
||||
# expression to use when scanning.
|
||||
class VerbatimScanner(scanner.CommonScanner):
|
||||
|
||||
def pattern(self):
|
||||
return "//###include[ ]*\"([^\"]*)\""
|
||||
|
||||
scanner.register(VerbatimScanner, ["include"])
|
||||
type.set_scanner("VERBATIM", VerbatimScanner)
|
||||
|
||||
import b2.build.generators as generators
|
||||
|
||||
generators.register_standard("verbatim.inline-file",
|
||||
["VERBATIM"], ["CPP"])
|
||||
|
||||
from b2.manager import get_manager
|
||||
|
||||
get_manager().engine().register_action("verbatim.inline-file",
|
||||
"""
|
||||
./inline_file.py $(<) $(>)
|
||||
""")
|
||||
|
||||
|
||||
|
||||
26
v2/example/generate/gen.jam
Normal file
26
v2/example/generate/gen.jam
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
import "class" : new ;
|
||||
import common ;
|
||||
|
||||
rule generate-example ( project name : property-set : sources * )
|
||||
{
|
||||
local result ;
|
||||
for local s in $(sources)
|
||||
{
|
||||
#local source-name = [ $(s).name ] ;
|
||||
#local source-action = [ $(s).action ] ;
|
||||
#local source-properties = [ $(source-action).properties ] ;
|
||||
|
||||
# Create a new action, that takes the source target and runs the
|
||||
# 'common.copy' command on it.
|
||||
local a = [ new non-scanning-action $(s) : common.copy : $(property-set)
|
||||
] ;
|
||||
|
||||
# Create a target to represent the action result. Uses the target name
|
||||
# passed here via the 'name' parameter and the same type and project as
|
||||
# the source.
|
||||
result += [ new file-target $(name) : [ $(s).type ] : $(project) : $(a)
|
||||
] ;
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
16
v2/example/generate/gen.py
Normal file
16
v2/example/generate/gen.py
Normal file
@@ -0,0 +1,16 @@
|
||||
|
||||
from b2.build.virtual_target import NonScanningAction, FileTarget
|
||||
|
||||
def generate_example(project, name, ps, sources):
|
||||
|
||||
result = []
|
||||
for s in sources:
|
||||
|
||||
a = NonScanningAction([s], "common.copy", ps)
|
||||
|
||||
# Create a target to represent the action result. Uses the target name
|
||||
# passed here via the 'name' parameter and the same type and project as
|
||||
# the source.
|
||||
result.append(FileTarget(name, s.type(), project, a))
|
||||
|
||||
return result
|
||||
26
v2/test/dependency-test/foo.py
Normal file
26
v2/test/dependency-test/foo.py
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2002, 2003, 2005, 2010 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)
|
||||
|
||||
import bjam
|
||||
import b2.build.type as type
|
||||
import b2.build.generators as generators
|
||||
|
||||
from b2.manager import get_manager
|
||||
|
||||
type.register("FOO", ["foo"])
|
||||
generators.register_standard("foo.foo", ["FOO"], ["CPP", "H"])
|
||||
|
||||
def prepare_foo(targets, sources, properties):
|
||||
|
||||
if properties.get('os') in ['windows', 'cygwin']:
|
||||
bjam.call('set-target-variable', targets, "DECL",
|
||||
"void __declspec(dllexport) foo(){}")
|
||||
|
||||
pass
|
||||
|
||||
get_manager().engine().register_action("foo.foo",\
|
||||
"""echo -e $(DECL:E="//")\\n > $(<[1])
|
||||
echo -e "#include <z.h>\\n" > $(<[2])
|
||||
""", function=prepare_foo)
|
||||
69
v2/tools/cast.py
Normal file
69
v2/tools/cast.py
Normal file
@@ -0,0 +1,69 @@
|
||||
# Status: ported
|
||||
# Base revision: 64432.
|
||||
# Copyright 2005-2010 Vladimir Prus.
|
||||
# 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)
|
||||
|
||||
# Defines main target 'cast', used to change type for target. For example, in Qt
|
||||
# library one wants two kinds of CPP files -- those that just compiled and those
|
||||
# that are passed via the MOC tool.
|
||||
#
|
||||
# This is done with:
|
||||
#
|
||||
# exe main : main.cpp [ cast _ moccable-cpp : widget.cpp ] ;
|
||||
#
|
||||
# Boost.Build will assing target type CPP to both main.cpp and widget.cpp. Then,
|
||||
# the cast rule will change target type of widget.cpp to MOCCABLE-CPP, and Qt
|
||||
# support will run the MOC tool as part of the build process.
|
||||
#
|
||||
# At the moment, the 'cast' rule only works for non-derived (source) targets.
|
||||
#
|
||||
# TODO: The following comment is unclear or incorrect. Clean it up.
|
||||
# > Another solution would be to add a separate main target 'moc-them' that
|
||||
# > would moc all the passed sources, no matter what their type is, but I prefer
|
||||
# > cast, as defining a new target type + generator for that type is somewhat
|
||||
# > simpler than defining a main target rule.
|
||||
|
||||
import b2.build.targets as targets
|
||||
import b2.build.virtual_target as virtual_target
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util import bjam_signature
|
||||
|
||||
class CastTargetClass(targets.TypedTarget):
|
||||
|
||||
def construct(name, source_targets, ps):
|
||||
result = []
|
||||
for s in source_targets:
|
||||
if not isinstance(s, virtual_targets.FileTarget):
|
||||
get_manager().errors()("Source to the 'cast' metatager is not a file")
|
||||
|
||||
if s.action():
|
||||
get_manager().errors()("Only non-derived targets allowed as sources for 'cast'.")
|
||||
|
||||
|
||||
r = s.clone_with_different_type(self.type())
|
||||
result.append(get_manager().virtual_targets().register(r))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@bjam_signature((["name", "type"], ["sources", "*"], ["requirements", "*"],
|
||||
["default_build", "*"], ["usage_requirements", "*"]))
|
||||
def cast(name, type, sources, requirements, default_build, usage_requirements):
|
||||
|
||||
from b2.manager import get_manager
|
||||
t = get_manager().targets()
|
||||
|
||||
project = get_manager().projects().current()
|
||||
|
||||
return t.main_target_alternative(
|
||||
CastTargetClass(name, project, type,
|
||||
t.main_target_sources(sources, name),
|
||||
t.main_target_requirements(requirements, project),
|
||||
t.main_target_default_build(default_build, project),
|
||||
t.main_target_usage_requirements(usage_requirements, project)))
|
||||
|
||||
|
||||
get_manager().projects().add_rule("cast", cast)
|
||||
46
v2/tools/message.py
Normal file
46
v2/tools/message.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# Status: ported.
|
||||
# Base revision: 64488.
|
||||
#
|
||||
# Copyright 2008, 2010 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)
|
||||
|
||||
# Defines main target type 'message', that prints a message when built for the
|
||||
# first time.
|
||||
|
||||
import b2.build.targets as targets
|
||||
import b2.build.property_set as property_set
|
||||
|
||||
from b2.manager import get_manager
|
||||
|
||||
class MessageTargetClass(targets.BasicTarget):
|
||||
|
||||
def __init__(self, name, project, *args):
|
||||
|
||||
targets.BasicTarget.__init__(self, name, project, [])
|
||||
self.args = args
|
||||
self.built = False
|
||||
|
||||
def construct(self, name, sources, ps):
|
||||
|
||||
if not self.built:
|
||||
for arg in self.args:
|
||||
if type(arg) == type([]):
|
||||
arg = " ".join(arg)
|
||||
print arg
|
||||
self.built = True
|
||||
|
||||
return (property_set.empty(), [])
|
||||
|
||||
def message(name, *args):
|
||||
|
||||
if type(name) == type([]):
|
||||
name = name[0]
|
||||
|
||||
t = get_manager().targets()
|
||||
|
||||
project = get_manager().projects().current()
|
||||
|
||||
return t.main_target_alternative(MessageTargetClass(*((name, project) + args)))
|
||||
|
||||
get_manager().projects().add_rule("message", message)
|
||||
51
v2/tools/notfile.py
Normal file
51
v2/tools/notfile.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Status: ported.
|
||||
# Base revision: 64429.
|
||||
#
|
||||
# Copyright (c) 2005-2010 Vladimir Prus.
|
||||
#
|
||||
# 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)
|
||||
|
||||
|
||||
import b2.build.type as type
|
||||
import b2.build.generators as generators
|
||||
import b2.build.virtual_target as virtual_target
|
||||
import b2.build.toolset as toolset
|
||||
import b2.build.targets as targets
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util import bjam_signature
|
||||
|
||||
type.register("NOTFILE_MAIN")
|
||||
|
||||
class NotfileGenerator(generators.Generator):
|
||||
|
||||
def run(self, project, name, ps, sources):
|
||||
pass
|
||||
action_name = ps.get('action')[0]
|
||||
if action_name[0] == '@':
|
||||
action = virtual_target.Action(get_manager(), sources, action_name[1:], ps)
|
||||
else:
|
||||
action = virtual_target.Action(get_manager(), sources, "notfile.run", ps)
|
||||
|
||||
return [get_manager().virtual_targets().register(
|
||||
virtual_target.NotFileTarget(name, project, action))]
|
||||
|
||||
generators.register(NotfileGenerator("notfile.main", False, [], ["NOTFILE_MAIN"]))
|
||||
|
||||
toolset.flags("notfile.run", "ACTION", [], ["<action>"])
|
||||
|
||||
get_manager().engine().register_action("notfile.run", "$(ACTION)")
|
||||
|
||||
@bjam_signature((["target_name"], ["action"], ["sources", "*"], ["requirements", "*"],
|
||||
["default_build", "*"]))
|
||||
def notfile(target_name, action, sources, requirements, default_build):
|
||||
|
||||
requirements.append("<action>" + action)
|
||||
|
||||
return targets.create_typed_metatarget(target_name, "NOTFILE_MAIN", sources, requirements,
|
||||
default_build, [])
|
||||
|
||||
|
||||
get_manager().projects().add_rule("notfile", notfile)
|
||||
168
v2/tools/package.py
Normal file
168
v2/tools/package.py
Normal file
@@ -0,0 +1,168 @@
|
||||
# Status: ported
|
||||
# Base revision: 64488
|
||||
#
|
||||
# Copyright (c) 2005, 2010 Vladimir Prus.
|
||||
# Copyright 2006 Rene Rivera.
|
||||
#
|
||||
# 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)
|
||||
|
||||
# Provides mechanism for installing whole packages into a specific directory
|
||||
# structure. This is opposed to the 'install' rule, that installs a number of
|
||||
# targets to a single directory, and does not care about directory structure at
|
||||
# all.
|
||||
|
||||
# Example usage:
|
||||
#
|
||||
# package.install boost : <properties>
|
||||
# : <binaries>
|
||||
# : <libraries>
|
||||
# : <headers>
|
||||
# ;
|
||||
#
|
||||
# This will install binaries, libraries and headers to the 'proper' location,
|
||||
# given by command line options --prefix, --exec-prefix, --bindir, --libdir and
|
||||
# --includedir.
|
||||
#
|
||||
# The rule is just a convenient wrapper, avoiding the need to define several
|
||||
# 'install' targets.
|
||||
#
|
||||
# The only install-related feature is <install-source-root>. It will apply to
|
||||
# headers only and if present, paths of headers relatively to source root will
|
||||
# be retained after installing. If it is not specified, then "." is assumed, so
|
||||
# relative paths in headers are always preserved.
|
||||
|
||||
import b2.build.feature as feature
|
||||
import b2.build.property as property
|
||||
import b2.util.option as option
|
||||
import b2.tools.stage as stage
|
||||
|
||||
from b2.build.alias import alias
|
||||
|
||||
from b2.manager import get_manager
|
||||
|
||||
from b2.util import bjam_signature
|
||||
from b2.util.utility import ungrist
|
||||
|
||||
|
||||
import os
|
||||
|
||||
feature.feature("install-default-prefix", [], ["free", "incidental"])
|
||||
|
||||
@bjam_signature((["name", "package_name", "?"], ["requirements", "*"],
|
||||
["binaries", "*"], ["libraries", "*"], ["headers", "*"]))
|
||||
def install(name, package_name=None, requirements=[], binaries=[], libraries=[], headers=[]):
|
||||
|
||||
requirements = requirements[:]
|
||||
binaries = binaries[:]
|
||||
libraries
|
||||
|
||||
if not package_name:
|
||||
package_name = name
|
||||
|
||||
if option.get("prefix"):
|
||||
# If --prefix is explicitly specified on the command line,
|
||||
# then we need wipe away any settings of libdir/includir that
|
||||
# is specified via options in config files.
|
||||
option.set("bindir", None)
|
||||
option.set("libdir", None)
|
||||
option.set("includedir", None)
|
||||
|
||||
# If <install-source-root> is not specified, all headers are installed to
|
||||
# prefix/include, no matter what their relative path is. Sometimes that is
|
||||
# what is needed.
|
||||
install_source_root = property.select('install-source-root', requirements)
|
||||
if install_source_root:
|
||||
requirements = property.change(requirements, 'install-source-root', None)
|
||||
|
||||
install_header_subdir = property.select('install-header-subdir', requirements)
|
||||
if install_header_subdir:
|
||||
install_header_subdir = ungrist(install_header_subdir[0])
|
||||
requirements = property.change(requirements, 'install-header-subdir', None)
|
||||
|
||||
# First, figure out all locations. Use the default if no prefix option
|
||||
# given.
|
||||
prefix = get_prefix(name, requirements)
|
||||
|
||||
# Architecture dependent files.
|
||||
exec_locate = option.get("exec-prefix", prefix)
|
||||
|
||||
# Binaries.
|
||||
bin_locate = option.get("bindir", os.path.join(prefix, "bin"))
|
||||
|
||||
# Object code libraries.
|
||||
lib_locate = option.get("libdir", os.path.join(prefix, "lib"))
|
||||
|
||||
# Source header files.
|
||||
include_locate = option.get("includedir", os.path.join(prefix, "include"))
|
||||
|
||||
stage.install(name + "-bin", binaries, requirements + ["<location>" + bin_locate])
|
||||
|
||||
alias(name + "-lib", [name + "-lib-shared", name + "-lib-static"])
|
||||
|
||||
# Since the install location of shared libraries differs on universe
|
||||
# and cygwin, use target alternatives to make different targets.
|
||||
# We should have used indirection conditioanl requirements, but it's
|
||||
# awkward to pass bin-locate and lib-locate from there to another rule.
|
||||
alias(name + "-lib-shared", [name + "-lib-shared-universe"])
|
||||
alias(name + "-lib-shared", [name + "-lib-shared-cygwin"], ["<target-os>cygwin"])
|
||||
|
||||
# For shared libraries, we install both explicitly specified one and the
|
||||
# shared libraries that the installed executables depend on.
|
||||
stage.install(name + "-lib-shared-universe", binaries + libraries,
|
||||
requirements + ["<location>" + lib_locate, "<install-dependencies>on",
|
||||
"<install-type>SHARED_LIB"])
|
||||
stage.install(name + "-lib-shared-cygwin", binaries + libraries,
|
||||
requirements + ["<location>" + bin_locate, "<install-dependencies>on",
|
||||
"<install-type>SHARED_LIB"])
|
||||
|
||||
# For static libraries, we do not care about executable dependencies, since
|
||||
# static libraries are already incorporated into them.
|
||||
stage.install(name + "-lib-static", libraries, requirements +
|
||||
["<location>" + lib_locate, "<install-dependencies>on", "<install-type>STATIC_LIB"])
|
||||
stage.install(name + "-headers", headers, requirements \
|
||||
+ ["<location>" + os.path.join(include_locate, s) for s in install_header_subdir]
|
||||
+ install_source_root)
|
||||
|
||||
alias(name, [name + "-bin", name + "-lib", name + "-headers"])
|
||||
|
||||
pt = get_manager().projects().current()
|
||||
|
||||
for subname in ["bin", "lib", "headers", "lib-shared", "lib-static", "lib-shared-universe", "lib-shared-cygwin"]:
|
||||
pt.mark_targets_as_explicit([name + "-" + subname])
|
||||
|
||||
@bjam_signature((["target_name"], ["package_name"], ["data", "*"], ["requirements", "*"]))
|
||||
def install_data(target_name, package_name, data, requirements):
|
||||
if not package_name:
|
||||
package_name = target_name
|
||||
|
||||
if option.get("prefix"):
|
||||
# If --prefix is explicitly specified on the command line,
|
||||
# then we need wipe away any settings of datarootdir
|
||||
option.set("datarootdir", None)
|
||||
|
||||
prefix = get_prefix(package_name, requirements)
|
||||
datadir = option.get("datarootdir", os.path.join(prefix, "share"))
|
||||
|
||||
stage.install(target_name, data,
|
||||
requirements + ["<location>" + os.path.join(datadir, package_name)])
|
||||
|
||||
get_manager().projects().current().mark_targets_as_explicit([target_name])
|
||||
|
||||
def get_prefix(package_name, requirements):
|
||||
|
||||
specified = property.select("install-default-prefix", requirements)
|
||||
if specified:
|
||||
specified = ungrist(specified[0])
|
||||
prefix = option.get("prefix", specified)
|
||||
requirements = property.change(requirements, "install-default-prefix", None)
|
||||
# Or some likely defaults if neither is given.
|
||||
if not prefix:
|
||||
if os.name == "nt":
|
||||
prefix = "C:\\" + package_name
|
||||
elif os.name == "posix":
|
||||
prefix = "/usr/local"
|
||||
|
||||
return prefix
|
||||
|
||||
350
v2/tools/stage.py
Normal file
350
v2/tools/stage.py
Normal file
@@ -0,0 +1,350 @@
|
||||
# Status: ported.
|
||||
# Base revision 64444.
|
||||
#
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2005, 2006 Rene Rivera
|
||||
# Copyright 2002, 2003, 2004, 2005, 2006, 2010 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 module defines the 'install' rule, used to copy a set of targets to a
|
||||
# single location.
|
||||
|
||||
import b2.build.feature as feature
|
||||
import b2.build.targets as targets
|
||||
import b2.build.property as property
|
||||
import b2.build.property_set as property_set
|
||||
import b2.build.generators as generators
|
||||
import b2.build.virtual_target as virtual_target
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util.sequence import unique
|
||||
from b2.util import bjam_signature
|
||||
|
||||
import b2.build.type
|
||||
|
||||
import os.path
|
||||
import re
|
||||
import types
|
||||
|
||||
feature.feature('install-dependencies', ['off', 'on'], ['incidental'])
|
||||
feature.feature('install-type', [], ['free', 'incidental'])
|
||||
feature.feature('install-source-root', [], ['free', 'path'])
|
||||
feature.feature('so-version', [], ['free', 'incidental'])
|
||||
|
||||
# If 'on', version symlinks for shared libraries will not be created. Affects
|
||||
# Unix builds only.
|
||||
feature.feature('install-no-version-symlinks', ['on'], ['optional', 'incidental'])
|
||||
|
||||
class InstallTargetClass(targets.BasicTarget):
|
||||
|
||||
def update_location(self, ps):
|
||||
"""If <location> is not set, sets it based on the project data."""
|
||||
|
||||
loc = ps.get('location')
|
||||
if not loc:
|
||||
loc = os.path.join(self.project().get('location'), self.name())
|
||||
ps = ps.add_raw(["<location>" + loc])
|
||||
|
||||
return ps
|
||||
|
||||
def adjust_properties(self, target, build_ps):
|
||||
a = target.action()
|
||||
properties = []
|
||||
if a:
|
||||
ps = a.properties()
|
||||
properties = ps.all()
|
||||
|
||||
# Unless <hardcode-dll-paths>true is in properties, which can happen
|
||||
# only if the user has explicitly requested it, nuke all <dll-path>
|
||||
# properties.
|
||||
|
||||
if build_ps.get('hardcode-dll-paths') != ['true']:
|
||||
properties = [p for p in properties if p.feature().name() != 'dll-path']
|
||||
|
||||
# If any <dll-path> properties were specified for installing, add
|
||||
# them.
|
||||
properties.extend(build_ps.get_properties('dll-path'))
|
||||
|
||||
# Also copy <linkflags> feature from current build set, to be used
|
||||
# for relinking.
|
||||
properties.extend(build_ps.get_properties('linkflags'))
|
||||
|
||||
# Remove the <tag> feature on original targets.
|
||||
# And <location>. If stage target has another stage target in
|
||||
# sources, then we shall get virtual targets with the <location>
|
||||
# property set.
|
||||
properties = [p for p in properties
|
||||
if not p.feature().name() in ['tag', 'location']]
|
||||
|
||||
properties.extend(build_ps.get_properties('dependency'))
|
||||
|
||||
properties.extend(build_ps.get_properties('location'))
|
||||
|
||||
|
||||
properties.extend(build_ps.get_properties('install-no-version-symlinks'))
|
||||
|
||||
d = build_ps.get_properties('install-source-root')
|
||||
|
||||
# Make the path absolute: we shall use it to compute relative paths and
|
||||
# making the path absolute will help.
|
||||
if d:
|
||||
p = d[0]
|
||||
properties.append(property.Property(p.feature(), os.path.abspath(p.value())))
|
||||
|
||||
return property_set.create(properties)
|
||||
|
||||
|
||||
def construct(self, name, source_targets, ps):
|
||||
|
||||
source_targets = self.targets_to_stage(source_targets, ps)
|
||||
ps = self.update_location(ps)
|
||||
|
||||
ename = ps.get('name')
|
||||
if ename:
|
||||
ename = ename[0]
|
||||
if ename and len(source_targets) > 1:
|
||||
get_manager().errors()("When <name> property is used in 'install', only one source is allowed")
|
||||
|
||||
result = []
|
||||
|
||||
for i in source_targets:
|
||||
|
||||
staged_targets = []
|
||||
new_ps = self.adjust_properties(i, ps)
|
||||
|
||||
# See if something special should be done when staging this type. It
|
||||
# is indicated by the presence of a special "INSTALLED_" type.
|
||||
t = i.type()
|
||||
if t and b2.build.type.registered("INSTALLED_" + t):
|
||||
|
||||
if ename:
|
||||
get_manager().errors()("In 'install': <name> property specified with target that requires relinking.")
|
||||
else:
|
||||
(r, targets) = generators.construct(self.project(), name, "INSTALLED_" + t,
|
||||
new_ps, [i])
|
||||
assert isinstance(r, property_set.PropertySet)
|
||||
staged_targets.extend(targets)
|
||||
|
||||
else:
|
||||
staged_targets.append(copy_file(self.project(), ename, i, new_ps))
|
||||
|
||||
if not staged_targets:
|
||||
get_manager().errors()("Unable to generate staged version of " + i)
|
||||
|
||||
result.extend(get_manager().virtual_targets().register(t) for t in staged_targets)
|
||||
|
||||
return (property_set.empty(), result)
|
||||
|
||||
def targets_to_stage(self, source_targets, ps):
|
||||
"""Given the list of source targets explicitly passed to 'stage', returns the
|
||||
list of targets which must be staged."""
|
||||
|
||||
result = []
|
||||
|
||||
# Traverse the dependencies, if needed.
|
||||
if ps.get('install-dependencies') == ['on']:
|
||||
source_targets = self.collect_targets(source_targets)
|
||||
|
||||
# Filter the target types, if needed.
|
||||
included_types = ps.get('install-type')
|
||||
for r in source_targets:
|
||||
ty = r.type()
|
||||
if ty:
|
||||
# Do not stage searched libs.
|
||||
if ty != "SEARCHED_LIB":
|
||||
if included_types:
|
||||
if self.include_type(ty, included_types):
|
||||
result.append(r)
|
||||
else:
|
||||
result.append(r)
|
||||
elif not included_types:
|
||||
# Don't install typeless target if there is an explicit list of
|
||||
# allowed types.
|
||||
result.append(r)
|
||||
|
||||
return result
|
||||
|
||||
# CONSIDER: figure out why we can not use virtual-target.traverse here.
|
||||
#
|
||||
def collect_targets(self, targets):
|
||||
|
||||
s = [t.creating_subvariant() for t in targets]
|
||||
s = unique(s)
|
||||
|
||||
result = set(targets)
|
||||
for i in s:
|
||||
i.all_referenced_targets(result)
|
||||
|
||||
result2 = []
|
||||
for r in result:
|
||||
if isinstance(r, property.Property):
|
||||
|
||||
if r.feature().name() != 'use':
|
||||
result2.append(r.value())
|
||||
else:
|
||||
result2.append(r)
|
||||
result2 = unique(result2)
|
||||
return result2
|
||||
|
||||
# Returns true iff 'type' is subtype of some element of 'types-to-include'.
|
||||
#
|
||||
def include_type(self, type, types_to_include):
|
||||
return any(b2.build.type.is_subtype(type, ti) for ti in types_to_include)
|
||||
|
||||
# Creates a copy of target 'source'. The 'properties' object should have a
|
||||
# <location> property which specifies where the target must be placed.
|
||||
#
|
||||
def copy_file(project, name, source, ps):
|
||||
|
||||
if not name:
|
||||
name = source.name()
|
||||
|
||||
relative = ""
|
||||
|
||||
new_a = virtual_target.NonScanningAction([source], "common.copy", ps)
|
||||
source_root = ps.get('install-source-root')
|
||||
if source_root:
|
||||
source_root = source_root[0]
|
||||
# Get the real path of the target. We probably need to strip relative
|
||||
# path from the target name at construction.
|
||||
path = os.path.join(source.path(), os.path.dirname(name))
|
||||
# Make the path absolute. Otherwise, it would be hard to compute the
|
||||
# relative path. The 'source-root' is already absolute, see the
|
||||
# 'adjust-properties' method above.
|
||||
path = os.path.abspath(path)
|
||||
|
||||
relative = os.path.relpath(path, source_root)
|
||||
|
||||
name = os.path.join(relative, os.path.basename(name))
|
||||
return virtual_target.FileTarget(name, source.type(), project, new_a, exact=True)
|
||||
|
||||
def symlink(name, project, source, ps):
|
||||
a = virtual_target.Action([source], "symlink.ln", ps)
|
||||
return virtual_target.FileTarget(name, source.type(), project, a, exact=True)
|
||||
|
||||
def relink_file(project, source, ps):
|
||||
action = source.action()
|
||||
cloned_action = virtual_target.clone_action(action, project, "", ps)
|
||||
targets = cloned_action.targets()
|
||||
# We relink only on Unix, where exe or shared lib is always a single file.
|
||||
assert len(targets) == 1
|
||||
return targets[0]
|
||||
|
||||
|
||||
# Declare installed version of the EXE type. Generator for this type will cause
|
||||
# relinking to the new location.
|
||||
b2.build.type.register('INSTALLED_EXE', [], 'EXE')
|
||||
|
||||
class InstalledExeGenerator(generators.Generator):
|
||||
|
||||
def __init__(self):
|
||||
generators.Generator.__init__(self, "install-exe", False, ['EXE'], ['INSTALLED_EXE'])
|
||||
|
||||
def run(self, project, name, ps, source):
|
||||
|
||||
need_relink = False;
|
||||
|
||||
if ps.get('os') in ['NT', 'CYGWIN'] or ps.get('target-os') in ['windows', 'cygwin']:
|
||||
# Never relink
|
||||
pass
|
||||
else:
|
||||
# See if the dll-path properties are not changed during
|
||||
# install. If so, copy, don't relink.
|
||||
need_relink = ps.get('dll-path') != source[0].action().properties().get('dll-path')
|
||||
|
||||
if need_relink:
|
||||
return [relink_file(project, source, ps)]
|
||||
else:
|
||||
return [copy_file(project, None, source[0], ps)]
|
||||
|
||||
generators.register(InstalledExeGenerator())
|
||||
|
||||
|
||||
# Installing a shared link on Unix might cause a creation of versioned symbolic
|
||||
# links.
|
||||
b2.build.type.register('INSTALLED_SHARED_LIB', [], 'SHARED_LIB')
|
||||
|
||||
class InstalledSharedLibGenerator(generators.Generator):
|
||||
|
||||
def __init__(self):
|
||||
generators.Generator.__init__(self, 'install-shared-lib', False, ['SHARED_LIB'], ['INSTALLED_SHARED_LIB'])
|
||||
|
||||
def run(self, project, name, ps, source):
|
||||
|
||||
source = source[0]
|
||||
if ps.get('os') in ['NT', 'CYGWIN'] or ps.get('target-os') in ['windows', 'cygwin']:
|
||||
copied = copy_file(project, None, source, ps)
|
||||
return [get_manager().virtual_targets().register(copied)]
|
||||
else:
|
||||
a = source.action()
|
||||
if not a:
|
||||
# Non-derived file, just copy.
|
||||
copied = copy_file(project, source, ps)
|
||||
else:
|
||||
|
||||
need_relink = ps.get('dll-path') != source.action().properties().get('dll-path')
|
||||
|
||||
if need_relink:
|
||||
# Rpath changed, need to relink.
|
||||
copied = relink_file(project, source, ps)
|
||||
else:
|
||||
copied = copy_file(project, None, source, ps)
|
||||
|
||||
result = [get_manager().virtual_targets().register(copied)]
|
||||
# If the name is in the form NNN.XXX.YYY.ZZZ, where all 'X', 'Y' and
|
||||
# 'Z' are numbers, we need to create NNN.XXX and NNN.XXX.YYY
|
||||
# symbolic links.
|
||||
m = re.match("(.*)\\.([0123456789]+)\\.([0123456789]+)\\.([0123456789]+)$",
|
||||
copied.name());
|
||||
if m:
|
||||
# Symlink without version at all is used to make
|
||||
# -lsome_library work.
|
||||
result.append(symlink(m.group(1), project, copied, ps))
|
||||
|
||||
# Symlinks of some libfoo.N and libfoo.N.M are used so that
|
||||
# library can found at runtime, if libfoo.N.M.X has soname of
|
||||
# libfoo.N. That happens when the library makes some binary
|
||||
# compatibility guarantees. If not, it is possible to skip those
|
||||
# symlinks.
|
||||
if ps.get('install-no-version-symlinks') != ['on']:
|
||||
|
||||
result.append(symlink(m.group(1) + '.' + m.group(2), project, copied, ps))
|
||||
result.append(symlink(m.group(1) + '.' + m.group(2) + '.' + m.group(3),
|
||||
project, copied, ps))
|
||||
|
||||
return result
|
||||
|
||||
generators.register(InstalledSharedLibGenerator())
|
||||
|
||||
|
||||
# Main target rule for 'install'.
|
||||
#
|
||||
@bjam_signature((["name"], ["sources", "*"], ["requirements", "*"],
|
||||
["default_build", "*"], ["usage_requirements", "*"]))
|
||||
def install(name, sources, requirements=[], default_build=[], usage_requirements=[]):
|
||||
|
||||
requirements = requirements[:]
|
||||
# Unless the user has explicitly asked us to hardcode dll paths, add
|
||||
# <hardcode-dll-paths>false in requirements, to override default value.
|
||||
if not '<hardcode-dll-paths>true' in requirements:
|
||||
requirements.append('<hardcode-dll-paths>false')
|
||||
|
||||
if any(r.startswith('<tag>') for r in requirements):
|
||||
get_manager().errors()("The <tag> property is not allowed for the 'install' rule")
|
||||
|
||||
from b2.manager import get_manager
|
||||
t = get_manager().targets()
|
||||
|
||||
project = get_manager().projects().current()
|
||||
|
||||
return t.main_target_alternative(
|
||||
InstallTargetClass(name, project,
|
||||
t.main_target_sources(sources, name),
|
||||
t.main_target_requirements(requirements, project),
|
||||
t.main_target_default_build(default_build, project),
|
||||
t.main_target_usage_requirements(usage_requirements, project)))
|
||||
|
||||
get_manager().projects().add_rule("install", install)
|
||||
get_manager().projects().add_rule("stage", install)
|
||||
|
||||
112
v2/tools/symlink.py
Normal file
112
v2/tools/symlink.py
Normal file
@@ -0,0 +1,112 @@
|
||||
# Status: ported.
|
||||
# Base revision: 64488.
|
||||
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# Copyright 2002, 2003 Rene Rivera
|
||||
# Copyright 2002, 2003, 2004, 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)
|
||||
|
||||
# Defines the "symlink" special target. 'symlink' targets make symbolic links
|
||||
# to the sources.
|
||||
|
||||
import b2.build.feature as feature
|
||||
import b2.build.targets as targets
|
||||
import b2.build.property_set as property_set
|
||||
import b2.build.virtual_target as virtual_target
|
||||
import b2.build.targets
|
||||
|
||||
from b2.manager import get_manager
|
||||
|
||||
import bjam
|
||||
|
||||
import os
|
||||
|
||||
|
||||
feature.feature("symlink-location", ["project-relative", "build-relative"], ["incidental"])
|
||||
|
||||
class SymlinkTarget(targets.BasicTarget):
|
||||
|
||||
_count = 0
|
||||
|
||||
def __init__(self, project, targets, sources):
|
||||
|
||||
# Generate a fake name for now. Need unnamed targets eventually.
|
||||
fake_name = "symlink#%s" % SymlinkTarget._count
|
||||
SymlinkTarget._count = SymlinkTarget._count + 1
|
||||
|
||||
b2.build.targets.BasicTarget.__init__(self, fake_name, project, sources)
|
||||
|
||||
# Remember the targets to map the sources onto. Pad or truncate
|
||||
# to fit the sources given.
|
||||
assert len(targets) <= len(sources)
|
||||
self.targets = targets[:] + sources[len(targets):]
|
||||
|
||||
# The virtual targets corresponding to the given targets.
|
||||
self.virtual_targets = []
|
||||
|
||||
def construct(self, name, source_targets, ps):
|
||||
i = 0
|
||||
for t in source_targets:
|
||||
s = self.targets[i]
|
||||
a = virtual_target.Action(self.manager(), [t], "symlink.ln", ps)
|
||||
vt = virtual_target.FileTarget(os.path.basename(s), t.type(), self.project(), a)
|
||||
|
||||
# Place the symlink in the directory relative to the project
|
||||
# location, instead of placing it in the build directory.
|
||||
if not ps.get('symlink-location') == "project-relative":
|
||||
vt.set_path(os.path.join(self.project().get('location'), os.path.dirname(s)))
|
||||
|
||||
vt = get_manager().virtual_targets().register(vt)
|
||||
self.virtual_targets.append(vt)
|
||||
i = i + 1
|
||||
|
||||
return (property_set.empty(), self.virtual_targets)
|
||||
|
||||
# Creates a symbolic link from a set of targets to a set of sources.
|
||||
# The targets and sources map one to one. The symlinks generated are
|
||||
# limited to be the ones given as the sources. That is, the targets
|
||||
# are either padded or trimmed to equate to the sources. The padding
|
||||
# is done with the name of the corresponding source. For example::
|
||||
#
|
||||
# symlink : one two ;
|
||||
#
|
||||
# Is equal to::
|
||||
#
|
||||
# symlink one two : one two ;
|
||||
#
|
||||
# Names for symlink are relative to the project location. They cannot
|
||||
# include ".." path components.
|
||||
def symlink(targets, sources):
|
||||
|
||||
from b2.manager import get_manager
|
||||
t = get_manager().targets()
|
||||
p = get_manager().projects().current()
|
||||
|
||||
return t.main_target_alternative(
|
||||
SymlinkTarget(p, targets,
|
||||
# Note: inline targets are not supported for symlink, intentionally,
|
||||
# since it's used to linking existing non-local targets.
|
||||
sources))
|
||||
|
||||
|
||||
def setup_ln(targets, sources, ps):
|
||||
|
||||
source_path = bjam.call("get-target-variable", sources[0], "LOCATE")[0]
|
||||
target_path = bjam.call("get-target-variable", targets[0], "LOCATE")[0]
|
||||
rel = os.path.relpath(source_path, target_path)
|
||||
if rel == ".":
|
||||
bjam.call("set-target-variable", targets, "PATH_TO_SOURCE", "")
|
||||
else:
|
||||
bjam.call("set-target-variable", targets, "PATH_TO_SOURCE", rel)
|
||||
|
||||
if os.name == 'nt':
|
||||
ln_action = """echo "NT symlinks not supported yet, making copy"
|
||||
del /f /q "$(<)" 2>nul >nul
|
||||
copy "$(>)" "$(<)" $(NULL_OUT)"""
|
||||
else:
|
||||
ln_action = "ln -f -s '$(>:D=:R=$(PATH_TO_SOURCE))' '$(<)'"
|
||||
|
||||
get_manager().engine().register_action("symlink.ln", ln_action, function=setup_ln)
|
||||
|
||||
get_manager().projects().add_rule("symlink", symlink)
|
||||
210
v2/tools/testing-aux.jam
Normal file
210
v2/tools/testing-aux.jam
Normal file
@@ -0,0 +1,210 @@
|
||||
# This module is imported by testing.py. The definitions here are
|
||||
# too tricky to do in Python
|
||||
|
||||
# Causes the 'target' to exist after bjam invocation if and only if all the
|
||||
# dependencies were successfully built.
|
||||
#
|
||||
rule expect-success ( target : dependency + : requirements * )
|
||||
{
|
||||
**passed** $(target) : $(sources) ;
|
||||
}
|
||||
IMPORT testing : expect-success : : testing.expect-success ;
|
||||
|
||||
# Causes the 'target' to exist after bjam invocation if and only if all some of
|
||||
# the dependencies were not successfully built.
|
||||
#
|
||||
rule expect-failure ( target : dependency + : properties * )
|
||||
{
|
||||
local grist = [ MATCH ^<(.*)> : $(dependency:G) ] ;
|
||||
local marker = $(dependency:G=$(grist)*fail) ;
|
||||
(failed-as-expected) $(marker) ;
|
||||
FAIL_EXPECTED $(dependency) ;
|
||||
LOCATE on $(marker) = [ on $(dependency) return $(LOCATE) ] ;
|
||||
RMOLD $(marker) ;
|
||||
DEPENDS $(marker) : $(dependency) ;
|
||||
DEPENDS $(target) : $(marker) ;
|
||||
**passed** $(target) : $(marker) ;
|
||||
}
|
||||
IMPORT testing : expect-failure : : testing.expect-failure ;
|
||||
|
||||
# The rule/action combination used to report successful passing of a test.
|
||||
#
|
||||
rule **passed**
|
||||
{
|
||||
# Force deletion of the target, in case any dependencies failed to build.
|
||||
RMOLD $(<) ;
|
||||
}
|
||||
|
||||
|
||||
# Used to create test files signifying passed tests.
|
||||
#
|
||||
actions **passed**
|
||||
{
|
||||
echo passed > "$(<)"
|
||||
}
|
||||
|
||||
|
||||
# Used to create replacement object files that do not get created during tests
|
||||
# that are expected to fail.
|
||||
#
|
||||
actions (failed-as-expected)
|
||||
{
|
||||
echo failed as expected > "$(<)"
|
||||
}
|
||||
|
||||
# Runs executable 'sources' and stores stdout in file 'target'. Unless
|
||||
# --preserve-test-targets command line option has been specified, removes the
|
||||
# executable. The 'target-to-remove' parameter controls what should be removed:
|
||||
# - if 'none', does not remove anything, ever
|
||||
# - if empty, removes 'source'
|
||||
# - if non-empty and not 'none', contains a list of sources to remove.
|
||||
#
|
||||
rule capture-output ( target : source : properties * : targets-to-remove * )
|
||||
{
|
||||
output-file on $(target) = $(target:S=.output) ;
|
||||
LOCATE on $(target:S=.output) = [ on $(target) return $(LOCATE) ] ;
|
||||
|
||||
# The INCLUDES kill a warning about independent target...
|
||||
INCLUDES $(target) : $(target:S=.output) ;
|
||||
# but it also puts .output into dependency graph, so we must tell jam it is
|
||||
# OK if it cannot find the target or updating rule.
|
||||
NOCARE $(target:S=.output) ;
|
||||
|
||||
# This has two-fold effect. First it adds input files to the dependendency
|
||||
# graph, preventing a warning. Second, it causes input files to be bound
|
||||
# before target is created. Therefore, they are bound using SEARCH setting
|
||||
# on them and not LOCATE setting of $(target), as in other case (due to jam
|
||||
# bug).
|
||||
DEPENDS $(target) : [ on $(target) return $(INPUT_FILES) ] ;
|
||||
|
||||
if $(targets-to-remove) = none
|
||||
{
|
||||
targets-to-remove = ;
|
||||
}
|
||||
else if ! $(targets-to-remove)
|
||||
{
|
||||
targets-to-remove = $(source) ;
|
||||
}
|
||||
|
||||
if [ on $(target) return $(REMOVE_TEST_TARGETS) ]
|
||||
{
|
||||
TEMPORARY $(targets-to-remove) ;
|
||||
# Set a second action on target that will be executed after capture
|
||||
# output action. The 'RmTemps' rule has the 'ignore' modifier so it is
|
||||
# always considered succeeded. This is needed for 'run-fail' test. For
|
||||
# that test the target will be marked with FAIL_EXPECTED, and without
|
||||
# 'ignore' successful execution will be negated and be reported as
|
||||
# failure. With 'ignore' we do not detect a case where removing files
|
||||
# fails, but it is not likely to happen.
|
||||
RmTemps $(target) : $(targets-to-remove) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
.STATUS = %status% ;
|
||||
.SET_STATUS = "set status=%ERRORLEVEL%" ;
|
||||
.RUN_OUTPUT_NL = "echo." ;
|
||||
.STATUS_0 = "%status% EQU 0 (" ;
|
||||
.STATUS_NOT_0 = "%status% NEQ 0 (" ;
|
||||
.VERBOSE = "%verbose% EQU 1 (" ;
|
||||
.ENDIF = ")" ;
|
||||
.SHELL_SET = "set " ;
|
||||
.CATENATE = type ;
|
||||
.CP = copy ;
|
||||
}
|
||||
else
|
||||
{
|
||||
.STATUS = "$status" ;
|
||||
.SET_STATUS = "status=$?" ;
|
||||
.RUN_OUTPUT_NL = "echo" ;
|
||||
.STATUS_0 = "test $status -eq 0 ; then" ;
|
||||
.STATUS_NOT_0 = "test $status -ne 0 ; then" ;
|
||||
.VERBOSE = "test $verbose -eq 1 ; then" ;
|
||||
.ENDIF = "fi" ;
|
||||
.SHELL_SET = "" ;
|
||||
.CATENATE = cat ;
|
||||
.CP = cp ;
|
||||
}
|
||||
|
||||
|
||||
.VERBOSE_TEST = 0 ;
|
||||
if --verbose-test in [ modules.peek : ARGV ]
|
||||
{
|
||||
.VERBOSE_TEST = 1 ;
|
||||
}
|
||||
|
||||
|
||||
.RM = [ common.rm-command ] ;
|
||||
|
||||
|
||||
actions capture-output bind INPUT_FILES output-file
|
||||
{
|
||||
$(PATH_SETUP)
|
||||
$(LAUNCHER) "$(>)" $(ARGS) "$(INPUT_FILES)" > "$(output-file)" 2>&1
|
||||
$(.SET_STATUS)
|
||||
$(.RUN_OUTPUT_NL) >> "$(output-file)"
|
||||
echo EXIT STATUS: $(.STATUS) >> "$(output-file)"
|
||||
if $(.STATUS_0)
|
||||
$(.CP) "$(output-file)" "$(<)"
|
||||
$(.ENDIF)
|
||||
$(.SHELL_SET)verbose=$(.VERBOSE_TEST)
|
||||
if $(.STATUS_NOT_0)
|
||||
$(.SHELL_SET)verbose=1
|
||||
$(.ENDIF)
|
||||
if $(.VERBOSE)
|
||||
echo ====== BEGIN OUTPUT ======
|
||||
$(.CATENATE) "$(output-file)"
|
||||
echo ====== END OUTPUT ======
|
||||
$(.ENDIF)
|
||||
exit $(.STATUS)
|
||||
}
|
||||
|
||||
IMPORT testing : capture-output : : testing.capture-output ;
|
||||
|
||||
|
||||
actions quietly updated ignore piecemeal together RmTemps
|
||||
{
|
||||
$(.RM) "$(>)"
|
||||
}
|
||||
|
||||
|
||||
.MAKE_FILE = [ common.file-creation-command ] ;
|
||||
|
||||
actions unit-test
|
||||
{
|
||||
$(PATH_SETUP)
|
||||
$(LAUNCHER) $(>) $(ARGS) && $(.MAKE_FILE) $(<)
|
||||
}
|
||||
|
||||
rule record-time ( target : source : start end user system )
|
||||
{
|
||||
local src-string = [$(source:G=:J=",")"] " ;
|
||||
USER_TIME on $(target) += $(src-string)$(user) ;
|
||||
SYSTEM_TIME on $(target) += $(src-string)$(system) ;
|
||||
}
|
||||
|
||||
# Calling this rule requests that Boost Build time how long it taks to build the
|
||||
# 'source' target and display the results both on the standard output and in the
|
||||
# 'target' file.
|
||||
#
|
||||
rule time ( target : source : properties * )
|
||||
{
|
||||
# Set up rule for recording timing information.
|
||||
__TIMING_RULE__ on $(source) = testing.record-time $(target) ;
|
||||
|
||||
# Make sure that the source is rebuilt any time we need to retrieve that
|
||||
# information.
|
||||
REBUILDS $(target) : $(source) ;
|
||||
}
|
||||
|
||||
|
||||
actions time
|
||||
{
|
||||
echo user: $(USER_TIME)
|
||||
echo system: $(SYSTEM_TIME)
|
||||
|
||||
echo user: $(USER_TIME)" seconds" > "$(<)"
|
||||
echo system: $(SYSTEM_TIME)" seconds" >> "$(<)"
|
||||
}
|
||||
342
v2/tools/testing.py
Normal file
342
v2/tools/testing.py
Normal file
@@ -0,0 +1,342 @@
|
||||
# Status: ported, except for --out-xml
|
||||
# Base revision: 64488
|
||||
#
|
||||
# Copyright 2005 Dave Abrahams
|
||||
# Copyright 2002, 2003, 2004, 2005, 2010 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 module implements regression testing framework. It declares a number of
|
||||
# main target rules which perform some action and, if the results are OK,
|
||||
# creates an output file.
|
||||
#
|
||||
# The exact list of rules is:
|
||||
# 'compile' -- creates .test file if compilation of sources was
|
||||
# successful.
|
||||
# 'compile-fail' -- creates .test file if compilation of sources failed.
|
||||
# 'run' -- creates .test file is running of executable produced from
|
||||
# sources was successful. Also leaves behind .output file
|
||||
# with the output from program run.
|
||||
# 'run-fail' -- same as above, but .test file is created if running fails.
|
||||
#
|
||||
# In all cases, presence of .test file is an indication that the test passed.
|
||||
# For more convenient reporting, you might want to use C++ Boost regression
|
||||
# testing utilities (see http://www.boost.org/more/regression.html).
|
||||
#
|
||||
# For historical reason, a 'unit-test' rule is available which has the same
|
||||
# syntax as 'exe' and behaves just like 'run'.
|
||||
|
||||
# Things to do:
|
||||
# - Teach compiler_status handle Jamfile.v2.
|
||||
# Notes:
|
||||
# - <no-warn> is not implemented, since it is Como-specific, and it is not
|
||||
# clear how to implement it
|
||||
# - std::locale-support is not implemented (it is used in one test).
|
||||
|
||||
import b2.build.feature as feature
|
||||
import b2.build.type as type
|
||||
import b2.build.targets as targets
|
||||
import b2.build.generators as generators
|
||||
import b2.build.toolset as toolset
|
||||
import b2.tools.common as common
|
||||
import b2.util.option as option
|
||||
import b2.build_system as build_system
|
||||
|
||||
|
||||
|
||||
from b2.manager import get_manager
|
||||
from b2.util import stem, bjam_signature
|
||||
from b2.util.sequence import unique
|
||||
|
||||
import bjam
|
||||
|
||||
import re
|
||||
import os.path
|
||||
import sys
|
||||
|
||||
def init():
|
||||
pass
|
||||
|
||||
# Feature controling the command used to lanch test programs.
|
||||
feature.feature("testing.launcher", [], ["free", "optional"])
|
||||
|
||||
feature.feature("test-info", [], ["free", "incidental"])
|
||||
feature.feature("testing.arg", [], ["free", "incidental"])
|
||||
feature.feature("testing.input-file", [], ["free", "dependency"])
|
||||
|
||||
feature.feature("preserve-test-targets", ["on", "off"], ["incidental", "propagated"])
|
||||
|
||||
# Register target types.
|
||||
type.register("TEST", ["test"])
|
||||
type.register("COMPILE", [], "TEST")
|
||||
type.register("COMPILE_FAIL", [], "TEST")
|
||||
|
||||
type.register("RUN_OUTPUT", ["run"])
|
||||
type.register("RUN", [], "TEST")
|
||||
type.register("RUN_FAIL", [], "TEST")
|
||||
|
||||
type.register("LINK", [], "TEST")
|
||||
type.register("LINK_FAIL", [], "TEST")
|
||||
type.register("UNIT_TEST", ["passed"], "TEST")
|
||||
|
||||
__all_tests = []
|
||||
|
||||
# Declare the rules which create main targets. While the 'type' module already
|
||||
# creates rules with the same names for us, we need extra convenience: default
|
||||
# name of main target, so write our own versions.
|
||||
|
||||
# Helper rule. Create a test target, using basename of first source if no target
|
||||
# name is explicitly passed. Remembers the created target in a global variable.
|
||||
def make_test(target_type, sources, requirements, target_name=None):
|
||||
|
||||
if not target_name:
|
||||
target_name = stem(os.path.basename(sources[0]))
|
||||
|
||||
# Having periods (".") in the target name is problematic because the typed
|
||||
# generator will strip the suffix and use the bare name for the file
|
||||
# targets. Even though the location-prefix averts problems most times it
|
||||
# does not prevent ambiguity issues when referring to the test targets. For
|
||||
# example when using the XML log output. So we rename the target to remove
|
||||
# the periods, and provide an alias for users.
|
||||
real_name = target_name.replace(".", "~")
|
||||
|
||||
project = get_manager().projects().current()
|
||||
# The <location-prefix> forces the build system for generate paths in the
|
||||
# form '$build_dir/array1.test/gcc/debug'. This is necessary to allow
|
||||
# post-processing tools to work.
|
||||
t = get_manager().targets().create_typed_target(
|
||||
type.type_from_rule_name(target_type), project, real_name, sources,
|
||||
requirements + ["<location-prefix>" + real_name + ".test"], [], [])
|
||||
|
||||
# The alias to the real target, per period replacement above.
|
||||
if real_name != target_name:
|
||||
get_manager().projects().project_rules().all_names_["alias"](
|
||||
target_name, [t])
|
||||
|
||||
# Remember the test (for --dump-tests). A good way would be to collect all
|
||||
# given a project. This has some technical problems: e.g. we can not call
|
||||
# this dump from a Jamfile since projects referred by 'build-project' are
|
||||
# not available until the whole Jamfile has been loaded.
|
||||
__all_tests.append(t)
|
||||
return t
|
||||
|
||||
|
||||
# Note: passing more that one cpp file here is known to fail. Passing a cpp file
|
||||
# and a library target works.
|
||||
#
|
||||
@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"]))
|
||||
def compile(sources, requirements, target_name=None):
|
||||
return make_test("compile", sources, requirements, target_name)
|
||||
|
||||
@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"]))
|
||||
def compile_fail(sources, requirements, target_name=None):
|
||||
return make_test("compile-fail", sources, requirements, target_name)
|
||||
|
||||
@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"]))
|
||||
def link(sources, requirements, target_name=None):
|
||||
return make_test("link", sources, requirements, target_name)
|
||||
|
||||
@bjam_signature((["sources", "*"], ["requirements", "*"], ["target_name", "?"]))
|
||||
def link_fail(sources, requirements, target_name=None):
|
||||
return make_test("link-fail", sources, requirements, target_name)
|
||||
|
||||
def handle_input_files(input_files):
|
||||
if len(input_files) > 1:
|
||||
# Check that sorting made when creating property-set instance will not
|
||||
# change the ordering.
|
||||
if sorted(input_files) != input_files:
|
||||
get_manager().errors()("Names of input files must be sorted alphabetically\n" +
|
||||
"due to internal limitations")
|
||||
return ["<testing.input-file>" + f for f in input_files]
|
||||
|
||||
@bjam_signature((["sources", "*"], ["args", "*"], ["input_files", "*"],
|
||||
["requirements", "*"], ["target_name", "?"],
|
||||
["default_build", "*"]))
|
||||
def run(sources, args, input_files, requirements, target_name=None, default_build=[]):
|
||||
if args:
|
||||
requirements.append("<testing.arg>" + " ".join(args))
|
||||
requirements.extend(handle_input_files(input_files))
|
||||
return make_test("run", sources, requirements, target_name)
|
||||
|
||||
@bjam_signature((["sources", "*"], ["args", "*"], ["input_files", "*"],
|
||||
["requirements", "*"], ["target_name", "?"],
|
||||
["default_build", "*"]))
|
||||
def run_fail(sources, args, input_files, requirements, target_name=None, default_build=[]):
|
||||
if args:
|
||||
requirements.append("<testing.arg>" + " ".join(args))
|
||||
requirements.extend(handle_input_files(input_files))
|
||||
return make_test("run-fail", sources, requirements, target_name)
|
||||
|
||||
# Register all the rules
|
||||
for name in ["compile", "compile-fail", "link", "link-fail", "run", "run-fail"]:
|
||||
get_manager().projects().add_rule(name, getattr(sys.modules[__name__], name.replace("-", "_")))
|
||||
|
||||
# Use 'test-suite' as a synonym for 'alias', for backward compatibility.
|
||||
from b2.build.alias import alias
|
||||
get_manager().projects().add_rule("test-suite", alias)
|
||||
|
||||
# For all main targets in 'project-module', which are typed targets with type
|
||||
# derived from 'TEST', produce some interesting information.
|
||||
#
|
||||
def dump_tests():
|
||||
for t in __all_tests:
|
||||
dump_test(t)
|
||||
|
||||
# Given a project location in normalized form (slashes are forward), compute the
|
||||
# name of the Boost library.
|
||||
#
|
||||
__ln1 = re.compile("/(tools|libs)/(.*)/(test|example)")
|
||||
__ln2 = re.compile("/(tools|libs)/(.*)$")
|
||||
__ln3 = re.compile("(/status$)")
|
||||
def get_library_name(path):
|
||||
|
||||
path = path.replace("\\", "/")
|
||||
match1 = __ln1.match(path)
|
||||
match2 = __ln2.match(path)
|
||||
match3 = __ln3.match(path)
|
||||
|
||||
if match1:
|
||||
return match1.group(2)
|
||||
elif match2:
|
||||
return match2.group(2)
|
||||
elif match3:
|
||||
return ""
|
||||
elif option.get("dump-tests", False, True):
|
||||
# The 'run' rule and others might be used outside boost. In that case,
|
||||
# just return the path, since the 'library name' makes no sense.
|
||||
return path
|
||||
|
||||
# Was an XML dump requested?
|
||||
__out_xml = option.get("out-xml", False, True)
|
||||
|
||||
# Takes a target (instance of 'basic-target') and prints
|
||||
# - its type
|
||||
# - its name
|
||||
# - comments specified via the <test-info> property
|
||||
# - relative location of all source from the project root.
|
||||
#
|
||||
def dump_test(target):
|
||||
type = target.type()
|
||||
name = target.name()
|
||||
project = target.project()
|
||||
|
||||
project_root = project.get('project-root')
|
||||
library = get_library_name(os.path.abspath(project.get('location')))
|
||||
if library:
|
||||
name = library + "/" + name
|
||||
|
||||
sources = target.sources()
|
||||
source_files = []
|
||||
for s in sources:
|
||||
if isinstance(s, targets.FileReference):
|
||||
location = os.path.abspath(os.path.join(s.location(), s.name()))
|
||||
source_files.append(os.path.relpath(location, os.path.abspath(project_root)))
|
||||
|
||||
target_name = project.get('location') + "//" + target.name() + ".test"
|
||||
|
||||
test_info = target.requirements().get('test-info')
|
||||
test_info = " ".join('"' + ti + '"' for ti in test_info)
|
||||
|
||||
# If the user requested XML output on the command-line, add the test info to
|
||||
# that XML file rather than dumping them to stdout.
|
||||
#if $(.out-xml)
|
||||
#{
|
||||
# local nl = "
|
||||
#" ;
|
||||
# .contents on $(.out-xml) +=
|
||||
# "$(nl) <test type=\"$(type)\" name=\"$(name)\">"
|
||||
# "$(nl) <target><![CDATA[$(target-name)]]></target>"
|
||||
# "$(nl) <info><![CDATA[$(test-info)]]></info>"
|
||||
# "$(nl) <source><![CDATA[$(source-files)]]></source>"
|
||||
# "$(nl) </test>"
|
||||
# ;
|
||||
# }
|
||||
# else
|
||||
|
||||
source_files = " ".join('"' + s + '"' for s in source_files)
|
||||
if test_info:
|
||||
print 'boost-test(%s) "%s" [%s] : %s' % (type, name, test_info, source_files)
|
||||
else:
|
||||
print 'boost-test(%s) "%s" : %s' % (type, name, source_files)
|
||||
|
||||
# Register generators. Depending on target type, either 'expect-success' or
|
||||
# 'expect-failure' rule will be used.
|
||||
generators.register_standard("testing.expect-success", ["OBJ"], ["COMPILE"])
|
||||
generators.register_standard("testing.expect-failure", ["OBJ"], ["COMPILE_FAIL"])
|
||||
generators.register_standard("testing.expect-success", ["RUN_OUTPUT"], ["RUN"])
|
||||
generators.register_standard("testing.expect-failure", ["RUN_OUTPUT"], ["RUN_FAIL"])
|
||||
generators.register_standard("testing.expect-success", ["EXE"], ["LINK"])
|
||||
generators.register_standard("testing.expect-failure", ["EXE"], ["LINK_FAIL"])
|
||||
|
||||
# Generator which runs an EXE and captures output.
|
||||
generators.register_standard("testing.capture-output", ["EXE"], ["RUN_OUTPUT"])
|
||||
|
||||
# Generator which creates a target if sources run successfully. Differs from RUN
|
||||
# in that run output is not captured. The reason why it exists is that the 'run'
|
||||
# rule is much better for automated testing, but is not user-friendly (see
|
||||
# http://article.gmane.org/gmane.comp.lib.boost.build/6353).
|
||||
generators.register_standard("testing.unit-test", ["EXE"], ["UNIT_TEST"])
|
||||
|
||||
# FIXME: if those calls are after bjam.call, then bjam will crash
|
||||
# when toolset.flags calls bjam.caller.
|
||||
toolset.flags("testing.capture-output", "ARGS", [], ["<testing.arg>"])
|
||||
toolset.flags("testing.capture-output", "INPUT_FILES", [], ["<testing.input-file>"])
|
||||
toolset.flags("testing.capture-output", "LAUNCHER", [], ["<testing.launcher>"])
|
||||
|
||||
toolset.flags("testing.unit-test", "LAUNCHER", [], ["<testing.launcher>"])
|
||||
toolset.flags("testing.unit-test", "ARGS", [], ["<testing.arg>"])
|
||||
|
||||
type.register("TIME", ["time"])
|
||||
generators.register_standard("testing.time", [], ["TIME"])
|
||||
|
||||
|
||||
# The following code sets up actions for this module. It's pretty convoluted,
|
||||
# but the basic points is that we most of actions are defined by Jam code
|
||||
# contained in testing-aux.jam, which we load into Jam module named 'testing'
|
||||
|
||||
def run_path_setup(target, sources, ps):
|
||||
|
||||
# For testing, we need to make sure that all dynamic libraries needed by the
|
||||
# test are found. So, we collect all paths from dependency libraries (via
|
||||
# xdll-path property) and add whatever explicit dll-path user has specified.
|
||||
# The resulting paths are added to the environment on each test invocation.
|
||||
dll_paths = ps.get('dll-path')
|
||||
dll_paths.extend(ps.get('xdll-path'))
|
||||
dll_paths.extend(bjam.call("get-target-variable", sources, "RUN_PATH"))
|
||||
dll_paths = unique(dll_paths)
|
||||
if dll_paths:
|
||||
bjam.call("set-target-variable", target, "PATH_SETUP",
|
||||
common.prepend_path_variable_command(
|
||||
common.shared_library_path_variable(), dll_paths))
|
||||
|
||||
def capture_output_setup(target, sources, ps):
|
||||
run_path_setup(target, sources, ps)
|
||||
|
||||
if ps.get('preserve-test-targets') == ['off']:
|
||||
bjam.call("set-target-variable", target, "REMOVE_TEST_TARGETS", "1")
|
||||
|
||||
get_manager().engine().register_bjam_action("testing.capture-output",
|
||||
capture_output_setup)
|
||||
|
||||
|
||||
path = os.path.dirname(get_manager().projects().loaded_tool_module_path_[__name__])
|
||||
import b2.util.os_j
|
||||
get_manager().projects().project_rules()._import_rule("testing", "os.name",
|
||||
b2.util.os_j.name)
|
||||
import b2.tools.common
|
||||
get_manager().projects().project_rules()._import_rule("testing", "common.rm-command",
|
||||
b2.tools.common.rm_command)
|
||||
get_manager().projects().project_rules()._import_rule("testing", "common.file-creation-command",
|
||||
b2.tools.common.file_creation_command)
|
||||
|
||||
bjam.call("load", "testing", os.path.join(path, "testing-aux.jam"))
|
||||
|
||||
|
||||
for name in ["expect-success", "expect-failure", "time"]:
|
||||
get_manager().engine().register_bjam_action("testing." + name)
|
||||
|
||||
get_manager().engine().register_bjam_action("testing.unit-test",
|
||||
run_path_setup)
|
||||
|
||||
if option.get("dump-tests", False, True):
|
||||
build_system.add_pre_build_hook(dump_tests)
|
||||
92
v2/tools/zlib.jam
Normal file
92
v2/tools/zlib.jam
Normal file
@@ -0,0 +1,92 @@
|
||||
# Copyright (c) 2010 Vladimir Prus.
|
||||
#
|
||||
# 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)
|
||||
|
||||
# Supports the zlib library
|
||||
#
|
||||
# After 'using zlib', the following targets are available:
|
||||
#
|
||||
# /zlib//zlib -- The zlib library
|
||||
|
||||
|
||||
# In addition to direct purpose of supporting zlib, this module also
|
||||
# serves as canonical example of how third-party condiguration works
|
||||
# in Boost.Build. The operation is as follows
|
||||
#
|
||||
# - For each 'using zlib : condition ... : ...' we create a target alternative
|
||||
# for zlib, with the specified condition.
|
||||
# - There's one target alternative for 'zlib' with no specific condition
|
||||
# properties.
|
||||
#
|
||||
# Two invocations of 'using zlib' with the same condition but different
|
||||
# properties are not permitted, e.g.:
|
||||
#
|
||||
# using zlib : condition <target-os>windows : include foo ;
|
||||
# using zlib : condition <target-os>windows : include bar ;
|
||||
#
|
||||
# is in error. One exception is for empty condition, 'using' without any
|
||||
# parameters is overridable. That is:
|
||||
#
|
||||
# using zlib ;
|
||||
# using zlib : include foo ;
|
||||
#
|
||||
# Is OK then the first 'using' is ignored. Likewise if the order of the statements
|
||||
# is reversed.
|
||||
#
|
||||
# When 'zlib' target is built, a target alternative is selected as usual for
|
||||
# Boost.Build. The selected alternative is a custom target class, which:
|
||||
#
|
||||
# - calls ac.find-include-path to find header path. If explicit path is provided
|
||||
# in 'using', only that path is checked, and if no header is found there, error
|
||||
# is emitted. Otherwise, we check a directory specified using ZLIB_INCLUDE
|
||||
# environment variable, and failing that, in standard directories.
|
||||
# [TODO: document sysroot handling]
|
||||
# - calls ac.find-library to find the library, in an identical fashion.
|
||||
#
|
||||
|
||||
import project ;
|
||||
import ac ;
|
||||
import errors ;
|
||||
import "class" : new ;
|
||||
import targets ;
|
||||
|
||||
project.initialize $(__name__) ;
|
||||
project = [ project.current ] ;
|
||||
project zlib ;
|
||||
|
||||
header = zlib.h ;
|
||||
names = z zlib zll zdll ;
|
||||
|
||||
.default-alternative = [ new ac-library zlib : $(project) ] ;
|
||||
$(.default-alternative).set-header $(header) ;
|
||||
$(.default-alternative).set-default-names $(names) ;
|
||||
targets.main-target-alternative $(.default-alternative) ;
|
||||
|
||||
rule init ( * : * )
|
||||
{
|
||||
if ! $(condition)
|
||||
{
|
||||
# Special case the no-condition case so that 'using' without parameters
|
||||
# can mix with more specific 'using'.
|
||||
$(.default-alternative).reconfigure $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
# FIXME: consider if we should allow overriding definitions for a given
|
||||
# condition -- e.g. project-config.jam might want to override whatever is
|
||||
# in user-config.jam.
|
||||
local mt = [ new ac-library zlib : $(project)
|
||||
: $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ] ;
|
||||
$(mt).set-header $(header) ;
|
||||
$(mt).set-default-names $(names) ;
|
||||
targets.main-target-alternative $(mt) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
15
v2/util/indirect.py
Normal file
15
v2/util/indirect.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# Status: minimally ported. This module is not supposed to be used much
|
||||
# with Boost.Build/Python.
|
||||
#
|
||||
# Copyright 2003 Dave Abrahams
|
||||
# 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 b2.util import call_jam_function, bjam_signature
|
||||
|
||||
def call(*args):
|
||||
a1 = args[0]
|
||||
name = a1[0]
|
||||
a1tail = a1[1:]
|
||||
call_jam_function(name, *((a1tail,) + args[1:]))
|
||||
35
v2/util/option.py
Normal file
35
v2/util/option.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2005-2010 Vladimir Prus.
|
||||
#
|
||||
# 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)
|
||||
|
||||
import sys
|
||||
import re
|
||||
import b2.util.regex
|
||||
|
||||
options = {}
|
||||
|
||||
# Set a value for a named option, to be used when not overridden on the command
|
||||
# line.
|
||||
def set(name, value=None):
|
||||
|
||||
global options
|
||||
|
||||
options[name] = value
|
||||
|
||||
def get(name, default_value=None, implied_value=None):
|
||||
|
||||
global options
|
||||
|
||||
matches = b2.util.regex.transform(sys.argv, "--" + re.escape(name) + "=(.*)")
|
||||
if matches:
|
||||
return matches[-1]
|
||||
else:
|
||||
m = b2.util.regex.transform(sys.argv, "--(" + re.escape(name) + ")")
|
||||
if m and implied_value:
|
||||
return implied_value
|
||||
elif options.has_key(name) and options[name] != None:
|
||||
return options[name]
|
||||
else:
|
||||
return default_value
|
||||
19
v2/util/os_j.py
Normal file
19
v2/util/os_j.py
Normal file
@@ -0,0 +1,19 @@
|
||||
# Status: stub, just enough to make tests work.
|
||||
#
|
||||
# Named os_j to avoid conflicts with standard 'os'. See
|
||||
# project.py:import for special-casing.
|
||||
#
|
||||
# Copyright 2001, 2002, 2003, 2005 Dave Abrahams
|
||||
# Copyright 2006 Rene Rivera
|
||||
# Copyright 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)
|
||||
|
||||
import bjam
|
||||
|
||||
__OS = bjam.call("peek", [], "OS")[0]
|
||||
|
||||
# Return Jam's name of OS to prevent existing code from burning
|
||||
# when faced with Python naming
|
||||
def name():
|
||||
return __OS
|
||||
Reference in New Issue
Block a user