summaryrefslogtreecommitdiff
path: root/tools/build
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-10-31 14:41:14 +0000
committer <>2014-12-12 16:07:56 +0000
commited232fdd34968697a68783b3195b1da4226915b5 (patch)
tree7a7053ceb8874b28ec4b868d4c49b500008a102e /tools/build
parent1c3648bf5b7d17fcd4fe9bc95802b16fd9eee304 (diff)
downloadboost-tarball-ed232fdd34968697a68783b3195b1da4226915b5.tar.gz
Imported from /home/lorry/working-area/delta_boost-tarball/boost_1_57_0.tar.bz2.boost_1_57_0
Diffstat (limited to 'tools/build')
-rw-r--r--tools/build/debian/boost-build.docs4
-rw-r--r--tools/build/debian/boost-build.examples1
-rw-r--r--tools/build/debian/changelog6
-rw-r--r--tools/build/debian/conffiles1
-rw-r--r--tools/build/debian/control13
-rw-r--r--tools/build/debian/excludes14
-rwxr-xr-xtools/build/debian/rules56
-rw-r--r--tools/build/doc/src/extending.xml2
-rw-r--r--tools/build/doc/src/overview.xml4
-rw-r--r--tools/build/doc/src/reference.xml69
-rw-r--r--tools/build/doc/src/tutorial.xml4
-rw-r--r--tools/build/index.html (renamed from tools/build/website/index.html)2
-rw-r--r--tools/build/src/build/engine.py27
-rw-r--r--tools/build/src/build/feature.py2
-rw-r--r--tools/build/src/build/project.py117
-rw-r--r--tools/build/src/build/property.jam2
-rw-r--r--tools/build/src/build/property_set.py2
-rw-r--r--tools/build/src/build/targets.jam6
-rw-r--r--tools/build/src/build/toolset.py2
-rw-r--r--tools/build/src/build/virtual-target.jam22
-rw-r--r--tools/build/src/build/virtual_target.py2
-rw-r--r--tools/build/src/contrib/__init__.py (renamed from tools/build/debian/copyright)0
-rw-r--r--tools/build/src/engine/execnt.c142
-rwxr-xr-xtools/build/src/options/help.jam10
-rw-r--r--tools/build/src/tools/clang-linux.jam29
-rw-r--r--tools/build/src/tools/clang-win.jam175
-rw-r--r--tools/build/src/tools/common.py19
-rw-r--r--tools/build/src/tools/common_clang_vc.jam987
-rw-r--r--tools/build/src/tools/cray.jam9
-rw-r--r--tools/build/src/tools/docutils.jam14
-rw-r--r--tools/build/src/tools/gcc.jam8
-rw-r--r--tools/build/src/tools/gcc.py13
-rw-r--r--tools/build/src/tools/intel-win.jam17
-rw-r--r--tools/build/src/tools/midl.py2
-rw-r--r--tools/build/src/tools/msvc.jam292
-rw-r--r--tools/build/src/tools/msvc.py2
-rw-r--r--tools/build/src/tools/python.jam6
-rw-r--r--tools/build/src/tools/rc.py3
-rw-r--r--tools/build/src/tools/testing.py2
-rw-r--r--tools/build/src/tools/types/asm.py28
-rw-r--r--tools/build/src/tools/types/cpp.py85
-rw-r--r--tools/build/src/util/doc.jam29
-rw-r--r--tools/build/src/util/path.py36
-rw-r--r--tools/build/src/util/regex.py33
-rw-r--r--tools/build/test/dependency_property.py2
45 files changed, 2030 insertions, 271 deletions
diff --git a/tools/build/debian/boost-build.docs b/tools/build/debian/boost-build.docs
deleted file mode 100644
index 70af14954..000000000
--- a/tools/build/debian/boost-build.docs
+++ /dev/null
@@ -1,4 +0,0 @@
-boost_build_v2.html
-index_v2.html
-boost.png
-doc \ No newline at end of file
diff --git a/tools/build/debian/boost-build.examples b/tools/build/debian/boost-build.examples
deleted file mode 100644
index e5a7b8d3b..000000000
--- a/tools/build/debian/boost-build.examples
+++ /dev/null
@@ -1 +0,0 @@
-example/* \ No newline at end of file
diff --git a/tools/build/debian/changelog b/tools/build/debian/changelog
deleted file mode 100644
index bfc1f139c..000000000
--- a/tools/build/debian/changelog
+++ /dev/null
@@ -1,6 +0,0 @@
-boost-build (2.0.m10-1) unstable; urgency=low
-
- * Initial Release.
-
- -- Vladimir Prus <ghost@cs.msu.su> Wed, 14 Aug 2002 14:08:00 +0400
-
diff --git a/tools/build/debian/conffiles b/tools/build/debian/conffiles
deleted file mode 100644
index 291d688ed..000000000
--- a/tools/build/debian/conffiles
+++ /dev/null
@@ -1 +0,0 @@
-/etc/site-config.jam
diff --git a/tools/build/debian/control b/tools/build/debian/control
deleted file mode 100644
index 7d1733e78..000000000
--- a/tools/build/debian/control
+++ /dev/null
@@ -1,13 +0,0 @@
-Source: boost-build
-Section: devel
-Priority: optional
-Maintainer: Vladimir Prus <ghost@cs.msu.su>
-Build-Depends: debhelper (>> 3.0.0), docbook-to-man, bison
-Standards-Version: 3.5.2
-
-Package: boost-build
-Architecture: all
-Depends: ${shlibs:Depends}, bjam (>> 3.1.9-1)
-Description: Build system
- Boost.Build is a build system with a simple and high-level language.
- It supports build variants, and several different compilers and tools.
diff --git a/tools/build/debian/excludes b/tools/build/debian/excludes
deleted file mode 100644
index 59882930d..000000000
--- a/tools/build/debian/excludes
+++ /dev/null
@@ -1,14 +0,0 @@
-boost.css
-boost_build_v2.html
-index_v2.html
-boost.png
-generators_prototype.py
-hacking.txt
-release_procedure.txt
-site-config.jam
-roll.sh
-debian
-doc
-example
-test
-CVS \ No newline at end of file
diff --git a/tools/build/debian/rules b/tools/build/debian/rules
deleted file mode 100755
index 96ccc418b..000000000
--- a/tools/build/debian/rules
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/make -f
-# Sample debian/rules that uses debhelper.
-# This file is public domain software, originally written by Joey Hess.
-
-# Uncomment this to turn on verbose mode.
-#export DH_VERBOSE=1
-
-build:
-clean:
-binary-arch:
-
-binary-indep:
- dh_testdir
- dh_testroot
-
- dh_clean -k
- dh_installdirs usr/share/boost-build etc
-
- # Add here commands to install the package into debian/<packagename>
- (tar --exclude-from debian/excludes -cpf - * ) | (cd `pwd`/debian/tmp/usr/share/boost-build && tar xpf - )
- chmod a-x -R `pwd`/debian/tmp/usr/share/boost-build
-
- dh_installchangelogs
- dh_installdocs -XCVS
- mv `pwd`/debian/tmp/usr/share/doc/boost-build/index_v2.html `pwd`/debian/tmp/usr/share/doc/boost-build/index.html
-
- (tar --exclude make --exclude CVS -cpf - example/* ) | ( cd `pwd`/debian/tmp/usr/share/doc/boost-build && tar xpf - )
-
- sed 's/# using gcc ;/using gcc ;/' user-config.jam > `pwd`/debian/tmp/etc/site-config.jam
-
-# dh_install
-# dh_installmenu
-# dh_installdebconf
-# dh_installlogrotate
-# dh_installemacsen
-# dh_installcatalogs
-# dh_installpam
-# dh_installmime
-# dh_installinit
-# dh_installcron
-# dh_installinfo
-# dh_undocumented
- dh_installman
- dh_link
- dh_compress
- dh_fixperms
-# dh_perl
-# dh_python
-# dh_makeshlibs
- dh_installdeb
- dh_gencontrol
- dh_md5sums
- dh_builddeb
-
-binary: binary-indep binary-arch
-.PHONY: build clean binary-indep binary-arch binary install
diff --git a/tools/build/doc/src/extending.xml b/tools/build/doc/src/extending.xml
index 8b7811dc7..e03a22c2a 100644
--- a/tools/build/doc/src/extending.xml
+++ b/tools/build/doc/src/extending.xml
@@ -469,7 +469,7 @@ exe codegen : codegen.cpp class_template.verbatim usage.verbatim ;
<section id="bbv2.extending.targets">
<title>Target types</title>
<para>The first thing we did in the <link
- linkend="bbv2.extender.intro">intruduction</link> was declaring a
+ linkend="bbv2.extender.intro">introduction</link> was declaring a
new target type:
<programlisting>
import type ;
diff --git a/tools/build/doc/src/overview.xml b/tools/build/doc/src/overview.xml
index 9fc30adb1..6dbb38a84 100644
--- a/tools/build/doc/src/overview.xml
+++ b/tools/build/doc/src/overview.xml
@@ -1194,14 +1194,14 @@ obj main : main.cpp : &lt;optimization&gt;off ;
release mode.
<programlisting>
lib network : network.cpp
- : <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NEWORK_LIB_SHARED</emphasis>
+ : <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NETWORK_LIB_SHARED</emphasis>
&lt;variant&gt;release:&lt;define&gt;EXTRA_FAST
;
</programlisting>
In the example above, whenever <filename>network</filename> is
built with <code>&lt;link&gt;shared</code>,
- <code>&lt;define&gt;NEWORK_LIB_SHARED</code> will be in its
+ <code>&lt;define&gt;NETWORK_LIB_SHARED</code> will be in its
properties, too.
</para>
diff --git a/tools/build/doc/src/reference.xml b/tools/build/doc/src/reference.xml
index a8d41f221..b34391268 100644
--- a/tools/build/doc/src/reference.xml
+++ b/tools/build/doc/src/reference.xml
@@ -817,6 +817,26 @@ path-constant DATA : data/a.txt ;
</listitem>
</varlistentry>
+ <varlistentry><term><literal>embed-manifest-file</literal></term>
+ <listitem>
+
+ <indexterm><primary>manifest file</primary><secondary>embedding</secondary></indexterm>
+ <indexterm><primary>embed-manifest-file</primary></indexterm>
+
+ <para>This feature is specific to the msvc toolset (see
+ <xref linkend="bbv2.reference.tools.compiler.msvc"/>),
+ and controls which manifest files should be embedded inside
+ executables and shared libraries. This
+ feature corresponds to the IDE option found in the project settings dialog,
+ under <menuchoice><guimenu>Configuration Properties</guimenu>
+ <guisubmenu>Manifest Tool</guisubmenu>
+ <guisubmenu>Input and Output</guisubmenu>
+ <guimenuitem>Additional Manifest Files</guimenuitem> </menuchoice>.
+ </para>
+
+ </listitem>
+ </varlistentry>
+
</variablelist>
</section>
@@ -1140,6 +1160,55 @@ using msvc : &toolset_ops; ;
options depending on the value of the<code>instruction-set</code>
feature.</para>
</section>
+
+ <section id="v2.reference.tools.compiler.msvc.winrt">
+ <title>Windows Runtime support</title>
+
+ <indexterm><primary>Windows Runtime support</primary>
+ <secondary>Microsoft Visual Studio</secondary></indexterm>
+
+ <para>
+ Starting with version 11.0, Microsoft Visual Studio can
+ produce binaries for Windows Store and Phone in addition to
+ traditional Win32 desktop. To specify which Windows API set
+ to target, use the <literal>windows-api</literal> feature.
+ Available options are <literal>desktop</literal>,
+ <literal>store</literal>, or <literal>phone</literal>. If not
+ specified, <literal>desktop</literal> will be used.
+ </para>
+
+ <para>
+ When using <literal>store</literal> or <literal>phone</literal>
+ the specified toolset determines what Windows version is
+ targeted. The following options are available:
+ </para>
+
+ <itemizedlist>
+ <listitem><para>Windows 8.0: toolset=msvc-11.0 windows-api=store</para>
+ </listitem>
+ <listitem><para>Windows 8.1: toolset=msvc-12.0 windows-api=store</para>
+ </listitem>
+ <listitem><para>Windows Phone 8.0: toolset=msvc-11.0 windows-api=phone</para>
+ </listitem>
+ <listitem><para>Windows Phone 8.1: toolset=msvc-12.0 windows-api=phone</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>
+ For example use the following to build for Windows Store 8.1
+ with the ARM architecture:
+ </para>
+ <programlisting>
+.\b2 toolset=msvc=12.0 windows-api=store architecture=arm</programlisting>
+
+ <para>
+ Note that when targeting Windows Phone 8.1, version 12.0 didn't
+ include the vcvars phone setup scripts. They can be separately
+ downloaded from
+ <ulink url="http://blogs.msdn.com/b/vcblog/archive/2014/07/18/using-boost-libraries-in-windows-store-and-phone-applications.aspx">here</ulink>.
+ </para>
+
+ </section>
</section>
<section id="bbv2.reference.tools.compiler.intel">
diff --git a/tools/build/doc/src/tutorial.xml b/tools/build/doc/src/tutorial.xml
index 141ed9196..29a014393 100644
--- a/tools/build/doc/src/tutorial.xml
+++ b/tools/build/doc/src/tutorial.xml
@@ -556,12 +556,12 @@ exe app : app.cpp core ;</programlisting>
<programlisting language="jam">
lib network : network.cpp
- : <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NEWORK_LIB_SHARED</emphasis>
+ : <emphasis role="bold">&lt;link&gt;shared:&lt;define&gt;NETWORK_LIB_SHARED</emphasis>
&lt;variant&gt;release:&lt;define&gt;EXTRA_FAST
;</programlisting>
In the example above, whenever <filename>network</filename> is built with
- <code language="jam">&lt;link&gt;shared</code>, <code language="jam">&lt;define&gt;NEWORK_LIB_SHARED
+ <code language="jam">&lt;link&gt;shared</code>, <code language="jam">&lt;define&gt;NETWORK_LIB_SHARED
</code> will be in its properties, too. Also, whenever its release variant
is built, <code>&lt;define&gt;EXTRA_FAST</code> will appear in its
properties.
diff --git a/tools/build/website/index.html b/tools/build/index.html
index 63df93fec..6769bcaec 100644
--- a/tools/build/website/index.html
+++ b/tools/build/index.html
@@ -36,7 +36,7 @@ div.sidebar p.rubric {
<body bgcolor="#FFFFFF" text="#000000">
- <p align="center"><img src="boost_build.png" width="396" height="60" alt="Boost.Build V2"></img>
+ <p align="center"><img src="website/boost_build.png" width="396" height="60" alt="Boost.Build V2"></img>
<div class="contents sidebar topic" id="index">
<p>
diff --git a/tools/build/src/build/engine.py b/tools/build/src/build/engine.py
index 9e624dae8..35333eaa0 100644
--- a/tools/build/src/build/engine.py
+++ b/tools/build/src/build/engine.py
@@ -81,7 +81,32 @@ class Engine:
for target in targets:
for source in sources:
self.do_add_dependency (target, source)
-
+
+ def get_target_variable(self, targets, variable):
+ """Gets the value of `variable` on set on the first target in `targets`.
+
+ Args:
+ targets (str or list): one or more targets to get the variable from.
+ variable (str): the name of the variable
+
+ Returns:
+ the value of `variable` set on `targets` (list)
+
+ Example:
+
+ >>> ENGINE = get_manager().engine()
+ >>> ENGINE.set_target_variable(targets, 'MY-VAR', 'Hello World')
+ >>> ENGINE.get_target_variable(targets, 'MY-VAR')
+ ['Hello World']
+
+ Equivalent Jam code:
+
+ MY-VAR on $(targets) = "Hello World" ;
+ echo [ on $(targets) return $(MY-VAR) ] ;
+ "Hello World"
+ """
+ return bjam_interface.call('get-target-variable', targets, variable)
+
def set_target_variable (self, targets, variable, value, append=0):
""" Sets a target variable.
diff --git a/tools/build/src/build/feature.py b/tools/build/src/build/feature.py
index 2ab6e5c67..386e49931 100644
--- a/tools/build/src/build/feature.py
+++ b/tools/build/src/build/feature.py
@@ -442,7 +442,7 @@ def validate_value_string (f, value_string):
# An empty value is allowed for optional features
if not values[0] in f.values() and \
(values[0] or not f.optional()):
- raise InvalidValue ("'%s' is not a known value of feature '%s'\nlegal values: '%s'" % (values [0], feature, f.values()))
+ raise InvalidValue ("'%s' is not a known value of feature '%s'\nlegal values: '%s'" % (values [0], f.name(), f.values()))
for v in values [1:]:
# this will validate any subfeature values in value-string
diff --git a/tools/build/src/build/project.py b/tools/build/src/build/project.py
index 1cbc0e8c0..71bc33fb3 100644
--- a/tools/build/src/build/project.py
+++ b/tools/build/src/build/project.py
@@ -45,9 +45,11 @@ from b2.build.errors import ExceptionWithUserContext
import b2.build.targets
import bjam
+import b2
import re
import sys
+import pkgutil
import os
import string
import imp
@@ -120,6 +122,8 @@ class ProjectRegistry:
self.JAMFILE = ["[Bb]uild.jam", "[Jj]amfile.v2", "[Jj]amfile",
"[Jj]amfile.jam"]
+ self.__python_module_cache = {}
+
def load (self, jamfile_location):
"""Loads jamfile at the given location. After loading, project global
@@ -525,7 +529,6 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
def attribute(self, project, attribute):
"""Returns the value of the specified attribute in the
specified jamfile module."""
- return self.module2attributes[project].get(attribute)
try:
return self.module2attributes[project].get(attribute)
except:
@@ -607,6 +610,39 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
return result
+ def __build_python_module_cache(self):
+ """Recursively walks through the b2/src subdirectories and
+ creates an index of base module name to package name. The
+ index is stored within self.__python_module_cache and allows
+ for an O(1) module lookup.
+
+ For example, given the base module name `toolset`,
+ self.__python_module_cache['toolset'] will return
+ 'b2.build.toolset'
+
+ pkgutil.walk_packages() will find any python package
+ provided a directory contains an __init__.py. This has the
+ added benefit of allowing libraries to be installed and
+ automatically avaiable within the contrib directory.
+
+ *Note*: pkgutil.walk_packages() will import any subpackage
+ in order to access its __path__variable. Meaning:
+ any initialization code will be run if the package hasn't
+ already been imported.
+ """
+ cache = {}
+ for importer, mname, ispkg in pkgutil.walk_packages(b2.__path__, prefix='b2.'):
+ basename = mname.split('.')[-1]
+ # since the jam code is only going to have "import toolset ;"
+ # it doesn't matter if there are separately named "b2.build.toolset" and
+ # "b2.contrib.toolset" as it is impossible to know which the user is
+ # referring to.
+ if basename in cache:
+ self.manager.errors()('duplicate module name "{0}" '
+ 'found in boost-build path'.format(basename))
+ cache[basename] = mname
+ self.__python_module_cache = cache
+
def load_module(self, name, extra_path=None):
"""Load a Python module that should be useable from Jamfiles.
@@ -620,50 +656,61 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project))
since then we might get naming conflicts between standard
Python modules and those.
"""
-
# See if we loaded module of this name already
existing = self.loaded_tool_modules_.get(name)
if existing:
return existing
- # See if we have a module b2.whatever.<name>, where <name>
- # is what is passed to this function
- modules = sys.modules
- for class_name in modules:
- parts = class_name.split('.')
- if name is class_name or parts[0] == "b2" \
- and parts[-1] == name.replace("-", "_"):
- module = modules[class_name]
- self.loaded_tool_modules_[name] = module
- return module
-
- # Lookup a module in BOOST_BUILD_PATH
- path = extra_path
- if not path:
- path = []
- path.extend(self.manager.boost_build_path())
- location = None
- for p in path:
- l = os.path.join(p, name + ".py")
- if os.path.exists(l):
- location = l
- break
-
- if not location:
- self.manager.errors()("Cannot find module '%s'" % name)
+ # check the extra path as well as any paths outside
+ # of the b2 package and import the module if it exists
+ b2_path = os.path.normpath(b2.__path__[0])
+ # normalize the pathing in the BOOST_BUILD_PATH.
+ # this allows for using startswith() to determine
+ # if a path is a subdirectory of the b2 root_path
+ paths = [os.path.normpath(p) for p in self.manager.boost_build_path()]
+ # remove all paths that start with b2's root_path
+ paths = [p for p in paths if not p.startswith(b2_path)]
+ # add any extra paths
+ paths.extend(extra_path)
- mname = name + "__for_jamfile"
- file = open(location)
try:
- # TODO: this means we'll never make use of .pyc module,
- # which might be a problem, or not.
+ # find_module is used so that the pyc's can be used.
+ # an ImportError is raised if not found
+ f, location, description = imp.find_module(name, paths)
+ mname = name + "__for_jamfile"
self.loaded_tool_module_path_[mname] = location
- module = imp.load_module(mname, file, os.path.basename(location),
- (".py", "r", imp.PY_SOURCE))
+ module = imp.load_module(mname, f, location, description)
self.loaded_tool_modules_[name] = module
return module
- finally:
- file.close()
+ except ImportError:
+ # if the module is not found in the b2 package,
+ # this error will be handled later
+ pass
+
+ # the cache is created here due to possibly importing packages
+ # that end up calling get_manager() which might fail
+ if not self.__python_module_cache:
+ self.__build_python_module_cache()
+
+ underscore_name = name.replace('-', '_')
+ # check to see if the module is within the b2 package
+ # and already loaded
+ mname = self.__python_module_cache.get(underscore_name)
+ if mname in sys.modules:
+ return sys.modules[mname]
+ # otherwise, if the module name is within the cache,
+ # the module exists within the BOOST_BUILD_PATH,
+ # load it.
+ elif mname:
+ # __import__ can be used here since the module
+ # is guaranteed to be found under the `b2` namespace.
+ __import__(mname)
+ module = sys.modules[mname]
+ self.loaded_tool_modules_[name] = module
+ self.loaded_tool_module_path_[mname] = module.__file__
+ return module
+
+ self.manager.errors()("Cannot find module '%s'" % name)
diff --git a/tools/build/src/build/property.jam b/tools/build/src/build/property.jam
index 7fdf18757..ff28dfd20 100644
--- a/tools/build/src/build/property.jam
+++ b/tools/build/src/build/property.jam
@@ -766,7 +766,7 @@ class property-map
errors.error "Ambiguous key $(properties:J= :E=)" ;
}
local original = $($(best)[1]) ;
- if $(value)
+ if $(value)-is-set
{
$(best) = $(value) $($(best)[2-]) ;
}
diff --git a/tools/build/src/build/property_set.py b/tools/build/src/build/property_set.py
index 4fff814c9..6b3643045 100644
--- a/tools/build/src/build/property_set.py
+++ b/tools/build/src/build/property_set.py
@@ -9,7 +9,7 @@
import hashlib
from b2.util.utility import *
-import property, feature, string
+import property, feature
import b2.build.feature
from b2.exceptions import *
from b2.util.sequence import unique
diff --git a/tools/build/src/build/targets.jam b/tools/build/src/build/targets.jam
index 3bd39a30e..44c8fc9e4 100644
--- a/tools/build/src/build/targets.jam
+++ b/tools/build/src/build/targets.jam
@@ -394,7 +394,7 @@ class project-target : abstract-target
if ! [ path.is-rooted $(project-part) ]
{
local rooted = [ path.root $(project-part) / ] ;
- if [ project.is-registered-id $(rooted) ]
+ if $(rooted) && [ project.is-registered-id $(rooted) ]
{
extra-error-message += - possibly missing a leading
slash ('/') character. ;
@@ -830,6 +830,10 @@ rule resolve-reference ( target-reference : project )
# Separate target name from properties override.
local split = [ MATCH "^([^<]*)(/(<.*))?$" : $(target-reference) ] ;
local id = $(split[1]) ;
+ if ! $(split) || ! $(id)
+ {
+ error "Malformed target reference $(target-reference)" ;
+ }
local sproperties = ;
if $(split[3])
{
diff --git a/tools/build/src/build/toolset.py b/tools/build/src/build/toolset.py
index 3665ab872..e969123d4 100644
--- a/tools/build/src/build/toolset.py
+++ b/tools/build/src/build/toolset.py
@@ -362,7 +362,7 @@ def __add_flag (rule_or_module, variable_name, condition, values):
assert m
module = m.group(1)
- __module_flags.setdefault(m, []).append(f)
+ __module_flags.setdefault(module, []).append(f)
__flags.setdefault(rule_or_module, []).append(f)
__requirements = []
diff --git a/tools/build/src/build/virtual-target.jam b/tools/build/src/build/virtual-target.jam
index 44a706db3..3103c3051 100644
--- a/tools/build/src/build/virtual-target.jam
+++ b/tools/build/src/build/virtual-target.jam
@@ -1088,15 +1088,19 @@ rule register-actual-name ( actual-name : virtual-target )
properties-added = [ set.difference $(p2) : $(p1) ] ;
properties-added ?= "none" ;
}
- import errors : error : errors.error ;
- errors.error "Duplicate name of actual target:" $(actual-name)
- : "previous virtual target" [ $(.actual.$(actual-name)).str ]
- : "created from" $(cmt1-name)
- : "another virtual target" [ $(virtual-target).str ]
- : "created from" $(cmt2-name)
- : "added properties:" $(properties-added)
- : "removed properties:" $(properties-removed)
- : $(extra-error-information) ;
+ import errors : user-error : errors.user-error ;
+ errors.user-error "Name clash for '$(actual-name)'"
+ : ""
+ : "Tried to build the target twice, with property sets having "
+ : "these incompabile properties:"
+ : ""
+ : " - " $(properties-removed)
+ : " - " $(properties-added)
+ : ""
+ : "Please make sure to have consistent requirements for these "
+ : "properties everywhere in your project, especially for install"
+ : "targets."
+ ;
}
else
{
diff --git a/tools/build/src/build/virtual_target.py b/tools/build/src/build/virtual_target.py
index f3d190f64..ac6703056 100644
--- a/tools/build/src/build/virtual_target.py
+++ b/tools/build/src/build/virtual_target.py
@@ -708,7 +708,7 @@ class FileTarget (AbstractFileTarget):
# any more
self.path_ = target_path
- return self.path_
+ return os.path.normpath(self.path_)
class NotFileTarget(AbstractFileTarget):
diff --git a/tools/build/debian/copyright b/tools/build/src/contrib/__init__.py
index e69de29bb..e69de29bb 100644
--- a/tools/build/debian/copyright
+++ b/tools/build/src/contrib/__init__.py
diff --git a/tools/build/src/engine/execnt.c b/tools/build/src/engine/execnt.c
index 12ed75987..d75aab0ae 100644
--- a/tools/build/src/engine/execnt.c
+++ b/tools/build/src/engine/execnt.c
@@ -780,31 +780,161 @@ static void read_output()
* cmdtab array, or -1.
*/
+typedef struct _twh_params
+{
+ int * active_procs;
+ HANDLE * active_handles;
+ DWORD num_active;
+ DWORD timeoutMillis;
+} twh_params;
+
+static int try_wait_helper( twh_params * );
+
static int try_wait( int const timeoutMillis )
{
+#define MAX_THREADS MAXJOBS/(MAXIMUM_WAIT_OBJECTS - 1) + 1
int i;
int num_active;
int wait_api_result;
- HANDLE active_handles[ MAXJOBS ];
- int active_procs[ MAXJOBS ];
+ HANDLE active_handles[ MAXJOBS + MAX_THREADS ];
+ int active_procs[ MAXJOBS + MAX_THREADS ];
+ unsigned int num_threads;
+ unsigned int num_handles;
+ unsigned int last_chunk_size;
+ unsigned int last_chunk_offset;
+ HANDLE completed_event = INVALID_HANDLE_VALUE;
+ HANDLE thread_handles[MAXIMUM_WAIT_OBJECTS];
+ twh_params thread_params[MAX_THREADS];
+ int result = -1;
+ BOOL success;
/* Prepare a list of all active processes to wait for. */
for ( num_active = 0, i = 0; i < globs.jobs; ++i )
if ( cmdtab[ i ].pi.hProcess )
{
+ if ( num_active == MAXIMUM_WAIT_OBJECTS )
+ {
+ /*
+ * We surpassed MAXIMUM_WAIT_OBJECTS, so we need to use threads
+ * to wait for this set. Create an event object which will
+ * notify threads to stop waiting. Every handle set chunk should
+ * have this event as its last element.
+ */
+ assert( completed_event == INVALID_HANDLE_VALUE );
+ completed_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ active_handles[ num_active ] = active_handles[ num_active - 1 ];
+ active_procs[ num_active ] = active_procs[ num_active - 1 ];
+ active_handles[ num_active - 1 ] = completed_event;
+ active_procs[ num_active - 1 ] = -1;
+ ++num_active;
+ }
+ else if ( ( completed_event != INVALID_HANDLE_VALUE ) &&
+ !((num_active + 1) % MAXIMUM_WAIT_OBJECTS) )
+ {
+ active_handles[ num_active ] = completed_event;
+ active_procs[ num_active ] = -1;
+ ++num_active;
+ }
active_handles[ num_active ] = cmdtab[ i ].pi.hProcess;
active_procs[ num_active ] = i;
++num_active;
}
+ assert( (num_active <= MAXIMUM_WAIT_OBJECTS) ==
+ (completed_event == INVALID_HANDLE_VALUE) );
+ if ( num_active <= MAXIMUM_WAIT_OBJECTS )
+ {
+ twh_params twh;
+ twh.active_procs = active_procs;
+ twh.active_handles = active_handles;
+ twh.num_active = num_active;
+ twh.timeoutMillis = timeoutMillis;
+ return try_wait_helper( &twh );
+ }
+
+ num_threads = num_active / MAXIMUM_WAIT_OBJECTS;
+ last_chunk_size = num_active % MAXIMUM_WAIT_OBJECTS;
+ num_handles = num_threads;
+ if ( last_chunk_size )
+ {
+ /* Can we fit the last chunk in the outer WFMO call? */
+ if ( last_chunk_size <= MAXIMUM_WAIT_OBJECTS - num_threads )
+ {
+ last_chunk_offset = num_threads * MAXIMUM_WAIT_OBJECTS;
+ for ( i = 0; i < last_chunk_size; ++i )
+ thread_handles[ i + num_threads ] =
+ active_handles[ i + last_chunk_offset ];
+ num_handles = num_threads + last_chunk_size;
+ }
+ else
+ {
+ /* We need another thread for the remainder. */
+ /* Add completed_event handle to the last chunk. */
+ active_handles[ num_active ] = completed_event;
+ active_procs[ num_active ] = -1;
+ ++last_chunk_size;
+ ++num_active;
+ ++num_threads;
+ num_handles = num_threads;
+ }
+ }
+
+ assert( num_threads <= MAX_THREADS );
+
+ for ( i = 0; i < num_threads; ++i )
+ {
+ thread_params[i].active_procs = active_procs +
+ i * MAXIMUM_WAIT_OBJECTS;
+ thread_params[i].active_handles = active_handles +
+ i * MAXIMUM_WAIT_OBJECTS;
+ thread_params[i].timeoutMillis = INFINITE;
+ thread_params[i].num_active = MAXIMUM_WAIT_OBJECTS;
+ if ( ( i == num_threads - 1 ) && last_chunk_size &&
+ ( num_handles == num_threads ) )
+ thread_params[i].num_active = last_chunk_size;
+ thread_handles[i] = CreateThread(NULL, 4 * 1024,
+ (LPTHREAD_START_ROUTINE)&try_wait_helper, &thread_params[i],
+ 0, NULL);
+ }
+ wait_api_result = WaitForMultipleObjects(num_handles, thread_handles,
+ FALSE, timeoutMillis);
+ if ( ( WAIT_OBJECT_0 <= wait_api_result ) &&
+ ( wait_api_result < WAIT_OBJECT_0 + num_threads ) )
+ {
+ HANDLE thread_handle = thread_handles[wait_api_result - WAIT_OBJECT_0];
+ success = GetExitCodeThread(thread_handle, (DWORD *)&result);
+ assert( success );
+ }
+ else if ( ( WAIT_OBJECT_0 + num_threads <= wait_api_result ) &&
+ ( wait_api_result < WAIT_OBJECT_0 + num_handles ) )
+ {
+ unsigned int offset = wait_api_result - num_threads - WAIT_OBJECT_0;
+ result = active_procs[ last_chunk_offset + offset ];
+ }
+ SetEvent(completed_event);
+ /* Should complete instantly. */
+ WaitForMultipleObjects(num_threads, thread_handles, TRUE, INFINITE);
+ CloseHandle(completed_event);
+ for ( i = 0; i < num_threads; ++i )
+ CloseHandle(thread_handles[i]);
+ return result;
+#undef MAX_THREADS
+}
+
+static int try_wait_helper( twh_params * params )
+{
+ int wait_api_result;
+
+ assert( params->num_active <= MAXIMUM_WAIT_OBJECTS );
+
/* Wait for a child to complete, or for our timeout window to expire. */
- wait_api_result = WaitForMultipleObjects( num_active, active_handles,
- FALSE, timeoutMillis );
+ wait_api_result = WaitForMultipleObjects( params->num_active,
+ params->active_handles, FALSE, params->timeoutMillis );
if ( ( WAIT_OBJECT_0 <= wait_api_result ) &&
- ( wait_api_result < WAIT_OBJECT_0 + num_active ) )
+ ( wait_api_result < WAIT_OBJECT_0 + params->num_active ) )
{
/* Terminated process detected - return its index. */
- return active_procs[ wait_api_result - WAIT_OBJECT_0 ];
+ return params->active_procs[ wait_api_result - WAIT_OBJECT_0 ];
}
/* Timeout. */
diff --git a/tools/build/src/options/help.jam b/tools/build/src/options/help.jam
index b507e1edd..abab3770e 100755
--- a/tools/build/src/options/help.jam
+++ b/tools/build/src/options/help.jam
@@ -88,6 +88,16 @@ rule process (
case --help-options :
print-help-usage ;
+ local BOOST_BUILD_PATH = [ modules.peek : BOOST_BUILD_PATH ] ;
+ local plugin-dir = options ;
+ local option-files = [ GLOB $(plugin-dir:D=$(BOOST_BUILD_PATH)) : *.jam ] ;
+ if $(option-files)
+ {
+ for local file in $(option-files)
+ {
+ do-scan $(file) : print-help-options ;
+ }
+ }
did-help = true ;
case --help :
diff --git a/tools/build/src/tools/clang-linux.jam b/tools/build/src/tools/clang-linux.jam
index 668078e09..0aa29d519 100644
--- a/tools/build/src/tools/clang-linux.jam
+++ b/tools/build/src/tools/clang-linux.jam
@@ -91,7 +91,7 @@ toolset.flags clang-linux.compile OPTIONS <rtti>off : -fno-rtti ;
# C and C++ compilation
rule compile.c++ ( targets * : sources * : properties * ) {
- gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ setup-threading $(targets) : $(sources) : $(properties) ;
gcc.setup-fpic $(targets) : $(sources) : $(properties) ;
gcc.setup-address-model $(targets) : $(sources) : $(properties) ;
@@ -117,7 +117,7 @@ actions compile.c++.with-pch bind PCH_FILE
rule compile.c ( targets * : sources * : properties * )
{
- gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ setup-threading $(targets) : $(sources) : $(properties) ;
gcc.setup-fpic $(targets) : $(sources) : $(properties) ;
gcc.setup-address-model $(targets) : $(sources) : $(properties) ;
@@ -146,7 +146,7 @@ actions compile.c.with-pch bind PCH_FILE
# PCH emission
rule compile.c++.pch ( targets * : sources * : properties * ) {
- gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ setup-threading $(targets) : $(sources) : $(properties) ;
gcc.setup-fpic $(targets) : $(sources) : $(properties) ;
gcc.setup-address-model $(targets) : $(sources) : $(properties) ;
}
@@ -156,7 +156,7 @@ actions compile.c++.pch {
}
rule compile.c.pch ( targets * : sources * : properties * ) {
- gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ setup-threading $(targets) : $(sources) : $(properties) ;
gcc.setup-fpic $(targets) : $(sources) : $(properties) ;
gcc.setup-address-model $(targets) : $(sources) : $(properties) ;
}
@@ -172,7 +172,7 @@ actions compile.c.pch
SPACE = " " ;
rule link ( targets * : sources * : properties * ) {
- gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ setup-threading $(targets) : $(sources) : $(properties) ;
gcc.setup-address-model $(targets) : $(sources) : $(properties) ;
SPACE on $(targets) = " " ;
JAM_SEMAPHORE on $(targets) = <s>clang-linux-link-semaphore ;
@@ -183,12 +183,29 @@ actions link bind LIBRARIES {
}
rule link.dll ( targets * : sources * : properties * ) {
- gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ setup-threading $(targets) : $(sources) : $(properties) ;
gcc.setup-address-model $(targets) : $(sources) : $(properties) ;
SPACE on $(targets) = " " ;
JAM_SEMAPHORE on $(targets) = <s>clang-linux-link-semaphore ;
}
+rule setup-threading ( targets * : sources * : properties * )
+{
+
+ local target = [ feature.get-values target-os : $(properties) ] ;
+
+ switch $(target)
+ {
+ case windows :
+ local threading = [ feature.get-values threading : $(properties) ] ;
+ if $(threading) = multi
+ {
+ OPTIONS on $(targets) += -pthread ;
+ }
+ case * : gcc.setup-threading $(targets) : $(sources) : $(properties) ;
+ }
+}
+
# Differ from 'link' above only by -shared.
actions link.dll bind LIBRARIES {
"$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,-R$(SPACE)-Wl,"$(RPATH)" -o "$(<)" -Wl,-soname$(SPACE)-Wl,$(<[1]:D=) -shared $(START-GROUP) "$(>)" "$(LIBRARIES)" $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) $(USER_OPTIONS)
diff --git a/tools/build/src/tools/clang-win.jam b/tools/build/src/tools/clang-win.jam
new file mode 100644
index 000000000..25a6d006d
--- /dev/null
+++ b/tools/build/src/tools/clang-win.jam
@@ -0,0 +1,175 @@
+# Copyright Vladimir Prus 2004.
+# 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)
+
+# Importing common is needed because the rules we inherit here depend on it.
+# That is nasty.
+import common ;
+import errors ;
+import feature ;
+import clang ;
+import msvc ;
+import os ;
+import toolset ;
+import generators ;
+import type ;
+import path ;
+import set ;
+
+feature.extend-subfeature toolset clang : platform : win ;
+
+toolset.inherit-generators clang-win <toolset>clang <toolset-clang:platform>win : msvc ;
+toolset.inherit-flags clang-win : msvc : <debug-symbols>on/<debug-store>object <asynch-exceptions>off <asynch-exceptions>on : YLOPTION ;
+toolset.inherit-rules clang-win : msvc ;
+
+# Override default do-nothing generators.
+generators.override clang-win.compile.c.pch : pch.default-c-pch-generator ;
+generators.override clang-win.compile.c++.pch : pch.default-cpp-pch-generator ;
+generators.override clang-win.compile.rc : rc.compile.resource ;
+generators.override clang-win.compile.mc : mc.compile ;
+
+toolset.flags clang-win.compile PCH_SOURCE <pch>on : <pch-source> ;
+
+toolset.flags clang-win.compile CFLAGS <debug-symbols>on/<debug-store>object : "" ;
+
+# Initializes the intel toolset for windows
+rule init ( version ? : # the compiler version
+ command * : # the command to invoke the compiler itself
+ options * # Additional option: <compatibility>
+ # either 'vc6', 'vc7', 'vc7.1'
+ # or 'native'(default).
+ )
+{
+ local compatibility =
+ [ feature.get-values <compatibility> : $(options) ] ;
+ local condition = [ common.check-init-parameters clang-win
+ : version $(version) : compatibility $(compatibility) ] ;
+
+ if ! $(compatibility)
+ {
+ import errors ;
+ errors.error "Please set <compatibility> property for visual studio version!" ;
+ }
+ local vc_version = [ MATCH vc([0-9]+) : $(compatibility) ] ;
+ if ! $(vc_version)
+ {
+ errors.user-error "Invalid value for compatibility option:"
+ $(compatibility) ;
+ }
+
+ local m = [ MATCH ([0-9]+).* : $(version) ] ;
+ local major = $(m[1]) ;
+
+ command = [ common.get-invocation-command clang-win : clang-cl.exe :
+ $(command) ] ;
+
+ common.handle-options clang-win : $(condition) : $(command) : $(options) ;
+
+ local setup ;
+ setup = [ get-visual-studio-vcvars $(vc_version) ] ; # Get visual studio vcvars bat file path
+
+ local target_types ;
+ if [ MATCH ^(AMD64) : [ os.environ PROCESSOR_ARCHITECTURE ] ]
+ {
+ target_types = x86 amd64 ;
+ }
+ else
+ {
+ target_types = x86 x86_amd64 ;
+ }
+
+ for local c in $(target_types)
+ {
+ local cpu-conditions ;
+ local setup-call ;
+ setup-call = "call \""$(setup)"\" $(c) > nul " ;
+ cpu-conditions = $(condition)/$(.cpu-arch-$(c)) ;
+
+ if [ os.name ] = NT
+ {
+ setup-call = $(setup-call)"
+ " ;
+ }
+ else
+ {
+ setup-call = "cmd /S /C "$(setup-call)" \"&&\" " ;
+ }
+
+ if $(.debug-configuration)
+ {
+ for local cpu-condition in $(cpu-conditions)
+ {
+ ECHO "notice: [clang-cfg] condition: '$(cpu-condition)', setup: '$(setup-call)'" ;
+ }
+ }
+
+ local compiler ;
+ compiler = [ path.native $(command) ] ;
+ compiler = "\"$(compiler)\"" ;
+
+ toolset.flags clang-win.compile .CC $(cpu-conditions) : $(setup-call)$(compiler) ;
+ toolset.flags clang-win.link .LD $(cpu-conditions) : $(setup-call)link /nologo ;
+ toolset.flags clang-win.archive .LD $(cpu-conditions) : $(setup-call)link /lib /nologo ;
+ toolset.flags clang-win.link .MT $(cpu-conditions) : $(setup-call)mt -nologo ;
+ toolset.flags clang-win.compile .MC $(cpu-conditions) : $(setup-call)mc ;
+ toolset.flags clang-win.compile .RC $(cpu-conditions) : $(setup-call)rc ;
+ }
+
+
+ local C++FLAGS ;
+
+ if $(vc_version) = 10
+ {
+ C++FLAGS += -fmsc-version=1600 ;
+ }
+ else if $(vc_version) = 11
+ {
+ C++FLAGS += -fmsc-version=1700 ;
+ }
+ else if $(vc_version) = 12
+ {
+ C++FLAGS += -fmsc-version=1800 ;
+ }
+
+ toolset.flags clang-win CFLAGS $(condition) : $(C++FLAGS) ;
+
+ msvc.configure-version-specific clang-win : $(vc_version) : $(condition) ;
+}
+
+local rule get-visual-studio-vcvars ( version )
+{
+ local env_variable_name ;
+ env_variable_name = "VS"$(version:U)"0COMNTOOLS" ;
+
+ local vc-path = [ os.environ $(env_variable_name) ] ;
+ vc-path = [ path.join $(vc-path) "../../VC/vcvarsall.bat" ] ;
+ path.native $(vc-path) ;
+}
+
+
+if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
+{
+ .debug-configuration = true ;
+}
+
+# Copied from msvc.jam
+# Supported CPU architectures.
+.cpu-arch-x86 =
+ <architecture>/<address-model>
+ <architecture>/<address-model>32
+ <architecture>x86/<address-model>
+ <architecture>x86/<address-model>32 ;
+
+.cpu-arch-amd64 =
+ <architecture>/<address-model>64
+ <architecture>x86/<address-model>64 ;
+
+.cpu-arch-x86_amd64 =
+ <architecture>/<address-model>64
+ <architecture>x86/<address-model>64 ;
+
+# toolset.flags clang-win.link LIBRARY_OPTION <toolset>clang : "" ;
+
+toolset.flags clang-win YLOPTION ;
+
diff --git a/tools/build/src/tools/common.py b/tools/build/src/tools/common.py
index b1ee26f0c..63c65e4c0 100644
--- a/tools/build/src/tools/common.py
+++ b/tools/build/src/tools/common.py
@@ -173,14 +173,18 @@ def check_init_parameters(toolset, requirement, *args):
The return value from this rule is a condition to be used for flags settings.
"""
+ from b2.build import toolset as b2_toolset
+ if requirement is None:
+ requirement = []
# The type checking here is my best guess about
# what the types should be.
assert(isinstance(toolset, str))
- assert(isinstance(requirement, str) or requirement is None)
+ # iterable and not a string, allows for future support of sets
+ assert(not isinstance(requirement, basestring) and hasattr(requirement, '__contains__'))
sig = toolset
condition = replace_grist(toolset, '<toolset>')
subcondition = []
-
+
for arg in args:
assert(isinstance(arg, tuple))
assert(len(arg) == 2)
@@ -233,6 +237,11 @@ def check_init_parameters(toolset, requirement, *args):
sig = sig + value + '-'
+ # if a requirement is specified, the signature should be unique
+ # with that requirement
+ if requirement:
+ sig += '-' + '-'.join(requirement)
+
if __all_signatures.has_key(sig):
message = "duplicate initialization of '%s' with the following parameters: " % toolset
@@ -253,15 +262,15 @@ def check_init_parameters(toolset, requirement, *args):
# condition. To accomplish this we add a toolset requirement that imposes
# the toolset subcondition, which encodes the version.
if requirement:
- r = ['<toolset>' + toolset, requirement]
+ r = ['<toolset>' + toolset] + requirement
r = ','.join(r)
- toolset.add_requirements([r + ':' + c for c in subcondition])
+ b2_toolset.add_requirements([r + ':' + c for c in subcondition])
# We add the requirements, if any, to the condition to scope the toolset
# variables and options to this specific version.
condition = [condition]
if requirement:
- condition += [requirement]
+ condition += requirement
if __show_configuration:
print "notice:", condition
diff --git a/tools/build/src/tools/common_clang_vc.jam b/tools/build/src/tools/common_clang_vc.jam
new file mode 100644
index 000000000..bdf1ca874
--- /dev/null
+++ b/tools/build/src/tools/common_clang_vc.jam
@@ -0,0 +1,987 @@
+# Copyright 2003, 2005 Dave Abrahams
+# Copyright 2005, 2006 Rene Rivera
+# Copyright 2005 Toon Knapen
+# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
+# Distributed under the Boost Software License, Version 1.0.
+# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
+
+# Provides actions common to all toolsets, such as creating directories and
+# removing files.
+
+import os ;
+import modules ;
+import utility ;
+import print ;
+import type ;
+import feature ;
+import errors ;
+import path ;
+import sequence ;
+import toolset ;
+import virtual-target ;
+
+if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
+{
+ .debug-configuration = true ;
+}
+if [ MATCH (--show-configuration) : [ modules.peek : ARGV ] ]
+{
+ .show-configuration = true ;
+}
+
+# Configurations
+#
+# The following class helps to manage toolset configurations. Each configuration
+# has a unique ID and one or more parameters. A typical example of a unique ID
+# is a condition generated by 'common.check-init-parameters' rule. Other kinds
+# of IDs can be used. Parameters may include any details about the configuration
+# like 'command', 'path', etc.
+#
+# A toolset configuration may be in one of the following states:
+#
+# - registered
+# Configuration has been registered (e.g. explicitly or by auto-detection
+# code) but has not yet been marked as used, i.e. 'toolset.using' rule has
+# not yet been called for it.
+# - used
+# Once called 'toolset.using' rule marks the configuration as 'used'.
+#
+# The main difference between the states above is that while a configuration is
+# 'registered' its options can be freely changed. This is useful in particular
+# for autodetection code - all detected configurations may be safely overwritten
+# by user code.
+
+class configurations
+{
+ import errors ;
+
+ rule __init__ ( )
+ {
+ }
+
+ # Registers a configuration.
+ #
+ # Returns 'true' if the configuration has been added and an empty value if
+ # it already exists. Reports an error if the configuration is 'used'.
+ #
+ rule register ( id )
+ {
+ if $(id) in $(self.used)
+ {
+ errors.error "common: the configuration '$(id)' is in use" ;
+ }
+
+ local retval ;
+
+ if ! $(id) in $(self.all)
+ {
+ self.all += $(id) ;
+
+ # Indicate that a new configuration has been added.
+ retval = true ;
+ }
+
+ return $(retval) ;
+ }
+
+ # Mark a configuration as 'used'.
+ #
+ # Returns 'true' if the state of the configuration has been changed to
+ # 'used' and an empty value if it the state has not been changed. Reports an
+ # error if the configuration is not known.
+ #
+ rule use ( id )
+ {
+ if ! $(id) in $(self.all)
+ {
+ errors.error "common: the configuration '$(id)' is not known" ;
+ }
+
+ local retval ;
+
+ if ! $(id) in $(self.used)
+ {
+ self.used += $(id) ;
+
+ # Indicate that the configuration has been marked as 'used'.
+ retval = true ;
+ }
+
+ return $(retval) ;
+ }
+
+ # Return all registered configurations.
+ #
+ rule all ( )
+ {
+ return $(self.all) ;
+ }
+
+ # Return all used configurations.
+ #
+ rule used ( )
+ {
+ return $(self.used) ;
+ }
+
+ # Returns the value of a configuration parameter.
+ #
+ rule get ( id : param )
+ {
+ return $(self.$(param).$(id)) ;
+ }
+
+ # Sets the value of a configuration parameter.
+ #
+ rule set ( id : param : value * )
+ {
+ self.$(param).$(id) = $(value) ;
+ }
+}
+
+
+# The rule for checking toolset parameters. Trailing parameters should all be
+# parameter name/value pairs. The rule will check that each parameter either has
+# a value in each invocation or has no value in each invocation. Also, the rule
+# will check that the combination of all parameter values is unique in all
+# invocations.
+#
+# Each parameter name corresponds to a subfeature. This rule will declare a
+# subfeature the first time a non-empty parameter value is passed and will
+# extend it with all the values.
+#
+# The return value from this rule is a condition to be used for flags settings.
+#
+rule check-init-parameters ( toolset requirement * : * )
+{
+ local sig = $(toolset) ;
+ local condition = <toolset>$(toolset) ;
+ local subcondition ;
+ for local index in 2 3 4 5 6 7 8 9
+ {
+ local name = $($(index)[1]) ;
+ local value = $($(index)[2]) ;
+
+ if $(value)-is-not-empty
+ {
+ condition = $(condition)-$(value) ;
+ if $(.had-unspecified-value.$(toolset).$(name))
+ {
+ errors.user-error
+ "$(toolset) initialization: parameter '$(name)'"
+ "inconsistent" : "no value was specified in earlier"
+ "initialization" : "an explicit value is specified now" ;
+ }
+ # The below logic is for intel compiler. It calls this rule with
+ # 'intel-linux' and 'intel-win' as toolset, so we need to get the
+ # base part of toolset name. We can not pass 'intel' as toolset
+ # because in that case it will be impossible to register versionless
+ # intel-linux and intel-win toolsets of a specific version.
+ local t = $(toolset) ;
+ local m = [ MATCH ([^-]*)- : $(toolset) ] ;
+ if $(m)
+ {
+ t = $(m[1]) ;
+ }
+ if ! $(.had-value.$(toolset).$(name))
+ {
+ if ! $(.declared-subfeature.$(t).$(name))
+ {
+ feature.subfeature toolset $(t) : $(name) : : propagated ;
+ .declared-subfeature.$(t).$(name) = true ;
+ }
+ .had-value.$(toolset).$(name) = true ;
+ }
+ feature.extend-subfeature toolset $(t) : $(name) : $(value) ;
+ subcondition += <toolset-$(t):$(name)>$(value) ;
+ }
+ else
+ {
+ if $(.had-value.$(toolset).$(name))
+ {
+ errors.user-error
+ "$(toolset) initialization: parameter '$(name)'"
+ "inconsistent" : "an explicit value was specified in an"
+ "earlier initialization" : "no value is specified now" ;
+ }
+ .had-unspecified-value.$(toolset).$(name) = true ;
+ }
+ sig = $(sig)$(value:E="")- ;
+ }
+ if $(sig) in $(.all-signatures)
+ {
+ local message =
+ "duplicate initialization of $(toolset) with the following parameters: " ;
+ for local index in 2 3 4 5 6 7 8 9
+ {
+ local p = $($(index)) ;
+ if $(p)
+ {
+ message += "$(p[1]) = $(p[2]:E=<unspecified>)" ;
+ }
+ }
+ message += "previous initialization at $(.init-loc.$(sig))" ;
+ errors.user-error
+ $(message[1]) : $(message[2]) : $(message[3]) : $(message[4]) :
+ $(message[5]) : $(message[6]) : $(message[7]) : $(message[8]) ;
+ }
+ .all-signatures += $(sig) ;
+ .init-loc.$(sig) = [ errors.nearest-user-location ] ;
+
+ # If we have a requirement, this version should only be applied under that
+ # condition. To accomplish this we add a toolset requirement that imposes
+ # the toolset subcondition, which encodes the version.
+ if $(requirement)
+ {
+ local r = <toolset>$(toolset) $(requirement) ;
+ r = $(r:J=,) ;
+ toolset.add-requirements $(r):$(subcondition) ;
+ }
+
+ # We add the requirements, if any, to the condition to scope the toolset
+ # variables and options to this specific version.
+ condition += $(requirement) ;
+
+ if $(.show-configuration)
+ {
+ ECHO notice: $(condition) ;
+ }
+ return $(condition:J=/) ;
+}
+
+
+# A helper rule to get the command to invoke some tool. If
+# 'user-provided-command' is not given, tries to find binary named 'tool' in
+# PATH and in the passed 'additional-path'. Otherwise, verifies that the first
+# element of 'user-provided-command' is an existing program.
+#
+# This rule returns the command to be used when invoking the tool. If we can not
+# find the tool, a warning is issued. If 'path-last' is specified, PATH is
+# checked after 'additional-paths' when searching for 'tool'.
+#
+rule get-invocation-command-nodefault ( toolset : tool :
+ user-provided-command * : additional-paths * : path-last ? )
+{
+ local command ;
+ if ! $(user-provided-command)
+ {
+ command = [ find-tool $(tool) : $(additional-paths) : $(path-last) ] ;
+ if ! $(command) && $(.debug-configuration)
+ {
+ ECHO warning: toolset $(toolset) initialization: can not find tool
+ $(tool) ;
+ ECHO warning: initialized from [ errors.nearest-user-location ] ;
+ }
+ }
+ else
+ {
+ command = [ check-tool $(user-provided-command) ] ;
+ if ! $(command) && $(.debug-configuration)
+ {
+ ECHO warning: toolset $(toolset) initialization: ;
+ ECHO warning: can not find user-provided command
+ '$(user-provided-command)' ;
+ ECHO warning: initialized from [ errors.nearest-user-location ] ;
+ }
+ }
+
+ return $(command) ;
+}
+
+
+# Same as get-invocation-command-nodefault, except that if no tool is found,
+# returns either the user-provided-command, if present, or the 'tool' parameter.
+#
+rule get-invocation-command ( toolset : tool : user-provided-command * :
+ additional-paths * : path-last ? )
+{
+ local result = [ get-invocation-command-nodefault $(toolset) : $(tool) :
+ $(user-provided-command) : $(additional-paths) : $(path-last) ] ;
+
+ if ! $(result)
+ {
+ if $(user-provided-command)
+ {
+ result = $(user-provided-command) ;
+ }
+ else
+ {
+ result = $(tool) ;
+ }
+ }
+ return $(result) ;
+}
+
+
+# Given an invocation command return the absolute path to the command. This
+# works even if command has no path element and was found on the PATH.
+#
+rule get-absolute-tool-path ( command )
+{
+ if $(command:D)
+ {
+ return $(command:D) ;
+ }
+ else
+ {
+ local m = [ GLOB [ modules.peek : PATH Path path ] : $(command)
+ $(command).exe ] ;
+ return $(m[1]:D) ;
+ }
+}
+
+
+# Attempts to find tool (binary) named 'name' in PATH and in 'additional-paths'.
+# If found in PATH, returns 'name' and if found in additional paths, returns
+# absolute name. If the tool is found in several directories, returns the first
+# path found. Otherwise, returns an empty string. If 'path-last' is specified,
+# PATH is searched after 'additional-paths'.
+#
+rule find-tool ( name : additional-paths * : path-last ? )
+{
+ local path = [ path.programs-path ] ;
+ local match = [ path.glob $(path) : $(name) $(name).exe ] ;
+ local additional-match = [ path.glob $(additional-paths) : $(name)
+ $(name).exe ] ;
+
+ local result ;
+ if $(path-last)
+ {
+ result = $(additional-match) ;
+ if ! $(result) && $(match)
+ {
+ result = $(name) ;
+ }
+ }
+ else
+ {
+ if $(match)
+ {
+ result = $(name) ;
+ }
+ else
+ {
+ result = $(additional-match) ;
+ }
+ }
+ if $(result)
+ {
+ return [ path.native $(result[1]) ] ;
+ }
+}
+
+
+# Checks if 'command' can be found either in path or is a full name to an
+# existing file.
+#
+local rule check-tool-aux ( command )
+{
+ if $(command:D)
+ {
+ if [ path.exists $(command) ]
+ # Both NT and Cygwin will run .exe files by their unqualified names.
+ || ( [ os.on-windows ] && [ path.exists $(command).exe ] )
+ # Only NT will run .bat & .cmd files by their unqualified names.
+ || ( ( [ os.name ] = NT ) && ( [ path.exists $(command).bat ] ||
+ [ path.exists $(command).cmd ] ) )
+ {
+ return $(command) ;
+ }
+ }
+ else
+ {
+ if [ GLOB [ modules.peek : PATH Path path ] : $(command) ]
+ {
+ return $(command) ;
+ }
+ }
+}
+
+
+# Checks that a tool can be invoked by 'command'. If command is not an absolute
+# path, checks if it can be found in 'path'. If comand is an absolute path,
+# check that it exists. Returns 'command' if ok or empty string otherwise.
+#
+local rule check-tool ( xcommand + )
+{
+ if [ check-tool-aux $(xcommand[1]) ] ||
+ [ check-tool-aux $(xcommand[-1]) ]
+ {
+ return $(xcommand) ;
+ }
+}
+
+
+# Handle common options for toolset, specifically sets the following flag
+# variables:
+# - CONFIG_COMMAND to $(command)
+# - OPTIONS for compile to the value of <compileflags> in $(options)
+# - OPTIONS for compile.c to the value of <cflags> in $(options)
+# - OPTIONS for compile.c++ to the value of <cxxflags> in $(options)
+# - OPTIONS for compile.fortran to the value of <fflags> in $(options)
+# - OPTIONS for link to the value of <linkflags> in $(options)
+#
+rule handle-options ( toolset : condition * : command * : options * )
+{
+ if $(.debug-configuration)
+ {
+ ECHO notice: will use '$(command)' for $(toolset), condition
+ $(condition:E=(empty)) ;
+ }
+
+ # The last parameter ('unchecked') says it is OK to set flags for another
+ # module.
+ toolset.flags $(toolset) CONFIG_COMMAND $(condition) : $(command)
+ : unchecked ;
+
+ toolset.flags $(toolset).compile OPTIONS $(condition) :
+ [ feature.get-values <compileflags> : $(options) ] : unchecked ;
+
+ toolset.flags $(toolset).compile.c OPTIONS $(condition) :
+ [ feature.get-values <cflags> : $(options) ] : unchecked ;
+
+ toolset.flags $(toolset).compile.c++ OPTIONS $(condition) :
+ [ feature.get-values <cxxflags> : $(options) ] : unchecked ;
+
+ toolset.flags $(toolset).compile.fortran OPTIONS $(condition) :
+ [ feature.get-values <fflags> : $(options) ] : unchecked ;
+
+ toolset.flags $(toolset).link OPTIONS $(condition) :
+ [ feature.get-values <linkflags> : $(options) ] : unchecked ;
+}
+
+
+# Returns the location of the "program files" directory on a Windows platform.
+#
+rule get-program-files-dir ( )
+{
+ local ProgramFiles = [ modules.peek : ProgramFiles ] ;
+ if $(ProgramFiles)
+ {
+ ProgramFiles = "$(ProgramFiles:J= )" ;
+ }
+ else
+ {
+ ProgramFiles = "c:\\Program Files" ;
+ }
+ return $(ProgramFiles) ;
+}
+
+
+if [ os.name ] = NT
+{
+ RM = del /f /q ;
+ CP = copy /b ;
+ IGNORE = "2>nul >nul & setlocal" ;
+ LN ?= $(CP) ;
+ # Ugly hack to convince copy to set the timestamp of the destination to the
+ # current time by concatenating the source with a nonexistent file. Note
+ # that this requires /b (binary) as the default when concatenating files is
+ # /a (ascii).
+ WINDOWS-CP-HACK = "+ this-file-does-not-exist-A698EE7806899E69" ;
+}
+else
+{
+ RM = rm -f ;
+ CP = cp ;
+ LN = ln ;
+}
+
+
+rule rm-command ( )
+{
+ return $(RM) ;
+}
+
+
+rule copy-command ( )
+{
+ return $(CP) ;
+}
+
+
+if "\n" = "n"
+{
+ # Escape characters not supported so use ugly hacks. Will not work on Cygwin
+ # - see below.
+ nl = "
+" ;
+ q = "" ;
+}
+else
+{
+ nl = "\n" ;
+ q = "\"" ;
+}
+
+# Returns the command needed to set an environment variable on the current
+# platform. The variable setting persists through all following commands and is
+# visible in the environment seen by subsequently executed commands. In other
+# words, on Unix systems, the variable is exported, which is consistent with the
+# only possible behavior on Windows systems.
+#
+rule variable-setting-command ( variable : value )
+{
+ if [ os.name ] = NT
+ {
+ return "set $(variable)=$(value)$(nl)" ;
+ }
+ else
+ {
+ # If we do not have escape character support in bjam, the cod below
+ # blows up on CYGWIN, since the $(nl) variable holds a Windows new-line
+ # \r\n sequence that messes up the executed export command which then
+ # reports that the passed variable name is incorrect.
+ # But we have a check for cygwin in kernel/bootstrap.jam already.
+ return "$(variable)=$(q)$(value)$(q)$(nl)export $(variable)$(nl)" ;
+ }
+}
+
+
+# Returns a command to sets a named shell path variable to the given NATIVE
+# paths on the current platform.
+#
+rule path-variable-setting-command ( variable : paths * )
+{
+ local sep = [ os.path-separator ] ;
+ return [ variable-setting-command $(variable) : $(paths:J=$(sep)) ] ;
+}
+
+
+# Returns a command that prepends the given paths to the named path variable on
+# the current platform.
+#
+rule prepend-path-variable-command ( variable : paths * )
+{
+ return [ path-variable-setting-command $(variable)
+ : $(paths) [ os.expand-variable $(variable) ] ] ;
+}
+
+
+# Return a command which can create a file. If 'r' is result of invocation, then
+# 'r foobar' will create foobar with unspecified content. What happens if file
+# already exists is unspecified.
+#
+rule file-creation-command ( )
+{
+ if [ os.name ] = NT
+ {
+ # A few alternative implementations on Windows:
+ #
+ # 'type NUL >> '
+ # That would construct an empty file instead of a file containing
+ # a space and an end-of-line marker but it would also not change
+ # the target's timestamp in case the file already exists.
+ #
+ # 'type NUL > '
+ # That would construct an empty file instead of a file containing
+ # a space and an end-of-line marker but it would also destroy an
+ # already existing file by overwriting it with an empty one.
+ #
+ # I guess the best solution would be to allow Boost Jam to define
+ # built-in functions such as 'create a file', 'touch a file' or 'copy a
+ # file' which could be used from inside action code. That would allow
+ # completely portable operations without this kind of kludge.
+ # (22.02.2009.) (Jurko)
+ return "echo. > " ;
+ }
+ else
+ {
+ return "touch " ;
+ }
+}
+
+
+# Returns a command that may be used for 'touching' files. It is not a real
+# 'touch' command on NT because it adds an empty line at the end of file but it
+# works with source files.
+#
+rule file-touch-command ( )
+{
+ if [ os.name ] = NT
+ {
+ return "echo. >> " ;
+ }
+ else
+ {
+ return "touch " ;
+ }
+}
+
+
+rule MkDir
+{
+ # If dir exists, do not update it. Do this even for $(DOT).
+ NOUPDATE $(<) ;
+
+ if $(<) != $(DOT) && ! $($(<)-mkdir)
+ {
+ # Cheesy gate to prevent multiple invocations on same dir.
+ $(<)-mkdir = true ;
+
+ # Schedule the mkdir build action.
+ common.mkdir $(<) ;
+
+ # Prepare a Jam 'dirs' target that can be used to make the build only
+ # construct all the target directories.
+ DEPENDS dirs : $(<) ;
+
+ # Recursively create parent directories. $(<:P) = $(<)'s parent & we
+ # recurse until root.
+
+ local s = $(<:P) ;
+ if [ os.name ] = NT
+ {
+ switch $(s)
+ {
+ case *: : s = ;
+ case *:\\ : s = ;
+ }
+ }
+
+ if $(s)
+ {
+ if $(s) != $(<)
+ {
+ DEPENDS $(<) : $(s) ;
+ MkDir $(s) ;
+ }
+ else
+ {
+ NOTFILE $(s) ;
+ }
+ }
+ }
+}
+
+
+#actions MkDir1
+#{
+# mkdir "$(<)"
+#}
+
+# The following quick-fix actions should be replaced using the original MkDir1
+# action once Boost Jam gets updated to correctly detect different paths leading
+# up to the same filesystem target and triggers their build action only once.
+# (todo) (04.07.2008.) (Jurko)
+
+if [ os.name ] = NT
+{
+ actions mkdir
+ {
+ if not exist "$(<)\\" mkdir "$(<)"
+ }
+}
+else
+{
+ actions mkdir
+ {
+ mkdir -p "$(<)"
+ }
+}
+
+actions piecemeal together existing Clean
+{
+ $(RM) "$(>)"
+}
+
+
+rule copy
+{
+}
+
+
+actions copy
+{
+ $(CP) "$(>)" $(WINDOWS-CP-HACK) "$(<)"
+}
+
+
+rule RmTemps
+{
+}
+
+
+actions quietly updated piecemeal together RmTemps
+{
+ $(RM) "$(>)" $(IGNORE)
+}
+
+
+actions hard-link
+{
+ $(RM) "$(<)" 2$(NULL_OUT) $(NULL_OUT)
+ $(LN) "$(>)" "$(<)" $(NULL_OUT)
+}
+
+
+# Given a target, as given to a custom tag rule, returns a string formatted
+# according to the passed format. Format is a list of properties that is
+# represented in the result. For each element of format the corresponding target
+# information is obtained and added to the result string. For all, but the
+# literal, the format value is taken as the as string to prepend to the output
+# to join the item to the rest of the result. If not given "-" is used as a
+# joiner.
+#
+# The format options can be:
+#
+# <base>[joiner]
+# :: The basename of the target name.
+# <toolset>[joiner]
+# :: The abbreviated toolset tag being used to build the target.
+# <threading>[joiner]
+# :: Indication of a multi-threaded build.
+# <runtime>[joiner]
+# :: Collective tag of the build runtime.
+# <version:/version-feature | X.Y[.Z]/>[joiner]
+# :: Short version tag taken from the given "version-feature" in the
+# build properties. Or if not present, the literal value as the
+# version number.
+# <property:/property-name/>[joiner]
+# :: Direct lookup of the given property-name value in the build
+# properties. /property-name/ is a regular expression. E.g.
+# <property:toolset-.*:flavor> will match every toolset.
+# /otherwise/
+# :: The literal value of the format argument.
+#
+# For example this format:
+#
+# boost_ <base> <toolset> <threading> <runtime> <version:boost-version>
+#
+# Might return:
+#
+# boost_thread-vc80-mt-gd-1_33.dll, or
+# boost_regex-vc80-gd-1_33.dll
+#
+# The returned name also has the target type specific prefix and suffix which
+# puts it in a ready form to use as the value from a custom tag rule.
+#
+rule format-name ( format * : name : type ? : property-set )
+{
+ local result = "" ;
+ for local f in $(format)
+ {
+ switch $(f:G)
+ {
+ case <base> :
+ result += $(name:B) ;
+
+ case <toolset> :
+ result += [ join-tag $(f:G=) : [ toolset-tag $(name) : $(type) :
+ $(property-set) ] ] ;
+
+ case <threading> :
+ result += [ join-tag $(f:G=) : [ threading-tag $(name) : $(type)
+ : $(property-set) ] ] ;
+
+ case <runtime> :
+ result += [ join-tag $(f:G=) : [ runtime-tag $(name) : $(type) :
+ $(property-set) ] ] ;
+
+ case <qt> :
+ result += [ join-tag $(f:G=) : [ qt-tag $(name) : $(type) :
+ $(property-set) ] ] ;
+
+ case <address-model> :
+ result += [ join-tag $(f:G=) : [ address-model-tag $(name) :
+ $(type) : $(property-set) ] ] ;
+
+ case <version:*> :
+ local key = [ MATCH <version:(.*)> : $(f:G) ] ;
+ local version = [ $(property-set).get <$(key)> ] ;
+ version ?= $(key) ;
+ version = [ MATCH "^([^.]+)[.]([^.]+)[.]?([^.]*)" : $(version) ] ;
+ result += [ join-tag $(f:G=) : $(version[1])_$(version[2]) ] ;
+
+ case <property:*> :
+ local key = [ MATCH <property:(.*)> : $(f:G) ] ;
+ local p0 = [ MATCH <($(key))> : [ $(property-set).raw ] ] ;
+ if $(p0)
+ {
+ local p = [ $(property-set).get <$(p0)> ] ;
+ if $(p)
+ {
+ result += [ join-tag $(f:G=) : $(p) ] ;
+ }
+ }
+
+ case * :
+ result += $(f:G=) ;
+ }
+ }
+ return [ virtual-target.add-prefix-and-suffix $(result:J=) : $(type) :
+ $(property-set) ] ;
+}
+
+
+local rule join-tag ( joiner ? : tag ? )
+{
+ if ! $(joiner) { joiner = - ; }
+ return $(joiner)$(tag) ;
+}
+
+
+local rule toolset-tag ( name : type ? : property-set )
+{
+ local tag = ;
+
+ local properties = [ $(property-set).raw ] ;
+ switch [ $(property-set).get <toolset> ]
+ {
+ case borland* : tag += bcb ;
+ case clang* :
+ {
+ switch [ $(property-set).get <toolset-clang:platform> ]
+ {
+ case darwin : tag += clang-darwin ;
+ case linux : tag += clang ;
+ case win : tag += clang-win ;
+ }
+ }
+ case como* : tag += como ;
+ case cw : tag += cw ;
+ case darwin* : tag += xgcc ;
+ case edg* : tag += edg ;
+ case gcc* :
+ {
+ switch [ $(property-set).get <toolset-gcc:flavor> ]
+ {
+ case *mingw* : tag += mgw ;
+ case * : tag += gcc ;
+ }
+ }
+ case intel :
+ if [ $(property-set).get <toolset-intel:platform> ] = win
+ {
+ tag += iw ;
+ }
+ else
+ {
+ tag += il ;
+ }
+ case kcc* : tag += kcc ;
+ case kylix* : tag += bck ;
+ #case metrowerks* : tag += cw ;
+ #case mingw* : tag += mgw ;
+ case mipspro* : tag += mp ;
+ case msvc* : tag += vc ;
+ case qcc* : tag += qcc ;
+ case sun* : tag += sw ;
+ case tru64cxx* : tag += tru ;
+ case vacpp* : tag += xlc ;
+ }
+ local version = [ MATCH <toolset.*version>([0123456789]+)[.]([0123456789]*)
+ : $(properties) ] ;
+ # For historical reasons, vc6.0 and vc7.0 use different naming.
+ if $(tag) = vc
+ {
+ if $(version[1]) = 6
+ {
+ # Cancel minor version.
+ version = 6 ;
+ }
+ else if $(version[1]) = 7 && $(version[2]) = 0
+ {
+ version = 7 ;
+ }
+ }
+ # On intel, version is not added, because it does not matter and it is the
+ # version of vc used as backend that matters. Ideally, we should encode the
+ # backend version but that would break compatibility with V1.
+ if $(tag) = iw
+ {
+ version = ;
+ }
+ if $(tag) = clang-win
+ {
+ local my_tmp = [ $(property-set).get <toolset-clang:compatibility> ] ;
+ version = $(version[1])_$(version[2])_$(my_tmp) ;
+ }
+
+ # On borland, version is not added for compatibility with V1.
+ if $(tag) = bcb
+ {
+ version = ;
+ }
+
+ tag += $(version) ;
+
+ return $(tag:J=) ;
+}
+
+
+local rule threading-tag ( name : type ? : property-set )
+{
+ if <threading>multi in [ $(property-set).raw ]
+ {
+ return mt ;
+ }
+}
+
+
+local rule runtime-tag ( name : type ? : property-set )
+{
+ local tag = ;
+
+ local properties = [ $(property-set).raw ] ;
+ if <runtime-link>static in $(properties) { tag += s ; }
+
+ # This is an ugly thing. In V1, there is code to automatically detect which
+ # properties affect a target. So, if <runtime-debugging> does not affect gcc
+ # toolset, the tag rules will not even see <runtime-debugging>. Similar
+ # functionality in V2 is not implemented yet, so we just check for toolsets
+ # known to care about runtime debugging.
+ if ( <toolset>msvc in $(properties) ) ||
+ ( <stdlib>stlport in $(properties) ) ||
+ ( <toolset-intel:platform>win in $(properties) )
+ {
+ if <runtime-debugging>on in $(properties) { tag += g ; }
+ }
+
+ if <python-debugging>on in $(properties) { tag += y ; }
+ if <variant>debug in $(properties) { tag += d ; }
+ if <stdlib>stlport in $(properties) { tag += p ; }
+ if <stdlib-stlport:iostream>hostios in $(properties) { tag += n ; }
+
+ return $(tag:J=) ;
+}
+
+
+# Create a tag for the Qt library version
+# "<qt>4.6.0" will result in tag "qt460"
+local rule qt-tag ( name : type ? : property-set )
+{
+ local v = [ MATCH ([0123456789]+)[.]?([0123456789]*)[.]?([0123456789]*) :
+ [ $(property-set).get <qt> ] ] ;
+ return qt$(v:J=) ;
+}
+
+
+# Create a tag for the address-model
+# <address-model>64 will simply generate "64"
+local rule address-model-tag ( name : type ? : property-set )
+{
+ return [ $(property-set).get <address-model> ] ;
+}
+
+
+rule __test__ ( )
+{
+ import assert ;
+
+ local save-os = [ modules.peek os : .name ] ;
+
+ modules.poke os : .name : LINUX ;
+ assert.result "PATH=\"foo:bar:baz\"\nexport PATH\n"
+ : path-variable-setting-command PATH : foo bar baz ;
+ assert.result "PATH=\"foo:bar:$PATH\"\nexport PATH\n"
+ : prepend-path-variable-command PATH : foo bar ;
+
+ modules.poke os : .name : NT ;
+ assert.result "set PATH=foo;bar;baz\n"
+ : path-variable-setting-command PATH : foo bar baz ;
+ assert.result "set PATH=foo;bar;%PATH%\n"
+ : prepend-path-variable-command PATH : foo bar ;
+
+ modules.poke os : .name : $(save-os) ;
+}
diff --git a/tools/build/src/tools/cray.jam b/tools/build/src/tools/cray.jam
index 1fa1ddc01..a64f1080a 100644
--- a/tools/build/src/tools/cray.jam
+++ b/tools/build/src/tools/cray.jam
@@ -69,14 +69,11 @@ flags cray.compile DEFINES <define> ;
flags cray.compile INCLUDES <include> ;
flags cray.link OPTIONS <linkflags> ;
-# flags cray.compile OPTIONS : -hgnu -fPIC -h system_alloc -h tolerant -h ipa0 ;
-flags cray.compile OPTIONS : -march=bdver1 -mfpmath=sse -mfma4 -mavx -funroll-all-loops -mprefer-avx128 -fprefetch-loop-arrays --param prefetch-latency=300 -minline-all-stringops -ffast-math -fno-finite-math-only ;
+flags cray.compile OPTIONS : -hgnu -fPIC -h system_alloc -h tolerant -h ipa0 ;
flags cray.compile OPTIONS <link>shared : -dynamic ;
flags cray.compile OPTIONS <link>static : -static ;
-# flags cray.link OPTIONS <link>static : -static ;
-# flags cray.link OPTIONS <link>shared ;
-flags cray.link OPTIONS <link>static : -static -march=bdver1 -mfpmath=sse -mfma4 -mavx -funroll-all-loops -mprefer-avx128 -fprefetch-loop-arrays --param prefetch-latency=300 -minline-all-stringops -ffast-math -fno-finite-math-only -Xlinker --allow-multiple-definition ;
-flags cray.link OPTIONS <link>shared : -march=bdver1 -mfpmath=sse -mfma4 -mavx -funroll-all-loops -mprefer-avx128 -fprefetch-loop-arrays --param prefetch-latency=300 -minline-all-stringops -ffast-math -fno-finite-math-only -Xlinker --allow-multiple-definition ;
+flags cray.link OPTIONS <link>static : -static ;
+flags cray.link OPTIONS <link>shared ;
flags cray.link LOPTIONS <link>shared : -dynamic ;
flags cray.link LIBPATH <library-path> ;
diff --git a/tools/build/src/tools/docutils.jam b/tools/build/src/tools/docutils.jam
index fc775b6fc..02b2794b2 100644
--- a/tools/build/src/tools/docutils.jam
+++ b/tools/build/src/tools/docutils.jam
@@ -13,6 +13,7 @@ import toolset ;
import path ;
import feature : feature ;
import property ;
+import errors ;
.initialized = ;
@@ -65,6 +66,19 @@ rule html ( target : source : properties * )
if ! [ on $(target) return $(RST2XXX) ]
{
local python-cmd = [ property.select <python.interpreter> : $(properties) ] ;
+ if ! $(.tools-dir) {
+ errors.user-error
+ "The docutils module is used, but not configured. "
+ : ""
+ : "Please modify your user-config.jam or project-config.jam to contain:"
+ : ""
+ : " using docutils : <docutils-dir> ;"
+ : ""
+ : "On Ubuntu, 'docutils-common' package will create /usr/share/docutils."
+ : "Other flavours of Linux likely have docutils as package as well."
+ : "On Windows, you can install from http://docutils.sourceforge.net/."
+ ;
+ }
RST2XXX on $(target) = $(python-cmd:G=:E="python") $(.tools-dir)/rst2html.py ;
}
}
diff --git a/tools/build/src/tools/gcc.jam b/tools/build/src/tools/gcc.jam
index 599e20ff7..ce9be9d6d 100644
--- a/tools/build/src/tools/gcc.jam
+++ b/tools/build/src/tools/gcc.jam
@@ -790,12 +790,16 @@ rule init-link-flags ( toolset linker condition )
# searched during load-time. Note that the AIX linker does not have an
# -soname equivalent, this is as close as it gets.
#
+ # The -bbigtoc option instrcuts the linker to create a TOC bigger than 64k.
+ # This is neccesary for some submodules such as math, but it does make running
+ # the tests a tad slower.
+ #
# The above options are definately for AIX 5.x, and most likely also for
# AIX 4.x and AIX 6.x. For details about the AIX linker see:
# http://download.boulder.ibm.com/ibmdl/pub/software/dw/aix/es-aix_ll.pdf
#
- toolset.flags $(toolset).link OPTIONS : -Wl,-brtl -Wl,-bnoipath
+ toolset.flags $(toolset).link OPTIONS : -Wl,-brtl -Wl,-bnoipath -Wl,-bbigtoc
: unchecked ;
case darwin :
@@ -1182,4 +1186,4 @@ cpu-flags gcc OPTIONS : power : rios2 : -mcpu=rios2 ;
cpu-flags gcc OPTIONS : power : rsc : -mcpu=rsc ;
cpu-flags gcc OPTIONS : power : rs64a : -mcpu=rs64 ;
# AIX variant of RS/6000 & PowerPC
-toolset.flags gcc AROPTIONS <address-model>64/<target-os>aix : "-X 64" ;
+toolset.flags gcc AROPTIONS <address-model>64/<target-os>aix : "-X64" ;
diff --git a/tools/build/src/tools/gcc.py b/tools/build/src/tools/gcc.py
index c2f3b0206..97f1e79d4 100644
--- a/tools/build/src/tools/gcc.py
+++ b/tools/build/src/tools/gcc.py
@@ -176,6 +176,13 @@ def init(version = None, command = None, options = None):
if debug():
print 'notice: using gcc archiver ::', condition, '::', archiver
+ # - Ranlib
+ ranlib = common.get_invocation_command('gcc',
+ 'ranlib', feature.get_values('<ranlib>', options), [bin], path_last=True)
+ toolset.flags('gcc.archive', '.RANLIB', condition, [ranlib])
+ if debug():
+ print 'notice: using gcc archiver ::', condition, '::', ranlib
+
# - The resource compiler.
rc_command = common.get_invocation_command_nodefault('gcc',
'windres', feature.get_values('<rc>', options), [bin], path_last=True)
@@ -639,7 +646,9 @@ def gcc_archive(targets, sources, properties):
# The letter 'c' suppresses the warning in case the archive does not exists yet.
# That warning is produced only on some platforms, for whatever reasons.
engine.register_action('gcc.archive',
- '"$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"',
+ '''"$(.AR)" $(AROPTIONS) rc "$(<)" "$(>)"
+ "$(.RANLIB)" "$(<)"
+ ''',
function=gcc_archive,
flags=['piecemeal'])
@@ -830,4 +839,4 @@ cpu_flags('gcc', 'OPTIONS', 'power', 'rs64a', ['-mcpu=rs64'])
# AIX variant of RS/6000 & PowerPC
flags('gcc', 'OPTIONS', ['<architecture>power/<address-model>32/<target-os>aix'], ['-maix32'])
flags('gcc', 'OPTIONS', ['<architecture>power/<address-model>64/<target-os>aix'], ['-maix64'])
-flags('gcc', 'AROPTIONS', ['<architecture>power/<address-model>64/<target-os>aix'], ['-X 64'])
+flags('gcc', 'AROPTIONS', ['<architecture>power/<address-model>64/<target-os>aix'], ['-X64'])
diff --git a/tools/build/src/tools/intel-win.jam b/tools/build/src/tools/intel-win.jam
index 81e43dacd..bccdb1fa3 100644
--- a/tools/build/src/tools/intel-win.jam
+++ b/tools/build/src/tools/intel-win.jam
@@ -141,6 +141,7 @@ local rule configure ( version ? : command * : options * )
local rule configure-really ( version ? : command * : options * : compatibility )
{
+ local rewrite-setupscript = [ feature.get-values <rewrite-setup-scripts> : $(options) ] ;
local condition = [ common.check-init-parameters intel-win
: version $(version) : compatibility $(compatibility) ] ;
@@ -175,7 +176,7 @@ local rule configure-really ( version ? : command * : options * : compatibility
}
local setup ;
- setup = [ GLOB $(root) : iclvars_*.bat ] ;
+ setup = [ path.glob $(root) : iclvars_*.bat ] ;
if ! $(setup)
{
setup = [ path.join $(root) "iclvars.bat" ] ;
@@ -200,7 +201,14 @@ local rule configure-really ( version ? : command * : options * : compatibility
{
errors.error "Don't know what parameter to pass for vc version ( $(compatibility) )" ;
}
- if [ MATCH ^(AMD64) : [ os.environ PROCESSOR_ARCHITECTURE ] ]
+ # There are two possible paths for the 64-bit intel compiler,
+ # one for the IA32-Intel64 cross compiler, and one for the native
+ # 64 bit compiler. We prefer the latter one if it's installed,
+ # and don't rely on whether the OS reports whether we're 64 or 32 bit
+ # as that really only tells us which subsystem bjam is running in:
+ #
+ local intel64_path = [ path.join $(root) intel64 ] ;
+ if [ path.glob $(intel64_path) : icl.exe ]
{
target_types = ia32 intel64 ;
}
@@ -226,7 +234,8 @@ local rule configure-really ( version ? : command * : options * : compatibility
local setup-call ;
if $(major) >= 12
{
- setup-call = "call \""$(setup)"\" $(c) $(iclvars_vs_arg) > nul " ;
+ local t = [ msvc.maybe-rewrite-setup intel-win : "\"$(setup)\"" : "$(c) $(iclvars_vs_arg)" : $(version) : $(rewrite-setupscript) ] ;
+ setup-call = "call $(t) > nul " ;
cpu-conditions = $(condition)/$(.cpu-arch-$(c)) ;
}
else
@@ -354,6 +363,7 @@ local rule configure-really ( version ? : command * : options * : compatibility
compatibility = vc7.1 ;
}
+ msvc-version = [ msvc.resolve-possible-msvc-version-alias $(msvc-version) ] ;
msvc.configure-version-specific intel-win : $(msvc-version) : $(condition) ;
}
@@ -463,6 +473,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
.iclvars-12.1-supported-vcs = "10.0 9.0 8.0" ;
.iclvars-13.0-supported-vcs = "11.0 10.0 9.0" ;
.iclvars-14.0-supported-vcs = "12.0 11.0 10.0 9.0" ;
+.iclvars-15.0-supported-vcs = "12.0 11.0 10.0 9.0" ;
.iclvars-version-alias-vc12 = vs2013 ;
.iclvars-version-alias-vc11 = vs2012 ;
.iclvars-version-alias-vc10 = vs2010 ;
diff --git a/tools/build/src/tools/midl.py b/tools/build/src/tools/midl.py
index 43bcdf6fe..86c1f34b6 100644
--- a/tools/build/src/tools/midl.py
+++ b/tools/build/src/tools/midl.py
@@ -22,7 +22,7 @@ type.register('IDL', ['idl'])
# to resources of an application (.rc). In order to be found by a resource
# compiler its target type should be derived from 'H' - otherwise
# the property '<implicit-dependency>' will be ignored.
-type.register('MSTYPELIB', 'tlb', 'H')
+type.register('MSTYPELIB', ['tlb'], 'H')
# Register scanner for MIDL files
class MidlScanner(scanner.Scanner):
diff --git a/tools/build/src/tools/msvc.jam b/tools/build/src/tools/msvc.jam
index 65feebdea..7fbe0f2e1 100644
--- a/tools/build/src/tools/msvc.jam
+++ b/tools/build/src/tools/msvc.jam
@@ -5,6 +5,7 @@
# Copyright (c) 2006 Ilya Sokolov
# Copyright (c) 2007 Rene Rivera
# Copyright (c) 2008 Jurko Gospodnetic
+# Copyright (c) 2014 Microsoft Corporation
#
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
@@ -32,12 +33,14 @@ import path ;
import pch ;
import property ;
import rc ;
+import set ;
import toolset ;
import type ;
type.register MANIFEST : manifest ;
feature.feature embed-manifest : on off : incidental propagated ;
+feature.feature embed-manifest-file : : free dependency ;
type.register PDB : pdb ;
@@ -127,9 +130,19 @@ rule init (
# <setup-i386>
# <setup-ia64>
# <setup-arm>
+ # <setup-phone-i386>
+ # <setup-phone-arm>
# Platform specific setup command to invoke before running any of the
# msvc tools used when builing a target for a specific platform, e.g.
# when building a 32 or 64 bit executable.
+ #
+ # <rewrite-setup-scripts>
+ # Whether to rewrite setup scripts. New scripts will be output in
+ # TEMP directory and will be used instead of originals in build actions.
+ # Possible values:
+ # * on - rewrite scripts, if they do not already exist (default)
+ # * always - always rewrite scripts, even if they already exist
+ # * off - use original setup scripts
: options *
)
{
@@ -268,9 +281,29 @@ rule configure-version-specific ( toolset : version : conditions )
# dependencies to put there.
toolset.flags $(toolset).link LINKFLAGS $(conditions) : /MANIFEST ;
}
+
+ # Starting with Visual Studio 2013 the CRT is split into a desktop and app dll.
+ #If targeting WinRT and 12.0 set lib path to link against app CRT.
+ if [ MATCH "(12)" : $(version) ]
+ {
+ local VCPath = [ path.parent [ path.make [ default-path $(version) ] ] ] ;
+ local storeLibPath = [ path.join [ path.join $(VCPath) "lib" ] "store" ] ;
+ toolset.flags $(toolset).link LINKPATH $(conditions)/<windows-api>store/$(.cpu-arch-i386) : [ path.native $(storeLibPath) ] ;
+ toolset.flags $(toolset).link LINKPATH $(conditions)/<windows-api>store/$(.cpu-arch-amd64) : [ path.native [ path.join $(storeLibPath) "amd64" ] ] ;
+ toolset.flags $(toolset).link LINKPATH $(conditions)/<windows-api>store/$(.cpu-arch-arm) : [ path.native [ path.join $(storeLibPath) "arm" ] ] ;
+ }
+
toolset.pop-checking-for-flags-module ;
}
+# Feature for handling targeting different Windows API sets.
+feature.feature windows-api : desktop store phone : propagated composite link-incompatible ;
+feature.compose <windows-api>store : <define>WINAPI_FAMILY=WINAPI_FAMILY_APP <define>_WIN32_WINNT=0x0602
+ <linkflags>/APPCONTAINER ;
+feature.compose <windows-api>phone : <define>WINAPI_FAMILY=WINAPI_FAMILY_PHONE_APP <define>_WIN32_WINNT=0x0602
+ <linkflags>/APPCONTAINER <linkflags>/NODEFAULTLIB:ole32.lib <linkflags>/NODEFAULTLIB:kernel32.lib <linkflags>WindowsPhoneCore.lib ;
+feature.set-default windows-api : desktop ;
+
# Registers this toolset including all of its flags, features & generators. Does
# nothing on repeated calls.
@@ -283,6 +316,15 @@ rule register-toolset ( )
}
}
+rule resolve-possible-msvc-version-alias ( version )
+{
+ if $(.version-alias-$(version))
+ {
+ version = $(.version-alias-$(version)) ;
+ }
+ return $(version) ;
+}
+
# Declare action for creating static libraries. If library exists, remove it
# before adding files. See
@@ -475,7 +517,15 @@ rule link ( targets + : sources * : properties * )
{
if <embed-manifest>on in $(properties)
{
- msvc.manifest $(targets) : $(sources) : $(properties) ;
+ if [ feature.get-values <embed-manifest-file> : $(properties) ]
+ {
+ DEPENDS $(<) : [ on $(<) return $(EMBED_MANIFEST_FILE) ] ;
+ msvc.manifest.user $(targets) $(EMBED_MANIFEST_FILE) : $(sources) : $(properties) ;
+ }
+ else
+ {
+ msvc.manifest $(targets) : $(sources) : $(properties) ;
+ }
}
}
@@ -484,7 +534,15 @@ rule link.dll ( targets + : sources * : properties * )
DEPENDS $(<) : [ on $(<) return $(DEF_FILE) ] ;
if <embed-manifest>on in $(properties)
{
- msvc.manifest.dll $(targets) : $(sources) : $(properties) ;
+ if [ feature.get-values <embed-manifest-file> : $(properties) ]
+ {
+ DEPENDS $(<) : [ on $(<) return $(EMBED_MANIFEST_FILE) ] ;
+ msvc.manifest.dll.user $(targets) $(EMBED_MANIFEST_FILE) : $(sources) : $(properties) ;
+ }
+ else
+ {
+ msvc.manifest.dll $(targets) : $(sources) : $(properties) ;
+ }
}
}
@@ -513,6 +571,11 @@ if [ os.name ] in NT
)
}
+ actions manifest.user bind EMBED_MANIFEST_FILE
+ {
+ $(.MT) -manifest "$(EMBED_MANIFEST_FILE)" "-outputresource:$(<[1]);1"
+ }
+
actions link.dll bind DEF_FILE LIBRARIES_MENTIONED_BY_FILE
{
$(.LD) /DLL $(LINKFLAGS) /out:"$(<[1]:W)" /IMPLIB:"$(<[2]:W)" /LIBPATH:"$(LINKPATH:W)" /def:"$(DEF_FILE)" $(OPTIONS) @"@($(<[1]:W).rsp:E=$(.nl)"$(>)" $(.nl)$(LIBRARIES_MENTIONED_BY_FILE) $(.nl)$(LIBRARIES) $(.nl)"$(LIBRARY_OPTION)$(FINDLIBS_ST).lib" $(.nl)"$(LIBRARY_OPTION)$(FINDLIBS_SA).lib")"
@@ -525,6 +588,10 @@ if [ os.name ] in NT
$(.MT) -manifest "$(<[1]).manifest" "-outputresource:$(<[1]);2"
)
}
+ actions manifest.dll.user bind EMBED_MANIFEST_FILE
+ {
+ $(.MT) -manifest "$(EMBED_MANIFEST_FILE)" "-outputresource:$(<[1]);2"
+ }
}
else
{
@@ -551,6 +618,11 @@ else
$(.MT) -manifest "$(<[1]:W).manifest" "-outputresource:$(<[1]:W);2"
fi
}
+
+ actions manifest.dll.user bind EMBED_MANIFEST_FILE
+ {
+ $(.MT) -manifest "$(EMBED_MANIFEST_FILE)" "-outputresource:$(<[1]);2"
+ }
}
# This rule sets up the pdb file that will be used when generating static
@@ -676,6 +748,106 @@ local rule auto-detect-toolset-versions ( )
}
}
+# Helper rule to generate a faster alternative to MSVC setup scripts.
+# We used to call MSVC setup scripts directly in every action, however in
+# newer MSVC versions (10.0+) they make long-lasting registry queries
+# which have a significant impact on build time.
+rule maybe-rewrite-setup ( toolset : setup-script : setup-options : version : rewrite-setup ? )
+{
+ local result = $(setup-script)" "$(setup-options) ;
+ # At the moment we only know how to rewrite scripts with cmd shell.
+ if ( [ os.name ] in NT ) && ( $(rewrite-setup) != off )
+ {
+ setup-script-id = b2_$(toolset)_$(version)_$(setup-script:B) ;
+ if $(setup-options)-is-not-empty
+ {
+ setup-script-id = $(setup-script-id)_$(setup-options) ;
+ }
+
+ if $(.$(setup-script-id))
+ {
+ errors.error rewriting setup script for the second time ;
+ }
+
+ local tmpdir = [ os.environ TEMP ] ;
+ local replacement = [ path.native $(tmpdir)/$(setup-script-id).cmd ] ;
+ if ( $(rewrite-setup) = always ) || ( ! [ path.exists $(replacement) ] )
+ {
+ local original-vars = [ SPLIT_BY_CHARACTERS [ SHELL set ] : "\n" ] ;
+ local new-vars = [ SPLIT_BY_CHARACTERS [ SHELL "$(setup-script) $(setup-options)>nul && set" ] : "\n" ] ;
+ local diff-vars = [ set.difference $(new-vars) : $(original-vars) ] ;
+ if $(diff-vars)
+ {
+ local target = <new-setup-script>$(replacement) ;
+ FILE_CONTENTS on $(target) = "SET "$(diff-vars) ;
+ ALWAYS $(target) ;
+ msvc.write-setup-script $(target) ;
+ UPDATE_NOW $(target) : : ignore-minus-n ;
+ .$(setup-script-id) = $(replacement) ;
+ result = "\""$(replacement)"\"" ;
+ }
+ }
+ else
+ {
+ result = "\""$(replacement)"\"" ;
+ }
+ }
+ return $(result) ;
+}
+
+actions write-setup-script
+{
+ @($(STDOUT):E=$(FILE_CONTENTS:J=$(.nl))) > "$(<)"
+}
+
+
+# Local helper rule to create the vcvars setup command for given architecture
+# and options.
+#
+local rule generate-setup-cmd ( version : command : parent : options * : cpu : global-setup : default-global-setup-options : default-setup )
+{
+ local setup-prefix = "call " ;
+ local setup-suffix = " >nul"$(.nl) ;
+ if ! [ os.name ] in NT
+ {
+ setup-prefix = "cmd.exe /S /C call " ;
+ setup-suffix = " \">nul\" \"&&\" " ;
+ }
+
+ local setup-options ;
+ local setup = [ feature.get-values <setup-$(cpu)> : $(options) ] ;
+
+ if ! $(setup)-is-defined
+ {
+ if $(global-setup)-is-defined
+ {
+ setup = $(global-setup) ;
+
+ # If needed we can easily add using configuration flags
+ # here for overriding which options get passed to the
+ # global setup command for which target platform:
+ # setup-options = [ feature.get-values <setup-options-$(c)> : $(options) ] ;
+ setup-options ?= $(default-global-setup-options) ;
+ }
+ else
+ {
+ setup = [ locate-default-setup $(command) : $(parent) : $(default-setup) ] ;
+ }
+ }
+
+ # Cygwin to Windows path translation.
+ setup = "\""$(setup:W)"\"" ;
+
+ # Append setup options to the setup name and add the final setup
+ # prefix & suffix.
+ setup-options ?= "" ;
+ local rewrite = [ feature.get-values <rewrite-setup-scripts> : $(options) ] ;
+ setup = [ maybe-rewrite-setup msvc : $(setup:J=" ") : $(setup-options:J=" ") : $(version) : $(rewrite) ] ;
+ setup = $(setup-prefix)$(setup)$(setup-suffix) ;
+
+ return $(setup) ;
+}
+
# Worker rule for toolset version configuration. Takes an explicit version id or
# nothing in case it should configure the default toolset version (the first
@@ -700,10 +872,7 @@ local rule configure-really ( version ? : options * )
}
# Version alias -> real version number.
- if $(.version-alias-$(version))
- {
- version = $(.version-alias-$(version)) ;
- }
+ version = [ resolve-possible-msvc-version-alias $(version) ] ;
# Check whether the selected configuration is already in use.
if $(version) in [ $(.versions).used ]
@@ -795,17 +964,24 @@ local rule configure-really ( version ? : options * )
# Generate and register setup command.
local below-8.0 = [ MATCH ^([67]\\.) : $(version) ] ;
-
+ local below-11.0 = [ MATCH ^([6789]\\.|10\\.) : $(version) ] ;
+
local cpu = i386 amd64 ia64 arm ;
if $(below-8.0)
{
cpu = i386 ;
}
-
+ if $(below-11.0)
+ {
+ cpu = i386 amd64 ia64 ;
+ }
+
local setup-amd64 ;
local setup-i386 ;
local setup-ia64 ;
local setup-arm ;
+ local setup-phone-i386 ;
+ local setup-phone-arm ;
if $(command)
{
@@ -828,7 +1004,7 @@ local rule configure-really ( version ? : options * )
# Setup will be used if the command name has been specified. If
# setup is not specified explicitly then a default setup script will
- # be used instead. Setup scripts may be global or arhitecture/
+ # be used instead. Setup scripts may be global or architecture/
# /platform/cpu specific. Setup options are used only in case of
# global setup scripts.
@@ -850,6 +1026,7 @@ local rule configure-really ( version ? : options * )
local global-setup = [ feature.get-values <setup> : $(options) ] ;
global-setup = $(global-setup[1]) ;
+ local global-setup-phone = $(global-setup) ;
if ! $(below-8.0)
{
global-setup ?= [ locate-default-setup $(command) : $(parent) :
@@ -860,6 +1037,8 @@ local rule configure-really ( version ? : options * )
local default-setup-i386 = vcvars32.bat ;
local default-setup-ia64 = vcvarsx86_ia64.bat ;
local default-setup-arm = vcvarsx86_arm.bat ;
+ local default-setup-phone-i386 = vcvarsphonex86.bat ;
+ local default-setup-phone-arm = vcvarsphonex86_arm.bat ;
# http://msdn2.microsoft.com/en-us/library/x4d2c09s(VS.80).aspx and
# http://msdn2.microsoft.com/en-us/library/x4d2c09s(vs.90).aspx
@@ -891,47 +1070,35 @@ local rule configure-really ( version ? : options * )
default-global-setup-options-ia64 = ia64 ;
}
- local setup-prefix = "call " ;
- local setup-suffix = " >nul"$(.nl) ;
- if ! [ os.name ] in NT
+ for local c in $(cpu)
{
- setup-prefix = "cmd.exe /S /C call " ;
- setup-suffix = " \">nul\" \"&&\" " ;
+ setup-$(c) = [ generate-setup-cmd $(version) : $(command) : $(parent) : $(options) : $(c) : $(global-setup) : $(default-global-setup-options-$(c)) : $(default-setup-$(c)) ] ;
}
-
- for local c in $(cpu)
+
+ # Windows phone has different setup scripts, located in a different directory hierarchy.
+ # The 11.0 toolset can target Windows Phone 8.0 and the 12.0 toolset can target Windows Phone 8.1,
+ # each of which have a different directory for their vcvars setup scripts.
+ local phone-parent = [ path.native [ path.join $(parent) WPSDK ] ] ;
+ local phone-directory = $(phone-parent) ;
+ if [ MATCH "(11.0)" : $(version) ]
{
- local setup-options ;
-
- setup-$(c) = [ feature.get-values <setup-$(c)> : $(options) ] ;
-
- if ! $(setup-$(c))-is-defined
+ phone-directory = [ path.native [ path.join $(phone-directory) WP80 ] ] ;
+ }
+ else if [ MATCH "(12.0)" : $(version) ]
+ {
+ phone-directory = [ path.native [ path.join $(phone-directory) WP81 ] ] ;
+ }
+ global-setup-phone ?= [ locate-default-setup $(phone-directory) : $(phone-parent) : vcvarsphoneall.bat ] ;
+
+ # If can't locate default phone setup script then this VS version doesn't support Windows Phone.
+ if $(global-setup-phone)-is-defined
+ {
+ # i386 CPU is for the Windows Phone emulator in Visual Studio.
+ local phone-cpu = i386 arm ;
+ for local c in $(phone-cpu)
{
- if $(global-setup)-is-defined
- {
- setup-$(c) = $(global-setup) ;
-
- # If needed we can easily add using configuration flags
- # here for overriding which options get passed to the
- # global setup command for which target platform:
- # setup-options = [ feature.get-values <setup-options-$(c)> : $(options) ] ;
-
- setup-options ?= $(default-global-setup-options-$(c)) ;
- }
- else
- {
- setup-$(c) = [ locate-default-setup $(command) :
- $(parent) : $(default-setup-$(c)) ] ;
- }
+ setup-phone-$(c) = [ generate-setup-cmd $(version) : $(phone-directory) : $(phone-parent) : $(options) : $(c) : $(global-setup-phone) : $(default-global-setup-options-$(c)) : $(default-setup-phone-$(c)) ] ;
}
-
- # Cygwin to Windows path translation.
- setup-$(c) = "\""$(setup-$(c):W)"\"" ;
-
- # Append setup options to the setup name and add the final setup
- # prefix & suffix.
- setup-options ?= "" ;
- setup-$(c) = $(setup-prefix)$(setup-$(c):J=" ")" "$(setup-options:J=" ")$(setup-suffix) ;
}
}
@@ -985,15 +1152,23 @@ local rule configure-really ( version ? : options * )
local cpu-assembler = $(assembler) ;
cpu-assembler ?= $(default-assembler-$(c)) ;
- toolset.flags msvc.compile .CC $(cpu-conditions) : $(setup-$(c))$(compiler) /Zm800 -nologo ;
- toolset.flags msvc.compile .RC $(cpu-conditions) : $(setup-$(c))$(resource-compiler) ;
- toolset.flags msvc.compile .ASM $(cpu-conditions) : $(setup-$(c))$(cpu-assembler) -nologo ;
- toolset.flags msvc.link .LD $(cpu-conditions) : $(setup-$(c))$(linker) /NOLOGO /INCREMENTAL:NO ;
- toolset.flags msvc.archive .LD $(cpu-conditions) : $(setup-$(c))$(linker) /lib /NOLOGO ;
- toolset.flags msvc.compile .IDL $(cpu-conditions) : $(setup-$(c))$(idl-compiler) ;
- toolset.flags msvc.compile .MC $(cpu-conditions) : $(setup-$(c))$(mc-compiler) ;
+ toolset.flags msvc.compile .RC <windows-api>$(api)/$(cpu-conditions) : $(setup-$(c))$(resource-compiler) ;
+ toolset.flags msvc.compile .IDL <windows-api>$(api)/$(cpu-conditions) : $(setup-$(c))$(idl-compiler) ;
+ toolset.flags msvc.compile .MC <windows-api>$(api)/$(cpu-conditions) : $(setup-$(c))$(mc-compiler) ;
+ toolset.flags msvc.link .MT <windows-api>$(api)/$(cpu-conditions) : $(setup-$(c))$(manifest-tool) -nologo ;
- toolset.flags msvc.link .MT $(cpu-conditions) : $(setup-$(c))$(manifest-tool) -nologo ;
+ for api in desktop store phone
+ {
+ local setup-script = $(setup-$(c)) ;
+ if $(api) = phone
+ {
+ setup-script = $(setup-phone-$(c)) ;
+ }
+ toolset.flags msvc.compile .CC <windows-api>$(api)/$(cpu-conditions) : $(setup-script)$(compiler) /Zm800 -nologo ;
+ toolset.flags msvc.compile .ASM <windows-api>$(api)/$(cpu-conditions) : $(setup-script)$(cpu-assembler) -nologo ;
+ toolset.flags msvc.link .LD <windows-api>$(api)/$(cpu-conditions) : $(setup-script)$(linker) /NOLOGO /INCREMENTAL:NO ;
+ toolset.flags msvc.archive .LD <windows-api>$(api)/$(cpu-conditions) : $(setup-script)$(linker) /lib /NOLOGO ;
+ }
if $(cc-filter)
{
@@ -1168,7 +1343,10 @@ local rule register-toolset-really ( )
OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : EXE : <toolset>msvc ] ;
generators.register [ new msvc-linking-generator msvc.link.dll :
OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB IMPORT_LIB :
- <toolset>msvc ] ;
+ <toolset>msvc <suppress-import-lib>false ] ;
+ generators.register [ new msvc-linking-generator msvc.link.dll :
+ OBJ SEARCHED_LIB STATIC_LIB IMPORT_LIB : SHARED_LIB :
+ <toolset>msvc <suppress-import-lib>true ] ;
generators.register-archiver msvc.archive : OBJ : STATIC_LIB : <toolset>msvc ;
generators.register-c-compiler msvc.compile.c++ : CPP : OBJ : <toolset>msvc ;
@@ -1283,6 +1461,8 @@ local rule register-toolset-really ( )
toolset.flags msvc.link FINDLIBS_SA <find-shared-library> ;
toolset.flags msvc.link LIBRARY_OPTION <toolset>msvc : "" : unchecked ;
toolset.flags msvc.link LIBRARIES_MENTIONED_BY_FILE : <library-file> ;
+
+ toolset.flags msvc.link.dll LINKFLAGS <suppress-import-lib>true : /NOENTRY ;
}
toolset.flags msvc.archive AROPTIONS <archiveflags> ;
@@ -1371,6 +1551,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
<architecture>ia64/<address-model>64 ;
.cpu-arch-arm =
+ <architecture>arm/<address-model>
<architecture>arm/<address-model>32 ;
@@ -1392,7 +1573,8 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
athlon-mp $(.cpu-type-em64t) $(.cpu-type-amd64) ;
.cpu-type-itanium = itanium itanium1 merced ;
.cpu-type-itanium2 = itanium2 mckinley ;
-
+.cpu-type-arm = armv2 armv2a armv3 armv3m armv4 armv4t armv5 armv5t armv5te armv6 armv6j iwmmxt ep9312
+ armv7 armv7s ;
# Known toolset versions, in order of preference.
.known-versions = 14.0 12.0 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1
diff --git a/tools/build/src/tools/msvc.py b/tools/build/src/tools/msvc.py
index 1f9cc2ccb..02dce9f9e 100644
--- a/tools/build/src/tools/msvc.py
+++ b/tools/build/src/tools/msvc.py
@@ -115,7 +115,7 @@ def init(version = None, command = None, options = None):
command = to_seq(command)
if command:
- options.append("<command>"+command)
+ options.extend("<command>"+cmd for cmd in command)
configure(version,options)
def configure(version=None, options=None):
diff --git a/tools/build/src/tools/python.jam b/tools/build/src/tools/python.jam
index dfb17ed8d..783b9cee8 100644
--- a/tools/build/src/tools/python.jam
+++ b/tools/build/src/tools/python.jam
@@ -1057,14 +1057,14 @@ IMPORT python : python-extension : : python-extension ;
rule py2to3
{
- common.copy $(>) $(<) ;
+ common.copy $(<) : $(>) ;
2to3 $(<) ;
}
actions 2to3
{
- 2to3 -wn "$(<)"
- 2to3 -dwn "$(<)"
+ 2to3 -wn --no-diffs "$(<)"
+ 2to3 -dwn --no-diffs "$(<)"
}
diff --git a/tools/build/src/tools/rc.py b/tools/build/src/tools/rc.py
index bacd3260a..d026480d8 100644
--- a/tools/build/src/tools/rc.py
+++ b/tools/build/src/tools/rc.py
@@ -27,6 +27,7 @@ import re
import bjam
from b2.build import type, toolset, generators, scanner, feature
+from b2.exceptions import AlreadyDefined
from b2.tools import builtin
from b2.util import regex
from b2.build.toolset import flags
@@ -91,7 +92,7 @@ class RCAction:
def rc_register_action(action_name, function = None):
global engine
if engine.actions.has_key(action_name):
- raise "Bjam action %s is already defined" % action_name
+ raise AlreadyDefined("Bjam action %s is already defined" % action_name)
engine.actions[action_name] = RCAction(action_name, function)
def rc_compile_resource(targets, sources, properties):
diff --git a/tools/build/src/tools/testing.py b/tools/build/src/tools/testing.py
index 360f07aed..a3b3f0117 100644
--- a/tools/build/src/tools/testing.py
+++ b/tools/build/src/tools/testing.py
@@ -322,7 +322,7 @@ get_manager().engine().register_bjam_action("testing.capture-output",
capture_output_setup)
-path = os.path.dirname(get_manager().projects().loaded_tool_module_path_[__name__])
+path = os.path.dirname(__file__)
import b2.util.os_j
get_manager().projects().project_rules()._import_rule("testing", "os.name",
b2.util.os_j.name)
diff --git a/tools/build/src/tools/types/asm.py b/tools/build/src/tools/types/asm.py
index b4e1c30e7..a4b4aee61 100644
--- a/tools/build/src/tools/types/asm.py
+++ b/tools/build/src/tools/types/asm.py
@@ -4,10 +4,30 @@
# 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)
+from b2.build import type as type_
+from b2.manager import get_manager
+from b2.tools.cast import cast
+from b2.util import bjam_signature
-from b2.build import type
-def register():
- type.register_type('ASM', ['s', 'S', 'asm'])
+MANAGER = get_manager()
+PROJECT_REGISTRY = MANAGER.projects()
-register()
+# maps project.name() + type to type
+_project_types = {}
+
+type_.register_type('ASM', ['s', 'S', 'asm'])
+
+
+@bjam_signature((['type_'], ['sources', '*'], ['name', '?']))
+def set_asm_type(type_, sources, name=''):
+ project = PROJECT_REGISTRY.current()
+ _project_types[project.name() + type_] = _project_types.get(
+ project.name() + type_, type_) + '_'
+
+ name = name if name else _project_types[project.name() + type_]
+ type_ += '.asm'
+ cast(name, type_.upper(), sources, [], [], [])
+
+
+PROJECT_REGISTRY.add_rule("set-asm-type", set_asm_type)
diff --git a/tools/build/src/tools/types/cpp.py b/tools/build/src/tools/types/cpp.py
index a6703255c..22f4dece4 100644
--- a/tools/build/src/tools/types/cpp.py
+++ b/tools/build/src/tools/types/cpp.py
@@ -1,13 +1,84 @@
# Copyright David Abrahams 2004. 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)
+import os
+import re
-from b2.build import type
+import bjam
-def register ():
- type.register_type('CPP', ['cpp', 'cxx', 'cc'])
- type.register_type('H', ['h'])
- type.register_type('HPP', ['hpp'], 'H')
- type.register_type('C', ['c'])
+from b2.build import type as type_, scanner
+from b2.manager import get_manager
+from b2.util.utility import replace_grist
-register ()
+
+MANAGER = get_manager()
+ENGINE = MANAGER.engine()
+SCANNERS = MANAGER.scanners()
+
+
+class CScanner(scanner.Scanner):
+ def __init__(self, includes):
+ scanner.Scanner.__init__(self)
+ self.includes = []
+ for include in includes:
+ self.includes.extend(replace_grist(include, '').split('&&'))
+
+ def pattern(self):
+ return '#\s*include\s*(<(.*)>|"(.*)")'
+
+ def process(self, target, matches, binding):
+ # create a single string so that findall
+ # can be used since it returns a list of
+ # all grouped matches
+ match_str = ' '.join(matches)
+ # the question mark makes the regexes non-greedy
+ angles = re.findall(r'<(.*?)>', match_str)
+ quoted = re.findall(r'"(.*?)"', match_str)
+
+ # CONSIDER: the new scoping rules seem to defeat "on target" variables.
+ g = ENGINE.get_target_variable(target, 'HDRGRIST')
+ b = os.path.normpath(os.path.dirname(binding))
+
+ # Attach binding of including file to included targets. When a target is
+ # directly created from a virtual target this extra information is
+ # unnecessary. But in other cases, it allows us to distinguish between
+ # two headers of the same name included from different places. We do not
+ # need this extra information for angle includes, since they should not
+ # depend on the including file (we can not get literal "." in the
+ # include path).
+ # local g2 = $(g)"#"$(b) ;
+ g2 = g + '#' + b
+
+ angles = [replace_grist(angle, g) for angle in angles]
+ quoted = [replace_grist(quote, g2) for quote in quoted]
+
+ includes = angles + quoted
+
+ bjam.call('INCLUDES', target, includes)
+ bjam.call('NOCARE', includes)
+ ENGINE.set_target_variable(angles, 'SEARCH', self.includes)
+ ENGINE.set_target_variable(quoted, 'SEARCH', [b] + self.includes)
+
+ # Just propagate the current scanner to includes, in hope that includes
+ # do not change scanners.
+ SCANNERS.propagate(self, includes)
+
+ bjam.call('ISFILE', includes)
+
+
+scanner.register(CScanner, 'include')
+
+type_.register_type('CPP', ['cpp', 'cxx', 'cc'])
+type_.register_type('H', ['h'])
+type_.register_type('HPP', ['hpp'], 'H')
+type_.register_type('C', ['c'])
+# It most cases where a CPP file or a H file is a source of some action, we
+# should rebuild the result if any of files included by CPP/H are changed. One
+# case when this is not needed is installation, which is handled specifically.
+type_.set_scanner('CPP', CScanner)
+type_.set_scanner('C', CScanner)
+# One case where scanning of H/HPP files is necessary is PCH generation -- if
+# any header included by HPP being precompiled changes, we need to recompile the
+# header.
+type_.set_scanner('H', CScanner)
+type_.set_scanner('HPP', CScanner)
diff --git a/tools/build/src/util/doc.jam b/tools/build/src/util/doc.jam
index 801aff4eb..702cab4b5 100644
--- a/tools/build/src/util/doc.jam
+++ b/tools/build/src/util/doc.jam
@@ -45,6 +45,12 @@ help-output-file = help ;
#
.option.debug ?= ;
+# These are all the options available for enabling or disabling to control the
+# help system in various ways. Options can be enabled or disabled with
+# '--help-enable-<option>', and '--help-disable-<option>' respectively.
+#
+.option-description = Help Options ;
+
# Enable or disable a documentation option.
#
local rule set-option (
@@ -358,31 +364,32 @@ local rule print-help-usage ( )
print.list-end ;
}
-
# Generates description of options controlling the help system. This
-# automatically reads the options as all variables in the doc module of the form
-# ".option.*".
+# automatically reads the options as all variables in the module given
+# with the name `module-name` of the form ".option.*".
#
local rule print-help-options (
- module-name # The doc module.
+ module-name
)
{
- print.section "Help Options"
- These are all the options available for enabling or disabling to control
- the help system in various ways. Options can be enabled or disabled with
- '"--help-enable-<option>"', and "'--help-disable-<option>'"
- respectively.
- ;
local options-to-list = [ MATCH ^[.]option[.](.*) : $($(module-name).variables) ] ;
if $(options-to-list)
{
+ local option-title = $($(module-name)..option-description.initial) ;
+ if ! $(option-title) || $(option-title) = "(empty)"
+ {
+ option-title = "$(module-name) Options" ;
+ }
+ local option-description = $(option-title)
+ $($(module-name)..option-description.docs) ;
+ print.section $(option-description) ;
print.list-start ;
for local option in [ sequence.insertion-sort $(options-to-list) ]
{
local def = disabled ;
if $($(module-name)..option.$(option).default) != "(empty)"
{
- def = enabled ;
+ def = $($(module-name)..option.$(option).default) ;
}
print.list-item $(option): $($(module-name)..option.$(option).docs)
Default is $(def). ;
diff --git a/tools/build/src/util/path.py b/tools/build/src/util/path.py
index 222b96bfe..d602598c9 100644
--- a/tools/build/src/util/path.py
+++ b/tools/build/src/util/path.py
@@ -193,7 +193,35 @@ def is_rooted (path):
# return [ sequence.join $(tokens2) : "/" ] ;
# }
# }
-#
+def reverse(path):
+ """Returns path2 such that `os.path.join(path, path2) == '.'`.
+ `path` may not contain '..' or be rooted.
+
+ Args:
+ path (str): the path to reverse
+
+ Returns:
+ the string of the reversed path
+
+ Example:
+
+ >>> p1 = 'path/to/somewhere'
+ >>> p2 = reverse('path/to/somewhere')
+ >>> p2
+ '../../..'
+ >>> os.path.normpath(os.path.join(p1, p2))
+ '.'
+ """
+ if is_rooted(path) or '..' in path:
+ from b2.manager import get_manager
+ get_manager().errors()(
+ 'reverse(path): path is either rooted or contains ".." in the path')
+ if path == '.':
+ return path
+ path = os.path.normpath(path)
+ # os.sep.join() is being used over os.path.join() due
+ # to an extra '..' that is created by os.path.join()
+ return os.sep.join('..' for t in path.split(os.sep))
# #
# # Auxillary rule: does all the semantic of 'join', except for error cheching.
# # The error checking is separated because this rule is recursive, and I don't
@@ -418,7 +446,11 @@ def programs_path ():
for elem in raw:
if elem:
for p in elem.split(os.path.pathsep):
- result.append(make(p))
+ # it's possible that the user's Path has
+ # double path separators, thus it is possible
+ # for p to be an empty string.
+ if p:
+ result.append(make(p))
return result
diff --git a/tools/build/src/util/regex.py b/tools/build/src/util/regex.py
index 29e26ecf4..6348c6fb1 100644
--- a/tools/build/src/util/regex.py
+++ b/tools/build/src/util/regex.py
@@ -5,9 +5,12 @@
import re
+from b2.util import bjam_signature
+
+
def transform (list, pattern, indices = [1]):
- """ Matches all elements of 'list' agains the 'pattern'
- and returns a list of the elements indicated by indices of
+ """ Matches all elements of 'list' agains the 'pattern'
+ and returns a list of the elements indicated by indices of
all successfull matches. If 'indices' is omitted returns
a list of first paranthethised groups of all successfull
matches.
@@ -23,3 +26,29 @@ def transform (list, pattern, indices = [1]):
return result
+
+@bjam_signature([['s', 'pattern', 'replacement']])
+def replace(s, pattern, replacement):
+ """Replaces occurrences of a match string in a given
+ string and returns the new string. The match string
+ can be a regex expression.
+
+ Args:
+ s (str): the string to modify
+ pattern (str): the search expression
+ replacement (str): the string to replace each match with
+ """
+ return re.sub(pattern, replacement, s)
+
+
+@bjam_signature((['items', '*'], ['match'], ['replacement']))
+def replace_list(items, match, replacement):
+ """Replaces occurrences of a match string in a given list of strings and returns
+ a list of new strings. The match string can be a regex expression.
+
+ Args:
+ items (list): the list of strings to modify.
+ match (str): the search expression.
+ replacement (str): the string to replace with.
+ """
+ return [replace(item, match, replacement) for item in items]
diff --git a/tools/build/test/dependency_property.py b/tools/build/test/dependency_property.py
index e5c78b60a..cdd8055b0 100644
--- a/tools/build/test/dependency_property.py
+++ b/tools/build/test/dependency_property.py
@@ -31,6 +31,6 @@ void foo() {}
""")
t.run_build_system(["--no-error-backtrace"], status=1)
-t.fail_test(string.find(t.stdout(), "Duplicate name of actual target") == -1)
+t.fail_test(string.find(t.stdout(), "Tried to build the target twice") == -1)
t.cleanup()