diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2014-10-31 14:41:14 +0000 |
---|---|---|
committer | <> | 2014-12-12 16:07:56 +0000 |
commit | ed232fdd34968697a68783b3195b1da4226915b5 (patch) | |
tree | 7a7053ceb8874b28ec4b868d4c49b500008a102e /tools/build | |
parent | 1c3648bf5b7d17fcd4fe9bc95802b16fd9eee304 (diff) | |
download | boost-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')
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 : <optimization>off ; release mode. <programlisting> lib network : network.cpp - : <emphasis role="bold"><link>shared:<define>NEWORK_LIB_SHARED</emphasis> + : <emphasis role="bold"><link>shared:<define>NETWORK_LIB_SHARED</emphasis> <variant>release:<define>EXTRA_FAST ; </programlisting> In the example above, whenever <filename>network</filename> is built with <code><link>shared</code>, - <code><define>NEWORK_LIB_SHARED</code> will be in its + <code><define>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"><link>shared:<define>NEWORK_LIB_SHARED</emphasis> + : <emphasis role="bold"><link>shared:<define>NETWORK_LIB_SHARED</emphasis> <variant>release:<define>EXTRA_FAST ;</programlisting> In the example above, whenever <filename>network</filename> is built with - <code language="jam"><link>shared</code>, <code language="jam"><define>NEWORK_LIB_SHARED + <code language="jam"><link>shared</code>, <code language="jam"><define>NETWORK_LIB_SHARED </code> will be in its properties, too. Also, whenever its release variant is built, <code><define>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() |