From d9417960f9206a18d43c9caac73799ba822af8c0 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 23 Feb 2016 13:59:24 -0500 Subject: [PATCH 001/158] Document archiver and ranlib options for gcc. --- doc/src/reference.xml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index e258985ee..82de577c0 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -930,6 +930,30 @@ using gcc : &toolset_ops; ; + + archiver + + + Specifies the archiver command that is used to produce static + libraries. Normally, it is autodetected using gcc + -print-prog-name option or defaulted to ar, + but in some cases you might want to override it, for example to expliitly + use a system version instead of one included with gcc. + + + + + ranlib + + + Specifies the ranlib command that is used to generated symbol table + for static libraries. Normally, it is autodetected using gcc + -print-prog-name option or defaulted to ranlib, + but in some cases you might want to override it, for example to expliitly + use a system version instead of one included with gcc. + + + rc From 596f45dab529f01bb79b7fbf284474a132791339 Mon Sep 17 00:00:00 2001 From: Daniel Date: Thu, 25 Feb 2016 18:27:22 +0000 Subject: [PATCH 002/158] Close para tags in listitems. --- doc/src/reference.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index 82de577c0..a66eb75a6 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -938,7 +938,7 @@ using gcc : &toolset_ops; ; libraries. Normally, it is autodetected using gcc -print-prog-name option or defaulted to ar, but in some cases you might want to override it, for example to expliitly - use a system version instead of one included with gcc. + use a system version instead of one included with gcc. @@ -950,7 +950,7 @@ using gcc : &toolset_ops; ; for static libraries. Normally, it is autodetected using gcc -print-prog-name option or defaulted to ranlib, but in some cases you might want to override it, for example to expliitly - use a system version instead of one included with gcc. + use a system version instead of one included with gcc. From 09b6788df6833ecd90c8c0e138a485107248310c Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 25 Feb 2016 16:16:31 -0700 Subject: [PATCH 003/158] Translate the result of running -print-prog-name to a windows path when running a cygwin gcc from a native windows build of b2. --- src/tools/common.jam | 4 +++ src/tools/cygwin.jam | 74 ++++++++++++++++++++++++++++++++++++++++++++ src/tools/gcc.jam | 23 +++++++++----- 3 files changed, 94 insertions(+), 7 deletions(-) create mode 100644 src/tools/cygwin.jam diff --git a/src/tools/common.jam b/src/tools/common.jam index ca9480be9..04b87accb 100644 --- a/src/tools/common.jam +++ b/src/tools/common.jam @@ -339,6 +339,10 @@ rule get-absolute-tool-path ( command ) # rule find-tool ( name : additional-paths * : path-last ? ) { + if $(name:D) + { + return [ check-tool-aux $(name) ] ; + } local path = [ path.programs-path ] ; local match = [ path.glob $(path) : $(name) $(name).exe ] ; local additional-match = [ path.glob $(additional-paths) : $(name) diff --git a/src/tools/cygwin.jam b/src/tools/cygwin.jam new file mode 100644 index 000000000..7c091c015 --- /dev/null +++ b/src/tools/cygwin.jam @@ -0,0 +1,74 @@ +# Copyright 2004 Vladimir Prus. +# Copyright 2016 Steven Watanabe +# 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 utility functions for handling cygwin paths + +import regex ; + +.cygwin-drive-letter-re = ^/cygdrive/([a-z])/(.*) ; + +# Like W32_GETREG, except prepend HKEY_CURRENT_USER\SOFTWARE and +# HKEY_LOCAL_MACHINE\SOFTWARE to the first argument, returning the first result +# found. Also accounts for the fact that on 64-bit machines, 32-bit software has +# its own area, under SOFTWARE\Wow6432node. +# +local rule software-registry-value ( path : data ? ) +{ + local result ; + for local root in HKEY_CURRENT_USER HKEY_LOCAL_MACHINE + { + for local x64elt in "" Wow6432node\\ # Account for 64-bit windows + { + if ! $(result) + { + result = [ W32_GETREG $(root)\\SOFTWARE\\$(x64elt)$(path) : $(data) ] ; + } + } + + } + return $(result) ; +} + +# :W only works in Cygwin builds of bjam. This one works on NT builds as well. +# +rule cygwin-to-windows-path ( path ) +{ + path = $(path:R="") ; # strip any trailing slash + + local drive-letter = [ SUBST $(path) $(.cygwin-drive-letter-re) $1:/$2 ] ; + if $(drive-letter) + { + path = $(drive-letter) ; + } + else if $(path:R=/x) = $(path) # already rooted? + { + # Look for a cygwin mount that includes each head sequence in $(path). + local head = $(path) ; + local tail = "" ; + + while $(head) + { + local root = [ software-registry-value + "Cygnus Solutions\\Cygwin\\mounts v2\\"$(head) : native ] ; + + if $(root) + { + path = $(tail:R=$(root)) ; + head = ; + } + tail = $(tail:R=$(head:D=)) ; + + if $(head) = / + { + head = ; + } + else + { + head = $(head:D) ; + } + } + } + return [ regex.replace $(path:R="") / \\ ] ; +} diff --git a/src/tools/gcc.jam b/src/tools/gcc.jam index e94eced20..0f346a501 100644 --- a/src/tools/gcc.jam +++ b/src/tools/gcc.jam @@ -12,6 +12,7 @@ import "class" : new ; import common ; +import cygwin ; import feature ; import fortran ; import generators ; @@ -231,13 +232,9 @@ rule init ( version ? : command * : options * ) # programs as needed to prefer using their installation specific versions. # This is essential for correct use of MinGW and for cross-compiling. - local nl = " -" ; - # - Archive builder. local archiver = [ common.get-invocation-command gcc - : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : - [ SHELL "$(command-string) -print-prog-name=ar" ] ] ] + : [ .get-prog-name $(command-string) : ar : $(flavor) ] : [ feature.get-values : $(options) ] : $(bin) : search-path ] ; @@ -249,8 +246,7 @@ rule init ( version ? : command * : options * ) # - Ranlib. local ranlib = [ common.get-invocation-command gcc - : [ NORMALIZE_PATH [ MATCH "(.*)[$(nl)]+" : - [ SHELL "$(command-string) -print-prog-name=ranlib" ] ] ] + : [ .get-prog-name $(command-string) : ranlib : $(flavor) ] : [ feature.get-values : $(options) ] : $(bin) : search-path ] ; @@ -286,6 +282,19 @@ if [ os.name ] = NT JAMSHELL = % ; } +# Uses -print-prog-name to get the name of the tool. +# Converts the path to native form if using cygwin. +rule .get-prog-name ( command-string : tool : flavor ? ) +{ + local prog-name = [ NORMALIZE_PATH [ MATCH "(.*)[\n]+" : + [ SHELL "$(command-string) -print-prog-name=$(tool)" ] ] ] ; + if $(flavor) != mingw && [ os.name ] = NT + { + prog-name = [ cygwin.cygwin-to-windows-path $(prog-name) ] ; + } + return $(prog-name) ; +} + generators.register-c-compiler gcc.compile.c++.preprocess : CPP : PREPROCESSED_CPP : gcc ; generators.register-c-compiler gcc.compile.c.preprocess : C : PREPROCESSED_C : gcc ; generators.register-c-compiler gcc.compile.c++ : CPP : OBJ : gcc ; From 1a0a48af96071d462122c0bec74600db67a6e9bb Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Sat, 27 Feb 2016 11:41:34 -0700 Subject: [PATCH 004/158] Mark python as configured even if we couldn't find the includes or libraries. We try to forge ahead anyway, and saying we didn't just causes more problems. We should consider erroring out in this case, instead, but for now this change is minimally disruptive. --- src/tools/python.jam | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index cb4a4c3e0..0139b033d 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -798,17 +798,15 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : } # Anything left to compute? - if $(includes) && $(libraries) - { - .configured = true ; - } - else + if ! ( $(includes) && $(libraries) ) { version ?= $(fallback-version) ; version ?= 2.5 ; exec-prefix ?= $(prefix) ; compute-default-paths $(target-os) : $(version) : $(prefix:E=) ; } + + .configured = true ; if ! $(interpreter-cmd) { From 4c546c3c15563123328edc47106daf2a64ddbde3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Hunold?= Date: Sun, 28 Feb 2016 17:09:32 +0100 Subject: [PATCH 005/158] Add support for more Qt libraries - QtDataVisualization - QtSerialPort - QtWebChannel - QtWebSockets - QtPurchasing - WebEngine (QtWebengine and QtWebengineWidgets) - Connectivity (QtBluetooth and QtNfc) - QtGamepad - QtScxml - QtSerialBus --- src/tools/qt5.jam | 35 ++++++++++++++++++++++++- test/qt5/jamroot.jam | 25 ++++++++++++++++++ test/qt5/qtbluetooth.cpp | 34 ++++++++++++++++++++++++ test/qt5/qtdatavisualization.cpp | 31 ++++++++++++++++++++++ test/qt5/qtgamepad.cpp | 29 +++++++++++++++++++++ test/qt5/qtnfc.cpp | 28 ++++++++++++++++++++ test/qt5/qtpurchasing.cpp | 44 ++++++++++++++++++++++++++++++++ test/qt5/qtscxml.cpp | 33 ++++++++++++++++++++++++ test/qt5/qtserialbus.cpp | 25 ++++++++++++++++++ test/qt5/qtserialport.cpp | 22 ++++++++++++++++ test/qt5/qtwebchannel.cpp | 29 +++++++++++++++++++++ test/qt5/qtwebengine.cpp | 30 ++++++++++++++++++++++ test/qt5/qtwebenginewidgets.cpp | 40 +++++++++++++++++++++++++++++ test/qt5/qtwebsocket.cpp | 26 +++++++++++++++++++ test/qt5/qtwebsockets.cpp | 24 +++++++++++++++++ test/qt5/qtwebview.cpp | 31 ++++++++++++++++++++++ 16 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 test/qt5/qtbluetooth.cpp create mode 100644 test/qt5/qtdatavisualization.cpp create mode 100644 test/qt5/qtgamepad.cpp create mode 100644 test/qt5/qtnfc.cpp create mode 100644 test/qt5/qtpurchasing.cpp create mode 100644 test/qt5/qtscxml.cpp create mode 100644 test/qt5/qtserialbus.cpp create mode 100644 test/qt5/qtserialport.cpp create mode 100644 test/qt5/qtwebchannel.cpp create mode 100644 test/qt5/qtwebengine.cpp create mode 100644 test/qt5/qtwebenginewidgets.cpp create mode 100644 test/qt5/qtwebsocket.cpp create mode 100644 test/qt5/qtwebsockets.cpp create mode 100644 test/qt5/qtwebview.cpp diff --git a/src/tools/qt5.jam b/src/tools/qt5.jam index 6eac4ad3f..464066da8 100644 --- a/src/tools/qt5.jam +++ b/src/tools/qt5.jam @@ -417,7 +417,7 @@ rule init ( prefix : version ? : condition * : namespace ? : infix ? : full_bin } else { - alias QtAngle + alias QtAngle : # sources : # requirements $(target-requirements) @@ -475,9 +475,21 @@ rule init ( prefix : version ? : condition * : namespace ? : infix ? : full_bin add-shared-library QtQuickParticles : QtQml : : $(target-requirements) ; add-shared-library QtQuickTest : QtQml : : $(target-requirements) ; + add-shared-library QtSerialPort : QtCore : QT_SERIALPORT_LIB : $(target-requirements) ; + # QtLocation (since 5.4) add-shared-library QtLocation : QtQuick QtPositioning : QT_LOCATION_LIB : $(target-requirements) ; + # Webengine support (since 5.4) + add-shared-library QtWebEngine : QtGui : QT_WEBENGINE_LIB : $(target-requirements) ; + add-shared-library QtWebEngineCore : QtWebEngine : QT_WEBENGINECORE_LIB : $(target-requirements) ; + add-shared-library QtWebEngineWidgets : QtWebEngineCore QtWidgets : QT_WEBENGINEWIDGETS_LIB : $(target-requirements) ; + + add-shared-library QtWebChannel : QtQml : QT_WEBCHANNEL_LIB : $(target-requirements) ; + add-shared-library QtWebSockets : QtNetwork : QT_WEBSOCKETS_LIB : $(target-requirements) ; + + add-shared-library QtWebView : QtWebEngineCore QtWebChannel : QT_WEBVIEW_LIB : $(target-requirements) ; + # Qt3d libraries (since 5.6) add-shared-library Qt3DCore : QtGui : QT_3DCORE_LIB : $(target-requirements) ; add-shared-library Qt3DRender : Qt3DCore QtConcurrent : QT_3DRENDER_LIB : $(target-requirements) ; @@ -487,6 +499,27 @@ rule init ( prefix : version ? : condition * : namespace ? : infix ? : full_bin # QtCharts (since 5.7) add-shared-library QtCharts : QtWidgets : QT_CHARTS_LIB : $(target-requirements) ; + # 3D data visualization (since 5.7) + add-shared-library QtDataVisualization : QtGui : QT_DATAVISUALIZATION_LIB : $(target-requirements) ; + + # In-App purchase API (since 5.7) + add-shared-library QtPurchasing : QtCore : QT_PURCHASING_LIB : $(target-requirements) ; + + # Qt Connectivity (since 5.3) + add-shared-library QtBluetooth : QtCore : QT_BLUETOOTH_LIB : $(target-requirements) ; + add-shared-library QtNfc : QtCore : QT_NFC_LIB : $(target-requirements) ; + + # Gamepad (since 5.7) + add-shared-library QtGamepad : QtCore : QT_GAMEPAD_LIB : $(target-requirements) ; + + # SCXML state machine (since 5.7) + add-shared-library QtScxml : QtCore : QT_SCXML_LIB : $(target-requirements) ; + + # Tech Preview QtQuick + # SerialBus (since 5.7) + add-shared-library QtSerialBus : QtCore : QT_SERIALBUS_LIB : $(target-requirements) ; + + # Platform dependent libraries # Regular expression support add-shared-library QtV8 : QtCore : : $(target-requirements) ; diff --git a/test/qt5/jamroot.jam b/test/qt5/jamroot.jam index 7e50faf01..782922557 100644 --- a/test/qt5/jamroot.jam +++ b/test/qt5/jamroot.jam @@ -48,8 +48,20 @@ if [ qt5.initialized ] # QtQuick version2 [ run qtquick.cpp /qt5//QtQuick : "--" -platform offscreen : $(CWD)/qtquick.qml ] + [ run qtwebengine.cpp /qt5//QtWebEngine ] + [ run qtwebenginewidgets.cpp /qt5//QtWebEngineWidgets ] + + # QtSerialPort + [ run qtserialport.cpp /qt5//QtSerialPort ] + [ run qtlocation.cpp /qt5//QtLocation ] + [ run qtwebchannel.cpp /qt5//QtWebChannel ] + [ run qtwebsockets.cpp /qt5//QtWebSockets ] + [ run qtwebview.cpp /qt5//QtWebView ] + + [ run qtpurchasing.cpp /qt5//QtPurchasing ] + [ run qtcharts.cpp /qt5//QtCharts ] [ run qt3dcore.cpp /qt5//Qt3DCore ] @@ -57,6 +69,19 @@ if [ qt5.initialized ] [ run qt3dinput.cpp /qt5//Qt3DInput ] [ run qt3dlogic.cpp /qt5//Qt3DLogic ] + [ run qtdatavisualization.cpp /qt5//QtDataVisualization ] + + # Qt Connectivity + [ run qtbluetooth.cpp /qt5//QtBluetooth ] + [ run qtnfc.cpp /qt5//QtNfc ] + + [ run qtgamepad.cpp /qt5//QtGamepad ] + + [ run qtscxml.cpp /qt5//QtScxml ] + + [ run qtserialbus.cpp /qt5//QtSerialBus ] + + # Help systems. [ link qthelp.cpp /qt5//QtHelp ] diff --git a/test/qt5/qtbluetooth.cpp b/test/qt5/qtbluetooth.cpp new file mode 100644 index 000000000..53beff17b --- /dev/null +++ b/test/qt5/qtbluetooth.cpp @@ -0,0 +1,34 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtBluetooth + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_BLUETOOTH_LIB), true); +} + +/*! + Try to detect a device + */ +BOOST_AUTO_TEST_CASE( bluetooth ) +{ + QList localAdapters = QBluetoothLocalDevice::allDevices(); + + if (!localAdapters.empty()) + { + QBluetoothLocalDevice adapter(localAdapters.at(0).address()); + adapter.setHostMode(QBluetoothLocalDevice::HostDiscoverable); + } + else + { + BOOST_TEST(localAdapters.size() == 0); + } +} diff --git a/test/qt5/qtdatavisualization.cpp b/test/qt5/qtdatavisualization.cpp new file mode 100644 index 000000000..bc35c04c5 --- /dev/null +++ b/test/qt5/qtdatavisualization.cpp @@ -0,0 +1,31 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtDataVisualization + +#include + +#include + +#include + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_DATAVISUALIZATION_LIB), true); +} + +BOOST_AUTO_TEST_CASE( datavisualization ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QtDataVisualization::Q3DBars graph; + + graph.setShadowQuality(QtDataVisualization::QAbstract3DGraph::ShadowQualitySoftMedium); + graph.activeTheme()->setBackgroundEnabled(false); + graph.activeTheme()->setLabelBackgroundEnabled(true); +} diff --git a/test/qt5/qtgamepad.cpp b/test/qt5/qtgamepad.cpp new file mode 100644 index 000000000..c6c6aea50 --- /dev/null +++ b/test/qt5/qtgamepad.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtGamepad + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GAMEPAD_LIB), true); +} + +/*! + Try to detect a device + */ +BOOST_AUTO_TEST_CASE( gamepad ) +{ + auto gamepads = QGamepadManager::instance()->connectedGamepads(); + if (gamepads.isEmpty()) { + return; + } + + QGamepad gamepad(*gamepads.begin()); +} diff --git a/test/qt5/qtnfc.cpp b/test/qt5/qtnfc.cpp new file mode 100644 index 000000000..df3805f67 --- /dev/null +++ b/test/qt5/qtnfc.cpp @@ -0,0 +1,28 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtNfc + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_NFC_LIB), true); +} + +/*! + Try to detect a device + */ +BOOST_AUTO_TEST_CASE( nfc ) +{ + QNearFieldManager manager; + if (!manager.isAvailable()) + { + BOOST_TEST_MESSAGE("No Nfc"); + } +} diff --git a/test/qt5/qtpurchasing.cpp b/test/qt5/qtpurchasing.cpp new file mode 100644 index 000000000..9a49ed2cc --- /dev/null +++ b/test/qt5/qtpurchasing.cpp @@ -0,0 +1,44 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtPurchasing + +#include + +#include + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_PURCHASING_LIB), true); +} + +class DummyProduct : public QInAppProduct +{ +public: + + DummyProduct() : QInAppProduct{QStringLiteral("One"), + QString{}, + QString{}, + Consumable, + QStringLiteral("DummyProduct"), + nullptr} {}; + void purchase() override {}; +}; + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +BOOST_AUTO_TEST_CASE (purchase) +{ + DummyProduct product; + + BOOST_TEST(product.price() == QLatin1String("One")); + BOOST_TEST(product.identifier() == QLatin1String("DummyProduct")); +} diff --git a/test/qt5/qtscxml.cpp b/test/qt5/qtscxml.cpp new file mode 100644 index 000000000..9e423a18a --- /dev/null +++ b/test/qt5/qtscxml.cpp @@ -0,0 +1,33 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtScxml + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SCXML_LIB), true); +} + +std::ostream& +operator << (std::ostream& stream, QString const& string) +{ + stream << qPrintable(string); + return stream; +} + +/*! + */ +BOOST_AUTO_TEST_CASE( scxml ) +{ + QString sessionId = QScxmlStateMachine::generateSessionId(QStringLiteral("dummy")); + + BOOST_TEST(sessionId.isEmpty() == false); + BOOST_TEST(sessionId == QString{"dummy1"}); +} diff --git a/test/qt5/qtserialbus.cpp b/test/qt5/qtserialbus.cpp new file mode 100644 index 000000000..5849351d8 --- /dev/null +++ b/test/qt5/qtserialbus.cpp @@ -0,0 +1,25 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtSerialBus + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SERIALBUS_LIB), true); +} + +/*! + create a canbus instance + */ +BOOST_AUTO_TEST_CASE( serialBus ) +{ + auto canbus = QCanBus::instance(); + Q_UNUSED(canbus); +} diff --git a/test/qt5/qtserialport.cpp b/test/qt5/qtserialport.cpp new file mode 100644 index 000000000..fd24ed92b --- /dev/null +++ b/test/qt5/qtserialport.cpp @@ -0,0 +1,22 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtSerialPort + +#include + +#include + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_SERIALPORT_LIB), true); +} + +BOOST_AUTO_TEST_CASE( serialport ) +{ + QSerialPort serialPort; + serialPort.setPortName(QStringLiteral("test serialport")); +} diff --git a/test/qt5/qtwebchannel.cpp b/test/qt5/qtwebchannel.cpp new file mode 100644 index 000000000..e4f05b7f2 --- /dev/null +++ b/test/qt5/qtwebchannel.cpp @@ -0,0 +1,29 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtWebChannel + +#include + +#include + +#include + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBCHANNEL_LIB), true); +} + +BOOST_AUTO_TEST_CASE( webchannel ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QWebChannel channel; + QObject dummy; + channel.registerObject(QStringLiteral("dummy"), &dummy); +} diff --git a/test/qt5/qtwebengine.cpp b/test/qt5/qtwebengine.cpp new file mode 100644 index 000000000..d4c1b0726 --- /dev/null +++ b/test/qt5/qtwebengine.cpp @@ -0,0 +1,30 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtWebEngine + +#include +#include + + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_GUI_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINE_LIB), true); +} + +/*! + Just call the global initialization function + */ +BOOST_AUTO_TEST_CASE( webengine ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QtWebEngine::initialize(); +} diff --git a/test/qt5/qtwebenginewidgets.cpp b/test/qt5/qtwebenginewidgets.cpp new file mode 100644 index 000000000..f0c3c2d8b --- /dev/null +++ b/test/qt5/qtwebenginewidgets.cpp @@ -0,0 +1,40 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtWebEngineWidgets + +#include + +#include +#include +#include + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WIDGETS_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINECORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINEWIDGETS_LIB), true); +} + +/*! + Also tests the core library + */ +BOOST_AUTO_TEST_CASE( webengine_widgets ) +{ + QApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QWebEngineSettings *defaultSettings = QWebEngineSettings::globalSettings(); + QWebEngineProfile *defaultProfile = QWebEngineProfile::defaultProfile(); + + defaultSettings->setAttribute(QWebEngineSettings::FullScreenSupportEnabled, true); + defaultProfile->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies); +} diff --git a/test/qt5/qtwebsocket.cpp b/test/qt5/qtwebsocket.cpp new file mode 100644 index 000000000..f46aa58b3 --- /dev/null +++ b/test/qt5/qtwebsocket.cpp @@ -0,0 +1,26 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtWebSockets + +#include + +#include + +#include + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBSOCKETS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( websocket ) +{ + QCoreApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QWebSocket socket; +} diff --git a/test/qt5/qtwebsockets.cpp b/test/qt5/qtwebsockets.cpp new file mode 100644 index 000000000..9829ce916 --- /dev/null +++ b/test/qt5/qtwebsockets.cpp @@ -0,0 +1,24 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtWebSockets + +#include + +#include + +BOOST_AUTO_TEST_CASE (defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBSOCKETS_LIB), true); +} + +BOOST_AUTO_TEST_CASE( websocket ) +{ + QWebSocket socket; + socket.setPauseMode(QAbstractSocket::PauseNever); + + BOOST_TEST(socket.isValid() == false); +} diff --git a/test/qt5/qtwebview.cpp b/test/qt5/qtwebview.cpp new file mode 100644 index 000000000..dfd130f37 --- /dev/null +++ b/test/qt5/qtwebview.cpp @@ -0,0 +1,31 @@ +// (c) Copyright Juergen Hunold 2016 +// Use, modification and distribution is subject to 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) + +#define BOOST_TEST_MODULE QtWebView + +#include + +#include + +#include + +BOOST_AUTO_TEST_CASE( defines) +{ + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_CORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBENGINECORE_LIB), true); + BOOST_CHECK_EQUAL(BOOST_IS_DEFINED(QT_WEBVIEW_LIB), true); +} + +/*! + Just call the global initialization function + */ +BOOST_AUTO_TEST_CASE( webview ) +{ + QGuiApplication app(boost::unit_test::framework::master_test_suite().argc, + boost::unit_test::framework::master_test_suite().argv); + + QtWebView::initialize(); +} From 72ff0b63ff2b875d356713ec5cbc6f3e56d5a1b3 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 10:17:54 -0700 Subject: [PATCH 006/158] Fix setup script handling for msvc-7.1. * global-setup doesn't exist. * cpu should only be i386. --- src/tools/msvc.jam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/msvc.jam b/src/tools/msvc.jam index f3561db20..78e64e684 100644 --- a/src/tools/msvc.jam +++ b/src/tools/msvc.jam @@ -793,7 +793,7 @@ actions write-setup-script # 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 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) ; @@ -960,7 +960,7 @@ local rule configure-really ( version ? : options * ) { cpu = i386 ; } - if $(below-11.0) + else if $(below-11.0) { cpu = i386 amd64 ia64 ; } From 7a59e03049e021234a341fa6bb55606414380f20 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 10:44:56 -0700 Subject: [PATCH 007/158] Fix test on windows. We shouldn't assume that W32_GETREGNAMES returns its results in any particular order. --- test/core-language/test.jam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/core-language/test.jam b/test/core-language/test.jam index 2853c736d..b0ac767ef 100644 --- a/test/core-language/test.jam +++ b/test/core-language/test.jam @@ -1457,9 +1457,9 @@ if $(NT) local sound = "Beep" "ExtendedSounds" ; local r1 = [ W32_GETREGNAMES "HKEY_CURRENT_USER\\Control Panel\\Sound" : values ] ; - check-equal w32_getregnames : $(sound:L) : $(r1:L) ; + check-equal w32_getregnames : $(sound:L) : [ SORT $(r1:L) ] ; local r2 = [ W32_GETREGNAMES "HKCU\\Control Panel\\Sound" : values ] ; - check-equal w32_getregnames : $(sound:L) : $(r2:L) ; + check-equal w32_getregnames : $(sound:L) : [ SORT $(r2:L) ] ; # Some Windows platforms may have additional keys under # 'CurrentControlSet' which we then remove here so they would not be From 9da5a06af89ccc2acaef64d07fe22cd43f8cca1b Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 11:22:20 -0700 Subject: [PATCH 008/158] Add missing header. Without this OS_CYGWIN is not defined which causes the :W modifier to fail. --- src/engine/pathnt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/pathnt.c b/src/engine/pathnt.c index 077dc3b1b..fcffe24df 100644 --- a/src/engine/pathnt.c +++ b/src/engine/pathnt.c @@ -16,8 +16,8 @@ * pathnt.c - NT specific path manipulation support */ +#include "jam.h" #include "pathsys.h" - #include "hash.h" #define WIN32_LEAN_AND_MEAN From f5e005e8f3ccc9dac62a2bc34b83c904ea5e1298 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 11:32:34 -0700 Subject: [PATCH 009/158] Fix memory leak on cygwin and vms. path_copy initializes a new string. It should never be used on a string that is already initialized. --- src/engine/pathnt.c | 3 ++- src/engine/pathvms.c | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/engine/pathnt.c b/src/engine/pathnt.c index fcffe24df..bde5cd0b8 100644 --- a/src/engine/pathnt.c +++ b/src/engine/pathnt.c @@ -345,7 +345,8 @@ static int translate_path_cyg2win( string * path ) if ( result ) { - string_copy( path, result ); + string_truncate( path, 0 ); + string_append( path, result ); translated = 1; } diff --git a/src/engine/pathvms.c b/src/engine/pathvms.c index 01f3f90d9..5882d40af 100644 --- a/src/engine/pathvms.c +++ b/src/engine/pathvms.c @@ -174,15 +174,25 @@ static int translate_path_posix2vms( string * path ) && stat(as_file->value, &statbuf ) > 0 && ( statbuf.st_mode & S_IFREG ) ) { - string_copy( path, as_file->value ); + string_truncate( path, 0 ); + string_append( path, as_file->value ); } else { - string_copy( path, as_dir->value ); + string_truncate( path, 0 ); + string_append( path, as_dir->value ); } } - else if ( file_count ) { string_copy( path, as_file->value ); } - else if ( dir_count ) { string_copy( path, as_dir->value ); } + else if ( file_count ) + { + string_truncate( path, 0 ); + string_append( path, as_file->value ); + } + else if ( dir_count ) + { + string_truncate( path, 0 ); + string_append( path, as_dir->value ); + } else { /* error: unable to translate path to native format */ From e2d07ad6db55dbd896f9177c7d2c4cc3a9f187de Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 12:48:38 -0700 Subject: [PATCH 010/158] Make sure that source files end with a newline. --- src/build/ac.jam | 2 +- test/bzip2.py | 2 +- test/zlib.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/build/ac.jam b/src/build/ac.jam index c4bd6b7e1..c6e36c6a5 100644 --- a/src/build/ac.jam +++ b/src/build/ac.jam @@ -26,7 +26,7 @@ rule generate-include ( target : sources * : properties * ) { local header = [ property.select : $(properties) ] ; print.output $(target) ; - print.text "#include <$(header:G=)>" : true ; + print.text "#include <$(header:G=)>\n" : true ; } rule generate-main ( target : sources * : properties * ) diff --git a/test/bzip2.py b/test/bzip2.py index b966eb718..4e74c6023 100755 --- a/test/bzip2.py +++ b/test/bzip2.py @@ -39,7 +39,7 @@ t.rm('bzip2') common_stuff = ''' source_file('test.cpp', 'test.cpp') source_file('main.cpp', 'int main() {}') -source_file('bzlib.h.cpp', '#include ') +source_file('bzlib.h.cpp', '#include \\n') action('-c -x c++ $main.cpp -o $main.o') ''' t.write('test.cpp', 'test.cpp') diff --git a/test/zlib.py b/test/zlib.py index 2821bd744..0bb8269ad 100755 --- a/test/zlib.py +++ b/test/zlib.py @@ -39,7 +39,7 @@ t.rm('zlib') common_stuff = ''' source_file('test.cpp', 'test.cpp') source_file('main.cpp', 'int main() {}') -source_file('zlib.h.cpp', '#include ') +source_file('zlib.h.cpp', '#include \\n') action('-c -x c++ $main.cpp -o $main.o') ''' t.write('test.cpp', 'test.cpp') From 6ece5736bcf099b4ff9c65ae6ea65142fa67314f Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 13:15:19 -0700 Subject: [PATCH 011/158] Junctions should be removed with rmdir, not del. This fixes a bug that causes -a --reconfigure to decide that junctions are not supported. --- src/tools/link.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/link.jam b/src/tools/link.jam index 944911b3e..50ec485c6 100644 --- a/src/tools/link.jam +++ b/src/tools/link.jam @@ -488,7 +488,7 @@ if [ os.name ] = NT actions junction { - if exist "$(<)" del "$(<)" + if exist "$(<)" rmdir "$(<)" mklink /J "$(<)" "$(>)" } From b5dc9949d05d1aa1548020eaa908b8010fd45f9d Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 1 Mar 2016 15:58:10 -0700 Subject: [PATCH 012/158] Fix building bzip2 from source as a shared library. bzip2 doesn't use a macro to control symbol export. Instead it provides a .def file, which we need to pass to the linker. --- src/tools/bzip2.jam | 50 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/tools/bzip2.jam b/src/tools/bzip2.jam index a994a70ef..0a525905c 100644 --- a/src/tools/bzip2.jam +++ b/src/tools/bzip2.jam @@ -20,6 +20,9 @@ import path ; import modules ; import errors ; import indirect ; +import make ; +import os ; +import print ; import property ; import property-set ; @@ -167,6 +170,7 @@ rule init ( tag = [ indirect.make $(tag) : [ $(caller).project-module ] ] ; } sources = [ path.glob $(source-path) : $(sources) ] ; + def-file = [ path.glob $(source-path) : libbz2.def ] ; if $(.debug) { ECHO "notice: [bzip2] Building bzip from source as $(build-name)" ; @@ -184,7 +188,15 @@ rule init ( } } local target ; - if $(sources) { + if $(sources) + { + if ! $(.def-file-target) + { + .def-file-target = [ targets.create-metatarget make-target-class + : $(.project) : libbz2.def : $(def-file) + : @bzip2.make-bz2-def-file ] + ; + } target = [ targets.create-typed-target LIB : $(.project) : $(build-name).$(library-id) : $(sources) @@ -193,7 +205,7 @@ rule init ( $(source-path) msvc:_CRT_SECURE_NO_DEPRECATE msvc:_SCL_SECURE_NO_DEPRECATE - shared:BZIP2_DLL + shared:libbz2.def : : $(source-path) ] ; } @@ -224,3 +236,37 @@ rule init ( } .configured.$(condition) = true ; } + +if [ os.name ] = NT +{ + local rule read-file ( file ) + { + return [ SPLIT_BY_CHARACTERS [ SHELL "type \"$(file:G=)\" 2>nul" ] : "\n" ] ; + } +} +else if [ os.name ] = VMS +{ + local rule read-file ( file ) + { + return [ SPLIT_BY_CHARACTERS [ SHELL "PIPE TYPE $(file:W) 2>NL:" ] : "\n" ] ; + } +} +else +{ + local rule read-file ( file ) + { + return [ SPLIT_BY_CHARACTERS [ SHELL "cat \"$(file:G=)\" 2>/dev/null" ] : "\n" ] ; + } +} + +rule make-bz2-def-file ( target : source : properties * ) +{ + print.output $(target) ; + for local line in [ read-file $(source) ] + { + if ! [ MATCH "(LIBRARY[ \t]+LIBBZ2)" : $(line) ] + { + print.text $(line) : yes ; + } + } +} From 8f39cdebc9c28c8ff6cc78dbf8a5a50cb8192e9d Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 4 Mar 2016 11:08:28 -0700 Subject: [PATCH 013/158] Fix two memory leaks and a double free. --- src/engine/function.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/function.c b/src/engine/function.c index 270fbaff9..89f8dfe51 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -574,9 +574,9 @@ static LIST * function_call_member_rule( JAM_FUNCTION * function, FRAME * frame, } } + list_free( first ); result = evaluate_rule( rule, real_rulename, inner ); frame_free( inner ); - object_free( rulename ); object_free( real_rulename ); return result; } @@ -4230,6 +4230,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) result = var_get( frame->module, varname ) ; } } + list_free( targets ); stack_push( s, list_copy( result ) ); break; } From f00b27cf5a7d87bcb87c7aef924167bbe7bbc972 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 4 Mar 2016 11:11:40 -0700 Subject: [PATCH 014/158] NDEBUG disables OBJECT_MAGIC. --- src/engine/object.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/object.c b/src/engine/object.c index 02440d2d1..07866baf4 100644 --- a/src/engine/object.c +++ b/src/engine/object.c @@ -259,7 +259,9 @@ OBJECT * object_new_range( char const * const string, int const size ) strtotal += size + 1; memcpy( m->data, string, size ); m->data[ size ] = '\0'; +#ifndef NDEBUG m->header.magic = OBJECT_MAGIC; +#endif return (OBJECT *)m->data; } #else From b015a40847adfb338ed226ba82670d14b2ae7f75 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 4 Mar 2016 11:38:50 -0700 Subject: [PATCH 015/158] Don't close the file automatically in yyline. We need yylval.file to survive until the parser is really done. --- src/engine/parse.c | 2 ++ src/engine/scan.c | 26 +++++++++++++++++--------- src/engine/scan.h | 1 + 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/engine/parse.c b/src/engine/parse.c index 02412e085..71c38764e 100644 --- a/src/engine/parse.c +++ b/src/engine/parse.c @@ -57,6 +57,8 @@ void parse_file( OBJECT * f, FRAME * frame ) list_free( function_run( func, frame, stack_global() ) ); function_free( func ); } + + yyfdone(); } diff --git a/src/engine/scan.c b/src/engine/scan.c index 324be0c72..73188a692 100644 --- a/src/engine/scan.c +++ b/src/engine/scan.c @@ -104,6 +104,22 @@ void yyfparse( OBJECT * s ) } +/* + * yyfdone() - cleanup after we're done parsing a file. + */ +void yyfdone( void ) +{ + include * const i = incp; + incp = i->next; + + /* Close file, free name. */ + if(i->file && (i->file != stdin)) + fclose(i->file); + object_free(i->fname); + BJAM_FREE((char *)i); +} + + /* * yyline() - read new line and return first character. * @@ -157,18 +173,10 @@ int yyline() } } - /* This include is done. Free it up and return EOF so yyparse() returns to + /* This include is done. Return EOF so yyparse() returns to * parse_file(). */ - incp = i->next; - - /* Close file, free name. */ - if ( i->file && ( i->file != stdin ) ) - fclose( i->file ); - object_free( i->fname ); - BJAM_FREE( (char *)i ); - return EOF; } diff --git a/src/engine/scan.h b/src/engine/scan.h index 745477fc1..371d6514f 100644 --- a/src/engine/scan.h +++ b/src/engine/scan.h @@ -51,6 +51,7 @@ void yymode( int n ); void yyerror( char const * s ); int yyanyerrors(); void yyfparse( OBJECT * s ); +void yyfdone( void ); int yyline(); int yylex(); int yyparse(); From aaeedea9ccd1cc5db566e371de7efd437cf72bb4 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Fri, 4 Mar 2016 12:28:42 -0700 Subject: [PATCH 016/158] Fix a leak and a missing copy when building with the global string table disabled. --- src/engine/modules/property-set.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/modules/property-set.c b/src/engine/modules/property-set.c index 21e35d5ab..aee1f2ff0 100644 --- a/src/engine/modules/property-set.c +++ b/src/engine/modules/property-set.c @@ -82,6 +82,7 @@ static void ps_map_destroy( struct ps_map * map ) for ( pos = map->table[ i ]; pos; ) { struct ps_map_entry * tmp = pos->next; + object_free( pos->value ); BJAM_FREE( pos ); pos = tmp; } @@ -164,7 +165,7 @@ LIST * property_set_create( FRAME * frame, int flags ) list_new( object_new( "property-set" ) ), 0 ); LISTITER iter, end; object_free( rulename ); - pos->value = list_front( val ); + pos->value = object_copy( list_front( val ) ); var_set( bindmodule( pos->value ), varname, unique, VAR_SET ); object_free( varname ); From de9a6001675fbedec45bb20061be3a98829587a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20G=C3=B3rny?= Date: Sun, 6 Mar 2016 18:20:51 +0100 Subject: [PATCH 017/158] Do not pass -Ofast to pathscale toolset Do not pass -Ofast when using the pathscale toolset. It enables insecure optimizations, and that is probably why no other toolset uses this option. It also causes internal compiler problems with current pathcc versions. --- src/engine/build.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/build.jam b/src/engine/build.jam index 787b2306c..ad2ea3580 100644 --- a/src/engine/build.jam +++ b/src/engine/build.jam @@ -304,7 +304,7 @@ toolset qcc qcc : "-o " : -D ## Qlogic Pathscale 2.4 toolset pathscale pathcc : "-o " : -D : - [ opt --release : -s -Ofast -O3 ] + [ opt --release : -s -O3 ] [ opt --debug : -g ] -I$(--python-include) -I$(--extra-include) : -L$(--python-lib[1]) -l$(--python-lib[2]) ; From 8b9dbbe418c6cf889444f2cd6239ae1605c2f27a Mon Sep 17 00:00:00 2001 From: Kohei Takahashi Date: Mon, 29 Feb 2016 22:47:12 +0900 Subject: [PATCH 018/158] Add support for FreeBSD 10 or later. Since FreeBSD 10, it uses clang as a system default compiler. freebsd-version is used to detect FreeBSD version. --- bootstrap.sh | 2 +- src/engine/build.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/bootstrap.sh b/bootstrap.sh index c99242ee8..bbb035063 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -57,7 +57,7 @@ my_dir="." if test "x$TOOLSET" = x; then guessed_toolset=`$my_dir/src/engine/build.sh --guess-toolset` case $guessed_toolset in - acc | darwin | gcc | como | mipspro | pathscale | pgi | qcc | vacpp | xlcpp ) + acc | darwin | gcc | como | mipspro | pathscale | pgi | qcc | vacpp | xlcpp | clang ) TOOLSET=$guessed_toolset ;; diff --git a/src/engine/build.sh b/src/engine/build.sh index 1470b480e..1d0dcc892 100755 --- a/src/engine/build.sh +++ b/src/engine/build.sh @@ -77,6 +77,7 @@ Guess_Toolset () BOOST_JAM_TOOLSET=vacpp fi elif test_uname AIX && test_path xlc; then BOOST_JAM_TOOLSET=vacpp + elif test_uname FreeBSD && test_path freebsd-version && test_path clang; then BOOST_JAM_TOOLSET=clang elif test_path gcc ; then BOOST_JAM_TOOLSET=gcc elif test_path icc ; then BOOST_JAM_TOOLSET=intel-linux elif test -r /opt/intel/cc/9.0/bin/iccvars.sh ; then From 25819cbda34d179b505243e3ebdb971df3ed2afe Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 22 Mar 2016 09:50:51 -0600 Subject: [PATCH 019/158] Make sure that explicit returns don't interfere with function rewriting. --- src/engine/function.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/engine/function.c b/src/engine/function.c index 89f8dfe51..510acbde4 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -2889,7 +2889,7 @@ static void compile_parse( PARSE * parse, compiler * c, int result_location ) { compile_parse( parse->left, c, RESULT_RETURN ); compile_emit_cleanups( c, 0 ); - compile_emit( c, INSTR_RETURN, 0 ); + compile_emit( c, INSTR_RETURN, 0 ); /* 0 for return in the middle of a function. */ } else if ( parse->type == PARSE_BREAK ) { @@ -2961,7 +2961,7 @@ FUNCTION * function_compile( PARSE * parse ) JAM_FUNCTION * result; compiler_init( c ); compile_parse( parse, c, RESULT_RETURN ); - compile_emit( c, INSTR_RETURN, 0 ); + compile_emit( c, INSTR_RETURN, 1 ); result = compile_to_function( c ); compiler_free( c ); result->file = object_copy( parse->file ); @@ -2981,7 +2981,7 @@ FUNCTION * function_compile_actions( char const * actions, OBJECT * file, compiler_init( c ); var_parse_actions_compile( parse, c ); var_parse_actions_free( parse ); - compile_emit( c, INSTR_RETURN, 0 ); + compile_emit( c, INSTR_RETURN, 1 ); result = compile_to_function( c ); compiler_free( c ); result->file = object_copy( file ); @@ -3612,7 +3612,9 @@ FUNCTION * function_bind_variables( FUNCTION * f, module_t * module, case INSTR_SET: op_code = INSTR_SET_FIXED; break; case INSTR_APPEND: op_code = INSTR_APPEND_FIXED; break; case INSTR_DEFAULT: op_code = INSTR_DEFAULT_FIXED; break; - case INSTR_RETURN: return (FUNCTION *)new_func; + case INSTR_RETURN: + if( code->arg == 1 ) return (FUNCTION *)new_func; + else continue; case INSTR_CALL_MEMBER_RULE: case INSTR_CALL_RULE: ++i; continue; case INSTR_PUSH_MODULE: From e6116e7567c338fb20ffb5b904857789c9765a8a Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Tue, 22 Mar 2016 10:18:13 -0600 Subject: [PATCH 020/158] Clean up formatting/undefined variables/odd control flow in zlib and bzip2. --- src/tools/bzip2.jam | 18 +++++++++--------- src/tools/zlib.jam | 21 +++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/tools/bzip2.jam b/src/tools/bzip2.jam index 0a525905c..ae9a03909 100644 --- a/src/tools/bzip2.jam +++ b/src/tools/bzip2.jam @@ -137,13 +137,11 @@ rule init ( [ property.select : $(options) ] "and" [ property.select : $(options) ] ; } - else - { - no-build-from-source = true ; - } } - - source-path ?= [ modules.peek : BZIP2_SOURCE ] ; + else + { + source-path ?= [ modules.peek : BZIP2_SOURCE ] ; + } if $(.configured.$(condition)) { @@ -160,7 +158,7 @@ rule init ( } return ; } - else if $(source-path) && ! $(no-build-from-source) + else if $(source-path) { build-name ?= bz2 ; library-id = [ CALC $(library-id) + 1 ] ; @@ -218,7 +216,9 @@ rule init ( $(mt).set-target $(target) ; } targets.main-target-alternative $(mt) ; - } else { + } + else + { if $(.debug) { ECHO "notice: [bzip2] Using pre-installed library" ; @@ -229,7 +229,7 @@ rule init ( } local mt = [ new ac-library bzip2 : $(.project) : $(condition) : - $(include-path) : $(library-path) : $(library-name) : $(root) ] ; + $(include-path) : $(library-path) : $(library-name) ] ; $(mt).set-header $(header) ; $(mt).set-default-names $(names) ; targets.main-target-alternative $(mt) ; diff --git a/src/tools/zlib.jam b/src/tools/zlib.jam index 8095eeeee..5a7d5fbdf 100644 --- a/src/tools/zlib.jam +++ b/src/tools/zlib.jam @@ -135,13 +135,11 @@ rule init ( [ property.select : $(options) ] "and" [ property.select : $(options) ] ; } - else - { - no-build-from-source = true ; - } } - - source-path ?= [ modules.peek : ZLIB_SOURCE ] ; + else + { + source-path ?= [ modules.peek : ZLIB_SOURCE ] ; + } if $(.configured.$(condition)) { @@ -158,7 +156,7 @@ rule init ( } return ; } - else if $(source-path) && ! $(no-build-from-source) + else if $(source-path) { build-name ?= z ; library-id = [ CALC $(library-id) + 1 ] ; @@ -185,7 +183,8 @@ rule init ( } } local target ; - if $(sources) { + if $(sources) + { target = [ targets.create-typed-target LIB : $(.project) : $(build-name).$(library-id) : $(sources) @@ -207,7 +206,9 @@ rule init ( $(mt).set-target $(target) ; } targets.main-target-alternative $(mt) ; - } else { + } + else + { if $(.debug) { ECHO "notice: [zlib] Using pre-installed library" ; @@ -218,7 +219,7 @@ rule init ( } local mt = [ new ac-library zlib : $(.project) : $(condition) : - $(include-path) : $(library-path) : $(library-name) : $(root) ] ; + $(include-path) : $(library-path) : $(library-name) ] ; $(mt).set-header $(header) ; $(mt).set-default-names $(names) ; targets.main-target-alternative $(mt) ; From 37ba13295cbed023c41a677b0fa57f9f59696b8e Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 23 Mar 2016 18:04:24 -0600 Subject: [PATCH 021/158] Remove wrong if. This case is already handled correctly by the next else if. --- src/engine/filent.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/engine/filent.c b/src/engine/filent.c index 4f19a56b5..9802dcb0a 100644 --- a/src/engine/filent.c +++ b/src/engine/filent.c @@ -227,10 +227,7 @@ int try_file_query_root( file_info_t * const info ) } else if ( pathstr[ 1 ] == ':' ) { - if ( !pathstr[ 2 ] ) - { - } - else if ( !pathstr[ 2 ] || ( pathstr[ 2 ] == '\\' && !pathstr[ 3 ] ) ) + if ( !pathstr[ 2 ] || ( pathstr[ 2 ] == '\\' && !pathstr[ 3 ] ) ) { buf[ 0 ] = pathstr[ 0 ]; buf[ 1 ] = ':'; From 1dd163c51cba63dde8301574963dd305088e73c7 Mon Sep 17 00:00:00 2001 From: "K. Noel Belcourt" Date: Fri, 8 Apr 2016 20:05:50 -0600 Subject: [PATCH 022/158] Darwin (gcc under El Capitan) no longer supports the -finline-functions option. Override the full option to just pass -Wno-inline only if on 10.11 or later. --- src/tools/darwin.jam | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/tools/darwin.jam b/src/tools/darwin.jam index edd6b7a4e..ceb2c6d3c 100644 --- a/src/tools/darwin.jam +++ b/src/tools/darwin.jam @@ -66,7 +66,8 @@ toolset.inherit-flags darwin : gcc x86/ power/32 power/64 - power/ ; + power/ + full ; # Options: # @@ -149,6 +150,12 @@ rule init ( version ? : command * : options * : requirement * ) # - GCC on Darwin with -pedantic, suppress unsupported long long warning flags darwin.compile OPTIONS $(condition)/all : -Wno-long-long ; + # - GCC on El Capitan (10.11) does not suport -finline-functions + if "10.11.0" <= $(.host-osx-version) + { + flags darwin.compile OPTIONS $(condition)/full : -Wno-inline ; + } + # - Set the link flags common with the GCC toolset. gcc.init-link-flags darwin darwin $(condition) ; From 786a5c5e65cf84c6cb2b7eb48f77bad6fc47d071 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Thu, 14 Apr 2016 08:49:00 -0600 Subject: [PATCH 023/158] If we can't find the python headers and libraries, abort configuration. Otherwise, we would attempt to build Boost.Python unconditionally. --- src/tools/python.jam | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 0139b033d..3ecd89764 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -797,13 +797,11 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : } } - # Anything left to compute? + # Check whether configuration succeeded. if ! ( $(includes) && $(libraries) ) { - version ?= $(fallback-version) ; - version ?= 2.5 ; - exec-prefix ?= $(prefix) ; - compute-default-paths $(target-os) : $(version) : $(prefix:E=) ; + debug-message Python headers and libraries not found. ; + return ; } .configured = true ; From 1e6a12f5bd206be547c832ddea4ad51c2625a43f Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Fri, 29 Apr 2016 07:58:50 -0400 Subject: [PATCH 024/158] Documentation fixes, largely grammar and spelling corrections. --- doc/src/overview.xml | 12 ++++++------ doc/src/reference.xml | 39 ++++++++++++++++++++++----------------- doc/src/tasks.xml | 14 +++++++------- doc/src/tutorial.xml | 16 ++++++++-------- 4 files changed, 43 insertions(+), 38 deletions(-) diff --git a/doc/src/overview.xml b/doc/src/overview.xml index 1c2310b96..04c1c7754 100644 --- a/doc/src/overview.xml +++ b/doc/src/overview.xml @@ -107,7 +107,7 @@ a.o: a.c add_program ("a", "a.c") - This is a function call that creates the targets necessary to create a executable file + This is a function call that creates the targets necessary to create an executable file from the source file a.c. Depending on configured properties, different command lines may be used. However, add_program is higher-level, but rather thin level. All targets are created immediately when the build description @@ -675,10 +675,10 @@ b2 toolset=gcc variant=debug optimization=space Changes the build directories for all project roots being built. When this option is specified, all Jamroot files must declare a project name. - The build directory for the project root will be computed by concatanating + The build directory for the project root will be computed by concatenating the value of the option, the project name specified in Jamroot, and the build dir specified in Jamroot - (or bin, if none is specified). + (or bin.v2, if none is specified). The option is primarily useful when building from read-only @@ -782,12 +782,12 @@ b2 toolset=gcc variant=debug optimization=space - Enable cummulative debugging levels from 1 to n. Values are: + Enable cumulative debugging levels from 1 to n. Values are: Show the actions taken for building targets, as they are executed (the default). Show "quiet" actions and display all action text, as they are executed. Show dependency analysis, and target/source timestamps/paths. - Show arguments and timming of shell invocations. + Show arguments and timing of shell invocations. Show rule invocations and variable expansions. Show directory/header file/archive scans, and attempts at binding to targets. Show variable settings. @@ -1595,7 +1595,7 @@ b2 app1 lib1//lib1 gcc debug optimization=full Selecting the main target alternative to use. For each alternative we look how many properties are present both in alternative's requirements, and in build request. The - alternative with large number of matching properties is selected. + alternative with largest number of matching properties is selected. Determining "common" properties. diff --git a/doc/src/reference.xml b/doc/src/reference.xml index a66eb75a6..6c7e31540 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -50,7 +50,7 @@ boost-build build-system ; automatically find the build system. The default bootstrap.jam, after loading some standard - definitions, loads two site-config.jam and user-config.jam. + definitions, loads both site-config.jam and user-config.jam. @@ -165,7 +165,7 @@ lib tools : [ glob *.cpp ] ; It is possible to also pass a second argument—the list of exclude patterns. The result will then include the list of - files patching any of include patterns, and not matching any + files matching any of include patterns, and not matching any of the exclude patterns. For example: lib tools : [ glob *.cpp : file_to_exclude.cpp bad*.cpp ] ; @@ -561,13 +561,15 @@ path-constant DATA : data/a.txt ; cflags cxxflags + compileflags linkflags The value of those features is passed without modification to the - corresponding tools. For cflags that is both the C and - C++ compilers, for cxxflags that is the C++ compiler + corresponding tools. For cflags that is C compiler, + for cxxflags that is the C++ compiler, + for compileflags that is both the C and C++ compilers, and for linkflags that is the linker. The features are handy when you are trying to do something special that cannot be achieved by a higher-level feature in Boost.Build. @@ -672,7 +674,7 @@ path-constant DATA : data/a.txt ; Allowed values: on, off. The debug-symbols feature specifies if - produced object files, executables and libraries should include + produced object files, executables, and libraries should include debug information. Typically, the value of this feature is implicitly set by the variant feature, but it can be explicitly @@ -686,8 +688,8 @@ path-constant DATA : data/a.txt ; Allowed values: on, off. - The runtime-debugging feature specifies if - produced object files, executables and libraries should include + The runtime-debugging feature specifies that, + if produced, object files, executables, and libraries should include behaviour useful only for debugging, such as asserts. Typically, the value of this feature is implicitly set by the variant feature, but it can be explicitly @@ -937,7 +939,7 @@ using gcc : &toolset_ops; ; Specifies the archiver command that is used to produce static libraries. Normally, it is autodetected using gcc -print-prog-name option or defaulted to ar, - but in some cases you might want to override it, for example to expliitly + but in some cases you might want to override it, for example to explicitly use a system version instead of one included with gcc. @@ -949,7 +951,7 @@ using gcc : &toolset_ops; ; Specifies the ranlib command that is used to generated symbol table for static libraries. Normally, it is autodetected using gcc -print-prog-name option or defaulted to ranlib, - but in some cases you might want to override it, for example to expliitly + but in some cases you might want to override it, for example to explicitly use a system version instead of one included with gcc. @@ -1021,6 +1023,9 @@ using gcc : &toolset_ops; ; C++ command-line tools on Microsoft Windows. The supported products and versions of command line tools are listed below: + Visual Studio 2015—14.0 + Visual Studio 2013—12.0 + Visual Studio 2012—11.0 Visual Studio 2010—10.0 Visual Studio 2008—9.0 Visual Studio 2005—8.0 @@ -1058,7 +1063,7 @@ using msvc : &toolset_ops; ; The command that compiles assembler sources. If not specified, ml will be used. The command will be invoked after the setup script was executed and adjusted - the PATH variable. + by the PATH variable. @@ -1067,7 +1072,7 @@ using msvc : &toolset_ops; ; The command that compiles C and C++ sources. If not specified, cl will be used. The command will be invoked after the setup script was executed and adjusted - the PATH variable. + by the PATH variable. @@ -1084,7 +1089,7 @@ using msvc : &toolset_ops; ; The command that compiles Microsoft COM interface definition files. If not specified, midl will be used. The command will be invoked after the setup script was - executed and adjusted the PATH variable. + executed and adjusted by the PATH variable. @@ -1094,7 +1099,7 @@ using msvc : &toolset_ops; ; The command that links executables and dynamic libraries. If not specified, link will be used. The command will be invoked after the setup script was executed - and adjusted the PATH variable. + and adjusted by the PATH variable. @@ -1103,7 +1108,7 @@ using msvc : &toolset_ops; ; The command that compiles Microsoft message catalog files. If not specified, mc will be used. The command will be invoked after the setup script was - executed and adjusted the PATH variable. + executed and adjusted by the PATH variable. @@ -1112,7 +1117,7 @@ using msvc : &toolset_ops; ; The command that compiles resource files. If not specified, rc will be used. The command will be - invoked after the setup script was executed and adjusted the + invoked after the setup script was executed and adjusted by the PATH variable. @@ -1443,7 +1448,7 @@ using cw : &toolset_ops; ; The command that compiles C and C++ sources. If not specified, mwcc will be used. The command will be invoked after the setup script was - executed and adjusted the PATH variable. + executed and adjusted by the PATH variable. @@ -1454,7 +1459,7 @@ using cw : &toolset_ops; ; libraries. If not specified, mwld will be used. The command will be invoked after the setup script was - executed and adjusted the PATH variable. + executed and adjusted by the PATH variable. diff --git a/doc/src/tasks.xml b/doc/src/tasks.xml index 8ff82f0b8..a4a357986 100644 --- a/doc/src/tasks.xml +++ b/doc/src/tasks.xml @@ -520,7 +520,7 @@ unit-test helpers_test By default, the executable is run directly. Sometimes, it is desirable to run the executable using some helper command. You - should use the this property to specify the name of the helper + should use this property to specify the name of the helper command. For example, if you write: unit-test helpers_test @@ -530,7 +530,7 @@ unit-test helpers_test The command used to run the executable will be: -valgrind bin/$toolset/debug/helpers_test +valgrind bin.v2/$toolset/debug/helpers_test @@ -575,7 +575,7 @@ unit-test helpers_test Boost.Build's virtual targets. This is higher-level than the file names that the make rule operates with and allows you to create more than one target, create differently named targets depending on - properties or use more than one tool. + properties, or use more than one tool. @@ -764,7 +764,7 @@ exe main : main.cpp pch ; "parser.y". The latter source is converted into "parser.c" and "parser.h". Then, if "app.cpp" includes "parser.h", Boost.Build will detect this dependency. Moreover, since "parser.h" will be generated into a build - directory, the path to that directory will automatically added to include + directory, the path to that directory will automatically be added to the include path. @@ -800,14 +800,14 @@ using gcc : arm : arm-none-linux-gnueabi-g++ ; After that, if the host and target os are the same, for example Linux, you can - just request that this compiler version to be used: + just request that this compiler version be used: b2 toolset=gcc-arm - If you want to target different operating system from the host, you need + If you want to target a different operating system from the host, you need to additionally specify the value for the target-os feature, for example: @@ -823,7 +823,7 @@ b2 toolset=gcc-mingw target-os=windows - When using the msvc compiler, it's only possible to cross-compiler to a 64-bit system + When using the msvc compiler, it's only possible to cross-compile to a 64-bit system on a 32-bit host. Please see for details. diff --git a/doc/src/tutorial.xml b/doc/src/tutorial.xml index 3227a6718..727c912cc 100644 --- a/doc/src/tutorial.xml +++ b/doc/src/tutorial.xml @@ -179,7 +179,7 @@ exe hello See - augments) the build request. + augment) the build request. @@ -280,8 +280,8 @@ top/ in their requirements, too. Of course, any project can add include paths to those specified by its parents. Many - features will be overridden, - rather than added-to, in subprojects. See for more information @@ -384,7 +384,7 @@ project lib foo : foo.cpp ; Usage requirements are applied not to the target being declared but to its - dependants. In this case, <include>. will be + dependents. In this case, <include>. will be applied to all targets that directly depend on foo. @@ -417,7 +417,7 @@ exe app : app.cpp /library-example/foo//bar ; If you want all applications in some project to link to a certain - library, you can avoid having to specify it directly the sources of + library, you can avoid having to specify directly the sources of every target by using the <library> property. For example, if /boost/filesystem//fs should be linked to all applications in your project, you can add @@ -433,7 +433,7 @@ project
- Static and shared libaries + Static and shared libraries Libraries can be either static, which means they are @@ -621,8 +621,8 @@ lib lib2 exe app : app.cpp ../util/lib2//lib2 ; As with any target, the alternative selected depends on the properties - propagated from lib2's dependants. If we build the - release and debug versions of app will be linked + propagated from lib2's dependents. If we build the + release and debug versions of app it will be linked with lib2_release.a and lib2_debug.a , respectively. From ef4c1035109eacc6f29da7eceb1bc668aba52427 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Fri, 29 Apr 2016 08:17:11 -0400 Subject: [PATCH 025/158] Remove syntactical change previously made. --- doc/src/reference.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index 6c7e31540..752cb57fa 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -1063,7 +1063,7 @@ using msvc : &toolset_ops; ; The command that compiles assembler sources. If not specified, ml will be used. The command will be invoked after the setup script was executed and adjusted - by the PATH variable. + the PATH variable. @@ -1072,7 +1072,7 @@ using msvc : &toolset_ops; ; The command that compiles C and C++ sources. If not specified, cl will be used. The command will be invoked after the setup script was executed and adjusted - by the PATH variable. + the PATH variable. @@ -1089,7 +1089,7 @@ using msvc : &toolset_ops; ; The command that compiles Microsoft COM interface definition files. If not specified, midl will be used. The command will be invoked after the setup script was - executed and adjusted by the PATH variable. + executed and adjusted the PATH variable. @@ -1099,7 +1099,7 @@ using msvc : &toolset_ops; ; The command that links executables and dynamic libraries. If not specified, link will be used. The command will be invoked after the setup script was executed - and adjusted by the PATH variable. + and adjusted the PATH variable. @@ -1108,7 +1108,7 @@ using msvc : &toolset_ops; ; The command that compiles Microsoft message catalog files. If not specified, mc will be used. The command will be invoked after the setup script was - executed and adjusted by the PATH variable. + executed and adjusted the PATH variable. @@ -1117,7 +1117,7 @@ using msvc : &toolset_ops; ; The command that compiles resource files. If not specified, rc will be used. The command will be - invoked after the setup script was executed and adjusted by the + invoked after the setup script was executed and adjusted the PATH variable. @@ -1448,7 +1448,7 @@ using cw : &toolset_ops; ; The command that compiles C and C++ sources. If not specified, mwcc will be used. The command will be invoked after the setup script was - executed and adjusted by the PATH variable. + executed and adjusted the PATH variable. @@ -1459,7 +1459,7 @@ using cw : &toolset_ops; ; libraries. If not specified, mwld will be used. The command will be invoked after the setup script was - executed and adjusted by the PATH variable. + executed and adjusted the PATH variable. From f7e019c8ade42d53fe1e35bd779fbd4d9370e9e6 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Fri, 29 Apr 2016 12:55:51 -0400 Subject: [PATCH 026/158] Corrected terminology in the documentation. --- doc/src/overview.xml | 2 +- doc/src/reference.xml | 4 ++-- doc/src/tasks.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/src/overview.xml b/doc/src/overview.xml index 04c1c7754..37bae1c96 100644 --- a/doc/src/overview.xml +++ b/doc/src/overview.xml @@ -678,7 +678,7 @@ b2 toolset=gcc variant=debug optimization=space The build directory for the project root will be computed by concatenating the value of the option, the project name specified in Jamroot, and the build dir specified in Jamroot - (or bin.v2, if none is specified). + (or bin, if none is specified). The option is primarily useful when building from read-only diff --git a/doc/src/reference.xml b/doc/src/reference.xml index 752cb57fa..b312112d4 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -688,8 +688,8 @@ path-constant DATA : data/a.txt ; Allowed values: on, off. - The runtime-debugging feature specifies that, - if produced, object files, executables, and libraries should include + The runtime-debugging feature specifies + whether produced object files, executables, and libraries should include behaviour useful only for debugging, such as asserts. Typically, the value of this feature is implicitly set by the variant feature, but it can be explicitly diff --git a/doc/src/tasks.xml b/doc/src/tasks.xml index a4a357986..48f611a28 100644 --- a/doc/src/tasks.xml +++ b/doc/src/tasks.xml @@ -530,7 +530,7 @@ unit-test helpers_test The command used to run the executable will be: -valgrind bin.v2/$toolset/debug/helpers_test +valgrind bin/$toolset/debug/helpers_test From 6f8ed92ce93381348e5fecf0bdc8575d22c5c9c3 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Fri, 29 Apr 2016 15:57:49 -0400 Subject: [PATCH 027/158] Removed erroneous documentation fix. --- doc/src/reference.xml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index b312112d4..535e78d7b 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -561,15 +561,13 @@ path-constant DATA : data/a.txt ; cflags cxxflags - compileflags linkflags The value of those features is passed without modification to the - corresponding tools. For cflags that is C compiler, - for cxxflags that is the C++ compiler, - for compileflags that is both the C and C++ compilers, + corresponding tools. For cflags that is both the C and + C++ compilers, for cxxflags that is the C++ compiler, and for linkflags that is the linker. The features are handy when you are trying to do something special that cannot be achieved by a higher-level feature in Boost.Build. From d0f83a8cb538ed42d8ea23c792221a98c9ae2de5 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Sat, 30 Apr 2016 12:59:12 -0400 Subject: [PATCH 028/158] Remove grammatical fix. --- doc/src/tutorial.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/tutorial.xml b/doc/src/tutorial.xml index 727c912cc..e36ac1402 100644 --- a/doc/src/tutorial.xml +++ b/doc/src/tutorial.xml @@ -280,8 +280,8 @@ top/ in their requirements, too. Of course, any project can add include paths to those specified by its parents. Many - features will be overridden in, - rather than added-to, subprojects. See for more information From 24f97b090f8f5af1e6188f7de8b821dc3a7a894a Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Mon, 16 May 2016 07:56:10 -0600 Subject: [PATCH 029/158] Documentation fix: a directory is a valid target-id which refers to the project in that directory. --- doc/src/reference.xml | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index a66eb75a6..0275f9fe1 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -2661,7 +2661,7 @@ exe hello : hello.cpp : <os>NT,<toolset>gcc:<link>static ; target. The syntax is: -target-id -> (project-id | target-name | file-name ) +target-id -> (target-name | file-name | project-id | directory-name) | (project-id | directory-name) "//" target-name project-id -> path target-name -> path @@ -2673,12 +2673,6 @@ directory-name -> path This grammar allows some elements to be recognized as either - - - project id (at this point, all project ids start with slash). - - - name of target declared in current Jamfile (note that target @@ -2692,17 +2686,30 @@ directory-name -> path project's sources location. + + + + project id (at this point, all project ids start with slash). + + + + + + the directory of another project, denoted by absolute name + or name relative to the current project's location. + + - To determine the real meaning a check is made if project-id - by the specified name exists, and then if main target of that - name exists. For example, valid target ids might be: + To determine the real meaning the possible interpretations + are checked in this order. For example, valid target ids might be: a -- target in current project lib/b.cpp -- regular file /boost/thread -- project "/boost/thread" /home/ghost/build/lr_library//parser -- target in specific project +../boost_1_61_0 -- project in specific directory From 4d304fb9044456f753f8a07932d9b9512c6c2ada Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Mon, 23 May 2016 11:52:10 +0100 Subject: [PATCH 030/158] Fix typos in comments --- example/user-config.jam | 2 +- src/tools/clang.jam | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/example/user-config.jam b/example/user-config.jam index fbbf13fd0..df86176cd 100644 --- a/example/user-config.jam +++ b/example/user-config.jam @@ -22,7 +22,7 @@ # This file uses Jam language syntax to describe available tools. Mostly, # there are 'using' lines, that contain the name of the used tools, and -# parameters to pass to those tools -- where paremeters are separated by +# parameters to pass to those tools -- where parameters are separated by # semicolons. Important syntax notes: # # - Both ':' and ';' must be separated from other tokens by whitespace diff --git a/src/tools/clang.jam b/src/tools/clang.jam index e0ac9a553..2d89f3807 100644 --- a/src/tools/clang.jam +++ b/src/tools/clang.jam @@ -3,7 +3,7 @@ # or copy at http://www.boost.org/LICENSE_1_0.txt) # This is a generic 'clang' toolset. Depending on the current system, it -# forwards either to 'clang-unix' or 'clang-darwin' modules. +# forwards either to 'clang-linux' or 'clang-darwin' modules. import feature ; import os ; From 2540d311e7cd9a18ffbd46a15412af6173db304f Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 13 Jun 2016 23:29:33 -0500 Subject: [PATCH 031/158] Don't accidentally remove python source tests. --- src/tools/python.jam | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 3ecd89764..6404d8ad3 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -1222,8 +1222,10 @@ rule capture-output ( target : sources * : properties * ) PYTHONPATH += [ feature.get-values pythonpath : $(properties) ] ; # After test is run, we remove the Python module, but not the Python script. + local targets-to-remove = $(sources[2-]) ; + targets-to-remove ?= none ; testing.capture-output $(target) : $(sources[1]) : $(properties) : - $(sources[2-]) ; + $(targets-to-remove) ; # PYTHONPATH is different; it will be interpreted by whichever Python is # invoked and so must follow path rules for the target os. The only OSes From 885574b61afffd11b47544144aa7f081db360a72 Mon Sep 17 00:00:00 2001 From: Victor Robertson Date: Mon, 20 Jun 2016 17:46:08 -0700 Subject: [PATCH 032/158] Add Apple TV support --- doc/src/reference.xml | 2 +- src/tools/builtin.jam | 2 +- src/tools/builtin.py | 2 +- src/tools/darwin.jam | 41 +++++++++++++++++++++++++++++++++++++++-- tutorial.html | 2 +- 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index 98b8e857b..7e4c4ec86 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -711,7 +711,7 @@ path-constant DATA : data/a.txt ; The complete list of possible values for this feature is: - aix, bsd, cygwin, darwin, freebsd, hpux, iphone, linux, netbsd, + aix, appletv, bsd, cygwin, darwin, freebsd, hpux, iphone, linux, netbsd, openbsd, osf, qnx, qnxnto, sgi, solaris, unix, unixware, windows. diff --git a/src/tools/builtin.jam b/src/tools/builtin.jam index f39fb7018..1236120fe 100644 --- a/src/tools/builtin.jam +++ b/src/tools/builtin.jam @@ -40,7 +40,7 @@ import convert ; import generate ; -.os-names = aix android bsd cygwin darwin freebsd haiku hpux iphone linux netbsd +.os-names = aix android appletv bsd cygwin darwin freebsd haiku hpux iphone linux netbsd openbsd osf qnx qnxnto sgi solaris unix unixware windows vms elf # Not actually an OS -- used for targeting bare metal where object # format is ELF. This catches both -elf and -eabi gcc targets and well diff --git a/src/tools/builtin.py b/src/tools/builtin.py index a149a3332..f49d41e40 100644 --- a/src/tools/builtin.py +++ b/src/tools/builtin.py @@ -82,7 +82,7 @@ def variant (name, parents_or_properties, explicit_properties = []): feature.compose ("" + name, explicit_properties.all()) __os_names = """ - amiga aix bsd cygwin darwin dos emx freebsd hpux iphone linux netbsd + amiga aix appletv bsd cygwin darwin dos emx freebsd hpux iphone linux netbsd openbsd osf qnx qnxnto sgi solaris sun sunos svr4 sysv ultrix unix unixware vms windows """.split() diff --git a/src/tools/darwin.jam b/src/tools/darwin.jam index ceb2c6d3c..73c6a0a80 100644 --- a/src/tools/darwin.jam +++ b/src/tools/darwin.jam @@ -223,6 +223,10 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? ) { switch $(version[1]) { + case appletv* : + { + return $(version[1])-$(version[2-]:J=.) ; + } case iphone* : { return $(version[1])-$(version[2-]:J=.) ; @@ -265,6 +269,31 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? ) # Then device variation options. switch $(version[1]) { + case appletvsim* : + { + local N = $(version[2]) ; + if ! $(version[3]) { N += 00 ; } + else if [ regex.match (..) : $(version[3]) ] { N += $(version[3]) ; } + else { N += 0$(version[3]) ; } + if ! $(version[4]) { N += 00 ; } + else if [ regex.match (..) : $(version[4]) ] { N += $(version[4]) ; } + else { N += 0$(version[4]) ; } + N = $(N:J=) ; + flags darwin.compile OPTIONS $(version-feature) + : -D__IPHONE_OS_VERSION_MIN_REQUIRED=$(N) ; + flags darwin.link OPTIONS $(version-feature) + : -D__IPHONE_OS_VERSION_MIN_REQUIRED=$(N) ; + } + + case appletv* : + { + flags darwin.compile OPTIONS $(version-feature) + : -mtvos-version-min=$(version[2-]:J=.) ; + flags darwin.link OPTIONS $(version-feature) + : -mtvos-version-min=$(version[2-]:J=.) ; + } + + case iphonesim* : { local N = $(version[2]) ; @@ -280,7 +309,7 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? ) flags darwin.link OPTIONS $(version-feature) : -D__IPHONE_OS_VERSION_MIN_REQUIRED=$(N) ; } - + case iphone* : { flags darwin.compile OPTIONS $(version-feature) @@ -340,7 +369,7 @@ local rule init-available-sdk-versions ( condition * : root ? ) { root ?= /Developer ; local sdks-root = $(root)/SDKs ; - local sdks = [ GLOB $(sdks-root) : MacOSX*.sdk iPhoneOS*.sdk iPhoneSimulator*.sdk ] ; + local sdks = [ GLOB $(sdks-root) : MacOSX*.sdk AppleTVOS*.sdk AppleTVSimulator*.sdk iPhoneOS*.sdk iPhoneSimulator*.sdk ] ; local result ; for local sdk in $(sdks) { @@ -355,6 +384,14 @@ local rule init-available-sdk-versions ( condition * : root ? ) { sdk-version = mac $(sdk-version) ; } + case appletvos : + { + sdk-version = appletv $(sdk-version) ; + } + case appletvsimulator : + { + sdk-version = appletvsim $(sdk-version) ; + } case iphoneos : { sdk-version = iphone $(sdk-version) ; diff --git a/tutorial.html b/tutorial.html index c500d2085..f50586e4f 100644 --- a/tutorial.html +++ b/tutorial.html @@ -1433,7 +1433,7 @@ exe hello : hello.cpp : <library>/boost//thread ; <target-os> - aix, bsd, cygwin, darwin, freebsd, hpux, iphone, linux, + aix, appletv, bsd, cygwin, darwin, freebsd, hpux, iphone, linux, netbsd, openbsd, osf, qnx, qnxnto, sgi, solaris, unix, unixware, windows From 5f09d1771683edaeadaef90cd6869035233fa06f Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 12 Jul 2016 21:56:17 +0300 Subject: [PATCH 033/158] Correct whitespace --- src/tools/darwin.jam | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tools/darwin.jam b/src/tools/darwin.jam index 73c6a0a80..a610603f0 100644 --- a/src/tools/darwin.jam +++ b/src/tools/darwin.jam @@ -292,7 +292,6 @@ local rule init-sdk ( condition * : root ? : version + : version-feature ? ) flags darwin.link OPTIONS $(version-feature) : -mtvos-version-min=$(version[2-]:J=.) ; } - case iphonesim* : { From ae5e63a1315493dfb2fc60c4d537674fa637f898 Mon Sep 17 00:00:00 2001 From: Marcel Raad Date: Sun, 3 Jul 2016 22:53:36 +0200 Subject: [PATCH 034/158] Add support for upcoming Visual Studio "15" This allows building with Visual Studio "15", expected to be released in 2017. Tested with Visual Studio "15" Preview 3. The compiler itself is the same as with Visual Studio 2015 Update 3, but if only Visual Studio "15" is installed, the compiler could not be found. --- src/engine/build.bat | 27 ++++++++++++++++++++++++++- src/engine/build.jam | 7 +++++++ src/tools/msvc.jam | 10 ++++++++-- src/tools/msvc.py | 8 ++++++-- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/src/engine/build.bat b/src/engine/build.bat index e0e742da2..2086f37a7 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -28,7 +28,7 @@ ECHO ### You can specify the toolset as the argument, i.e.: ECHO ### .\build.bat msvc ECHO ### ECHO ### Toolsets supported by this script are: borland, como, gcc, gcc-nocygwin, -ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10, vc11, vc12, vc14 +ECHO ### intel-win32, metrowerks, mingw, msvc, vc7, vc8, vc9, vc10, vc11, vc12, vc14, vc15 ECHO ### call :Set_Error endlocal @@ -100,6 +100,16 @@ call :Clear_Error call :Test_Empty %ProgramFiles% if not errorlevel 1 set ProgramFiles=C:\Program Files +call :Clear_Error +if NOT "_%VS150COMNTOOLS%_" == "__" ( + set "BOOST_JAM_TOOLSET=vc15" + set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" + goto :eof) +call :Clear_Error +if EXIST "%ProgramFiles%\Microsoft Visual Studio 15.0\VC\VCVARSALL.BAT" ( + set "BOOST_JAM_TOOLSET=vc15" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio 15.0\VC\" + goto :eof) call :Clear_Error if NOT "_%VS140COMNTOOLS%_" == "__" ( set "BOOST_JAM_TOOLSET=vc14" @@ -446,6 +456,21 @@ set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0" set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0" set "_known_=1" :Skip_VC14 +if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc15_" goto Skip_VC15 +if NOT "_%VS150COMNTOOLS%_" == "__" ( + set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" + ) +if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%VCVARSALL.BAT" %BOOST_JAM_ARGS% +if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" ( + if "_%VCINSTALLDIR%_" == "__" ( + set "PATH=%BOOST_JAM_TOOLSET_ROOT%bin;%PATH%" + ) ) +set "BOOST_JAM_CC=cl /nologo /RTC1 /Zi /MTd /Fobootstrap/ /Fdbootstrap/ -DNT -DYYDEBUG -wd4996 kernel32.lib advapi32.lib user32.lib" +set "BOOST_JAM_OPT_JAM=/Febootstrap\jam0" +set "BOOST_JAM_OPT_MKJAMBASE=/Febootstrap\mkjambase0" +set "BOOST_JAM_OPT_YYACC=/Febootstrap\yyacc0" +set "_known_=1" +:Skip_VC15 if NOT "_%BOOST_JAM_TOOLSET%_" == "_borland_" goto Skip_BORLAND if "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" ( call :Test_Path bcc32.exe ) diff --git a/src/engine/build.jam b/src/engine/build.jam index ad2ea3580..e16b24085 100644 --- a/src/engine/build.jam +++ b/src/engine/build.jam @@ -394,12 +394,19 @@ toolset vc12 cl : /Fe /Fe /Fd /Fo : -D [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ] -I$(--python-include) -I$(--extra-include) : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ; +## Microsoft Visual C++ 2015 toolset vc14 cl : /Fe /Fe /Fd /Fo : -D : /nologo [ opt --release : /GL /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ] [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ] -I$(--python-include) -I$(--extra-include) : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ; +toolset vc15 cl : /Fe /Fe /Fd /Fo : -D + : /nologo + [ opt --release : /GL /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ] + [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ] + -I$(--python-include) -I$(--extra-include) + : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ; ## VMS/OpenVMS DEC C toolset vmsdecc cc : /OBJECT= : "/DEFINES=(" "," ")" : /STANDARD=VAXC /PREFIX_LIBRARY_ENTRIES=(ALL_ENTRIES) diff --git a/src/tools/msvc.jam b/src/tools/msvc.jam index 78e64e684..3f8f49e68 100644 --- a/src/tools/msvc.jam +++ b/src/tools/msvc.jam @@ -907,7 +907,11 @@ local rule configure-really ( version ? : options * ) # version from the path. # FIXME: We currently detect both Microsoft Visual Studio 9.0 and # 9.0express as 9.0 here. - if [ MATCH "(Microsoft Visual Studio 14)" : $(command) ] + if [ MATCH "(Microsoft Visual Studio 15)" : $(command) ] + { + version = 15.0 ; + } + else if [ MATCH "(Microsoft Visual Studio 14)" : $(command) ] { version = 14.0 ; } @@ -1591,7 +1595,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] 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 +.known-versions = 15.0 14.0 12.0 11.0 10.0 10.0express 9.0 9.0express 8.0 8.0express 7.1 7.1toolkit 7.0 6.0 ; # Version aliases. @@ -1604,6 +1608,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] .version-alias-11 = 11.0 ; .version-alias-12 = 12.0 ; .version-alias-14 = 14.0 ; +.version-alias-15 = 15.0 ; # Names of registry keys containing the Visual C++ installation path (relative # to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"). @@ -1619,6 +1624,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] .version-11.0-reg = "VisualStudio\\11.0\\Setup\\VC" ; .version-12.0-reg = "VisualStudio\\12.0\\Setup\\VC" ; .version-14.0-reg = "VisualStudio\\14.0\\Setup\\VC" ; +.version-15.0-reg = "VisualStudio\\15.0\\Setup\\VC" ; # Visual C++ Toolkit 2003 does not store its installation path in the registry. # The environment variable 'VCToolkitInstallDir' and the default installation diff --git a/src/tools/msvc.py b/src/tools/msvc.py index 8cdc273e0..1115af334 100644 --- a/src/tools/msvc.py +++ b/src/tools/msvc.py @@ -676,7 +676,9 @@ def configure_really(version=None, options=[]): # version from the path. # FIXME: We currently detect both Microsoft Visual Studio 9.0 and # 9.0express as 9.0 here. - if re.search("Microsoft Visual Studio 14", command): + if re.search("Microsoft Visual Studio 15", command): + version = '15.0' + elif re.search("Microsoft Visual Studio 14", command): version = '14.0' elif re.search("Microsoft Visual Studio 12", command): version = '12.0' @@ -1191,7 +1193,7 @@ __cpu_type_itanium2 = ['itanium2', 'mckinley'] # 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', '7.1toolkit', '7.0', '6.0'] +_known_versions = ['15.0', '14.0', '12.0', '11.0', '10.0', '10.0express', '9.0', '9.0express', '8.0', '8.0express', '7.1', '7.1toolkit', '7.0', '6.0'] # Version aliases. __version_alias_6 = '6.0' @@ -1203,6 +1205,7 @@ __version_alias_10 = '10.0' __version_alias_11 = '11.0' __version_alias_12 = '12.0' __version_alias_14 = '14.0' +__version_alias_15 = '15.0' # Names of registry keys containing the Visual C++ installation path (relative # to "HKEY_LOCAL_MACHINE\SOFTWARE\\Microsoft"). @@ -1218,6 +1221,7 @@ __version_10_0express_reg = "VCExpress\\10.0\\Setup\\VC" __version_11_0_reg = "VisualStudio\\11.0\\Setup\\VC" __version_12_0_reg = "VisualStudio\\12.0\\Setup\\VC" __version_14_0_reg = "VisualStudio\\14.0\\Setup\\VC" +__version_15_0_reg = "VisualStudio\\15.0\\Setup\\VC" # Visual C++ Toolkit 2003 does not store its installation path in the registry. # The environment variable 'VCToolkitInstallDir' and the default installation From 3ea65143c058c0ed700c3c8ee090d0b7955bbfd1 Mon Sep 17 00:00:00 2001 From: Ashish Sadanandan Date: Fri, 15 Jul 2016 00:01:02 -0600 Subject: [PATCH 035/158] Strip trailing whitespace, no other changes --- src/tools/mpi.jam | 144 +++++++++++++++++++++++----------------------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/src/tools/mpi.jam b/src/tools/mpi.jam index a161101bc..15241c041 100644 --- a/src/tools/mpi.jam +++ b/src/tools/mpi.jam @@ -3,33 +3,33 @@ # (C) Copyright 2005, 2006 Trustees of Indiana University # (C) Copyright 2005 Douglas Gregor # -# Distributed under the Boost Software License, Version 1.0. (See accompanying +# 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.) # # Authors: Douglas Gregor # Andrew Lumsdaine # # ==== MPI Configuration ==== -# -# For many users, MPI support can be enabled simply by adding the following +# +# For many users, MPI support can be enabled simply by adding the following # line to your user-config.jam file: # # using mpi ; # -# This should auto-detect MPI settings based on the MPI wrapper compiler in +# This should auto-detect MPI settings based on the MPI wrapper compiler in # your path, e.g., "mpic++". If the wrapper compiler is not in your path, or # has a different name, you can pass the name of the wrapper compiler as the # first argument to the mpi module: # # using mpi : /opt/mpich2-1.0.4/bin/mpiCC ; # -# If your MPI implementation does not have a wrapper compiler, or the MPI +# If your MPI implementation does not have a wrapper compiler, or the MPI # auto-detection code does not work with your MPI's wrapper compiler, -# you can pass MPI-related options explicitly via the second parameter to the +# you can pass MPI-related options explicitly via the second parameter to the # mpi module: # # using mpi : : lammpio lammpi++ -# mpi lam +# mpi lam # dl ; # # To see the results of MPI auto-detection, pass "--debug-configuration" on @@ -41,17 +41,17 @@ # to this to run tests and tell the program to expect the number of # processors to follow (default: "-np"). With the default parameters, # for instance, the test harness will execute, e.g., -# +# # mpirun -np 4 all_gather_test # # ==== Linking Against the MPI Libraries === # -# To link against the MPI libraries, import the "mpi" module and add the +# To link against the MPI libraries, import the "mpi" module and add the # following requirement to your target: -# -# /mpi//mpi # -# Since MPI support is not always available, you should check +# /mpi//mpi +# +# Since MPI support is not always available, you should check # "mpi.configured" before trying to link against the MPI libraries. import "class" : new ; @@ -82,7 +82,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] # value rest-of-cmdline # # This is a subroutine of cmdline_to_features -rule add_feature ( prefix name cmdline ) +rule add_feature ( prefix name cmdline ) { local match = [ MATCH "^$(prefix)([^\" ]+|\"[^\"]+\") *(.*)$" : $(cmdline) ] ; @@ -142,7 +142,7 @@ rule cmdline_to_features ( cmdline : unknown-features ? ) executable = $(match[1]) ; cmdline = $(match[2]) ; - # List the prefix/feature pairs that we will be able to transform. + # List the prefix/feature pairs that we will be able to transform. # Every kind of parameter not mentioned here will be placed in both # cxxflags and linkflags, because we don't know where they should go. local feature_kinds-D = "define" ; @@ -171,13 +171,13 @@ rule cmdline_to_features ( cmdline : unknown-features ? ) # uses -lpthread as opposed to -pthread. We do want to # set multi, instead of -lpthread. result += "multi" ; - MPI_EXTRA_REQUIREMENTS += "multi" ; + MPI_EXTRA_REQUIREMENTS += "multi" ; } else - { - result += $(add[1]) ; + { + result += $(add[1]) ; } - + cmdline = $(add[2]) ; matched = yes ; } @@ -204,7 +204,7 @@ rule cmdline_to_features ( cmdline : unknown-features ? ) # conflicts when BBv2 determines which "common" properties to # apply to a target. In our case, the single property # gets propagated from the common properties to Boost.MPI - # targets, even though multi is in the usage + # targets, even though multi is in the usage # requirements of /mpi//mpi. MPI_EXTRA_REQUIREMENTS += "multi" ; } @@ -235,16 +235,16 @@ local rule safe-shell-command ( cmdline ) return [ MATCH ".*(SSCOK).*" : $(result) ] ; } -# Initialize the MPI module. +# Initialize the MPI module. rule init ( mpicxx ? : options * : mpirun-with-options * ) { if ! $(options) && $(.debug-configuration) { ECHO "===============MPI Auto-configuration===============" ; } - + if ! $(mpicxx) && [ os.on-windows ] - { + { # Try to auto-configure to the Microsoft Compute Cluster Pack local cluster_pack_path_native = "C:\\Program Files\\Microsoft Compute Cluster Pack" ; local cluster_pack_path = [ path.make $(cluster_pack_path_native) ] ; @@ -254,16 +254,16 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) { ECHO "Found Microsoft Compute Cluster Pack: $(cluster_pack_path_native)" ; } - + # Pick up either the 32-bit or 64-bit library, depending on which address # model the user has selected. Default to 32-bit. - options = $(cluster_pack_path)/Include + options = $(cluster_pack_path)/Include 64:$(cluster_pack_path)/Lib/amd64 $(cluster_pack_path)/Lib/i386 msmpi msvc:_SECURE_SCL=0 ; - + # Setup the "mpirun" equivalent (mpiexec) .mpirun = "\"$(cluster_pack_path_native)\\Bin\\mpiexec.exe"\" ; .mpirun_flags = -n ; @@ -272,26 +272,26 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) { ECHO "Did not find Microsoft Compute Cluster Pack in $(cluster_pack_path_native)." ; } - } - + } + if ! $(options) - { + { # Try to auto-detect options based on the wrapper compiler local command = [ common.get-invocation-command mpi : mpic++ : $(mpicxx) ] ; - if ! $(mpicxx) && ! $(command) + if ! $(mpicxx) && ! $(command) { - # Try "mpiCC", which is used by MPICH + # Try "mpiCC", which is used by MPICH command = [ common.get-invocation-command mpi : mpiCC ] ; } - if ! $(mpicxx) && ! $(command) + if ! $(mpicxx) && ! $(command) { # Try "mpicxx", which is used by OpenMPI and MPICH2 command = [ common.get-invocation-command mpi : mpicxx ] ; } - if ! $(mpicxx) && ! $(command) + if ! $(mpicxx) && ! $(command) { # Try "CC", which is used by Cray command = [ common.get-invocation-command mpi : CC ] ; @@ -302,10 +302,10 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) local link_flags ; if ! $(command) - { + { # Do nothing: we'll complain later } - # OpenMPI and newer versions of LAM-MPI have -showme:compile and + # OpenMPI and newer versions of LAM-MPI have -showme:compile and # -showme:link. else if [ safe-shell-command "$(command) -showme:compile" ] && [ safe-shell-command "$(command) -showme:link" ] @@ -317,8 +317,8 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) compile_flags = [ SHELL "$(command) -showme:compile" ] ; link_flags = [ SHELL "$(command) -showme:link" ] ; - - # Prepend COMPILER as the executable name, to match the format of + + # Prepend COMPILER as the executable name, to match the format of # other compilation commands. compile_flags = "COMPILER $(compile_flags) -DOMPI_SKIP_MPICXX " ; link_flags = "COMPILER $(link_flags)" ; @@ -379,7 +379,7 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) ECHO "Found IBM MPI wrapper compiler: $(command)" ; } - # + # compile_flags = [ SHELL "$(command) -c -v 2>/dev/null" ] ; compile_flags = [ MATCH "(.*)exec: export.*" : $(compile_flags) ] ; local front = [ MATCH "(.*)-v" : $(compile_flags) ] ; @@ -402,7 +402,7 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) compile_flags = "$(compile_flags) $(f_flags)" ; } } - # Cray + # Cray else if [ safe-shell-command "$(command) -v" ] { compile_flags = [ safe-shell-command "$(command) -###" ] ; @@ -411,8 +411,8 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) # ECHO "Noel: link_flags: $(link_flags)" ; result = " " ; } - - # Prepend COMPILER as the executable name, to match the format of + + # Prepend COMPILER as the executable name, to match the format of if $(result) || $(compile_flags) && $(link_flags) { @@ -421,17 +421,17 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) result = [ strip-eol $(result) ] ; options = [ cmdline_to_features $(result) ] ; } - else - { + else + { compile_flags = [ strip-eol $(compile_flags) ] ; link_flags = [ strip-eol $(link_flags) ] ; # Separately process compilation and link features, then combine # them at the end. - local compile_features = [ cmdline_to_features $(compile_flags) - : "" ] ; - local link_features = [ cmdline_to_features $(link_flags) - : "" ] ; + local compile_features = [ cmdline_to_features $(compile_flags) + : "" ] ; + local link_features = [ cmdline_to_features $(link_flags) + : "" ] ; options = $(compile_features) $(link_features) ; } @@ -444,44 +444,44 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) } else { - local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" + local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" : $(compile_flags) ] ; ECHO "MPI compilation flags: $(match[2])" ; - local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" + local match = [ MATCH "^([^\" ]+|\"[^\"]+\") *(.*)$" : $(link_flags) ] ; ECHO "MPI link flags: $(match[2])" ; } } - } - else + } + else { if $(command) { ECHO "MPI auto-detection failed: unknown wrapper compiler $(command)" ; ECHO "Please report this error to the Boost mailing list: http://www.boost.org" ; - } + } else if $(mpicxx) { ECHO "MPI auto-detection failed: unable to find wrapper compiler $(mpicxx)" ; - } + } else { ECHO "MPI auto-detection failed: unable to find wrapper compiler `mpic++' or `mpiCC'" ; } ECHO "You will need to manually configure MPI support." ; } - + } # Find mpirun (or its equivalent) and its flags if ! $(.mpirun) { - .mpirun = + .mpirun = [ common.get-invocation-command mpi : mpirun : $(mpirun-with-options[1]) ] ; .mpirun_flags = $(mpirun-with-options[2-]) ; .mpirun_flags ?= -np ; } - + if $(.debug-configuration) { if $(options) @@ -494,15 +494,15 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) { echo "MPI launcher: $(.mpirun) $(.mpirun_flags)" ; } - + ECHO "====================================================" ; } - if $(options) + if $(options) { .configured = true ; - # Set up the "mpi" alias + # Set up the "mpi" alias alias mpi : : : : $(options) ; } } @@ -537,21 +537,21 @@ class mpi-test-generator : generator } rule run ( project name ? : property-set : sources * : multiple ? ) - { + { # Generate an executable from the sources. This is the executable we will run. - local executable = + local executable = [ generators.construct $(project) $(name) : EXE : $(property-set) : $(sources) ] ; - result = + result = [ construct-result $(executable[2-]) : $(project) $(name)-run : $(property-set) ] ; } } # Use mpi-test-generator to generate MPI tests from sources -generators.register +generators.register [ new mpi-test-generator mpi.capture-output : : RUN_MPI_OUTPUT ] ; -generators.register-standard testing.expect-success +generators.register-standard testing.expect-success : RUN_MPI_OUTPUT : RUN_MPI ; # The number of processes to spawn when executing an MPI test. @@ -574,25 +574,25 @@ rule capture-output ( target : sources * : properties * ) JAM_SEMAPHORE on $(target) = mpi-run-semaphore ; # We launch MPI processes using the "mpirun" equivalent specified by the user. - LAUNCHER on $(target) = + LAUNCHER on $(target) = [ on $(target) return $(.mpirun) $(.mpirun_flags) $(num_processes) ] ; } -# Creates a set of test cases to be run through the MPI launcher. The name, sources, -# and requirements are the same as for any other test generator. However, schedule is -# a list of numbers, which indicates how many processes each test run will use. For +# Creates a set of test cases to be run through the MPI launcher. The name, sources, +# and requirements are the same as for any other test generator. However, schedule is +# a list of numbers, which indicates how many processes each test run will use. For # example, passing 1 2 7 will run the test with 1 process, then 2 processes, then 7 -# 7 processes. The name provided is just the base name: the actual tests will be -# the name followed by a hypen, then the number of processes. +# 7 processes. The name provided is just the base name: the actual tests will be +# the name followed by a hypen, then the number of processes. rule mpi-test ( name : sources * : requirements * : schedule * ) -{ +{ sources ?= $(name).cpp ; schedule ?= 1 2 3 4 7 8 13 17 ; local result ; for processes in $(schedule) - { - result += [ testing.make-test + { + result += [ testing.make-test run-mpi : $(sources) /boost/mpi//boost_mpi : $(requirements) msvc:static $(processes) : $(name)-$(processes) ] ; } From c8665267d3787c348e8317475ded63776c9a329d Mon Sep 17 00:00:00 2001 From: Ashish Sadanandan Date: Fri, 15 Jul 2016 00:04:28 -0600 Subject: [PATCH 036/158] Fix for auto configuring MPI on Windows. Microsoft has a new MPI implementation available - https://msdn.microsoft.com/en-us/library/windows/desktop/bb524831%28v=vs.85%29.aspx There are now two installers, one for the MPI executor and another for the MPI SDK (which contains the headers and static libraries), and these install to different locations by default. The jam file has been changed so that MS-MPI is first checked, if found use that as the MPI executor/SDK. If not found, the MS Compute Cluster Pack is checked next. --- src/tools/mpi.jam | 40 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/src/tools/mpi.jam b/src/tools/mpi.jam index 15241c041..1ccc54133 100644 --- a/src/tools/mpi.jam +++ b/src/tools/mpi.jam @@ -245,16 +245,48 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) if ! $(mpicxx) && [ os.on-windows ] { - # Try to auto-configure to the Microsoft Compute Cluster Pack + # Paths for Microsoft MPI + local ms_mpi_path_native = "C:\\Program Files\\Microsoft MPI" ; + local ms_mpi_sdk_path_native = "C:\\Program Files (x86)\\Microsoft SDKs\\MPI" ; + + # Path for Microsoft Compute Cluster Pack local cluster_pack_path_native = "C:\\Program Files\\Microsoft Compute Cluster Pack" ; - local cluster_pack_path = [ path.make $(cluster_pack_path_native) ] ; - if [ GLOB $(cluster_pack_path_native)\\Include : mpi.h ] + + # Try to auto-configure Microsoft MPI + if [ GLOB $(ms_mpi_path_native)\\Bin : mpiexec.exe ] && + [ GLOB $(ms_mpi_sdk_path_native)\\Include : mpi.h ] + { + if $(.debug-configuration) + { + ECHO "Found Microsoft MPI: $(ms_mpi_path_native)" ; + ECHO "Found Microsoft MPI SDK: $(ms_mpi_sdk_path_native)" ; + } + + local ms_mpi_sdk_path = [ path.make $(ms_mpi_sdk_path_native) ] ; + + # Pick up either the 32-bit or 64-bit library, depending on which address + # model the user has selected. Default to 32-bit. + options = $(ms_mpi_sdk_path)/Include + 64:$(ms_mpi_sdk_path)/Lib/x64 + $(ms_mpi_sdk_path)/Lib/x86 + msmpi + msvc:_SECURE_SCL=0 + ; + + # Setup the "mpirun" equivalent (mpiexec) + .mpirun = "\"$(ms_mpi_path_native)\\Bin\\mpiexec.exe"\" ; + .mpirun_flags = -n ; + } + # Try to auto-configure to the Microsoft Compute Cluster Pack + else if [ GLOB $(cluster_pack_path_native)\\Include : mpi.h ] { if $(.debug-configuration) { ECHO "Found Microsoft Compute Cluster Pack: $(cluster_pack_path_native)" ; } + local cluster_pack_path = [ path.make $(cluster_pack_path_native) ] ; + # Pick up either the 32-bit or 64-bit library, depending on which address # model the user has selected. Default to 32-bit. options = $(cluster_pack_path)/Include @@ -270,6 +302,8 @@ rule init ( mpicxx ? : options * : mpirun-with-options * ) } else if $(.debug-configuration) { + ECHO "Did not find Microsoft MPI in $(ms_mpi_path_native)" ; + ECHO " and/or Microsoft MPI SDK in $(ms_mpi_sdk_path_native)." ; ECHO "Did not find Microsoft Compute Cluster Pack in $(cluster_pack_path_native)." ; } } From 78ffbe094400d277627b2c19ceb182d637b8baca Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sat, 16 Jul 2016 15:53:30 -0500 Subject: [PATCH 037/158] Fix not having a default python interpreter version on targets. This change adds a toolset requirement that sets the python version feature of the first configured python for a given target OS (usually the host OS). This allows to correctly configure different python interpreters for different target OSes. --- src/tools/python.jam | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tools/python.jam b/src/tools/python.jam index 6404d8ad3..6ee32167f 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -900,6 +900,17 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : toolset.add-requirements $(target-requirements:J=,):$(interpreter-cmd) ; + # We also set a default requirement that assigns the first python configured + # for a particular target OS as the default. This makes it so that we can + # select a python interpreter with only knowledge of the target OS. And hence + # can configure different Pythons based on the target OS only. + local toolset-requirements = [ toolset.requirements ] ; + local default-python-requirement = $(target-os):$(version:E=default) ; + if ! [ $(toolset-requirements).contains-raw $(default-python-requirement) ] + { + toolset.add-requirements $(default-python-requirement) ; + } + # Register the right suffix for extensions. register-extension-suffix $(extension-suffix) : $(target-requirements) ; From caeb6a9695fb0675189c21f95afc5d4c0e6affa5 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sat, 23 Jul 2016 12:40:14 -0500 Subject: [PATCH 038/158] Fix check to avoid duplicate default python toolset requirement. --- src/tools/python.jam | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 6ee32167f..23aab658f 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -905,10 +905,12 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : # select a python interpreter with only knowledge of the target OS. And hence # can configure different Pythons based on the target OS only. local toolset-requirements = [ toolset.requirements ] ; - local default-python-requirement = $(target-os):$(version:E=default) ; - if ! [ $(toolset-requirements).contains-raw $(default-python-requirement) ] + local toolset-target-os-requirements + = [ property.evaluate-conditionals-in-context + [ $(toolset-requirements).raw ] : $(target-os) ] ; + if ! in $(toolset-target-os-requirements:G) { - toolset.add-requirements $(default-python-requirement) ; + toolset.add-requirements $(target-os):$(version:E=default) ; } # Register the right suffix for extensions. From 01a1bfa2530d453e1de3624d7a6fc0d6eb014524 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Wed, 3 Aug 2016 18:32:03 -0500 Subject: [PATCH 039/158] A basic implementation of a toolset for Emscripten. It can currently compile C/C++ to Javascript (as ASM.js). --- src/tools/emscripten.jam | 106 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/tools/emscripten.jam diff --git a/src/tools/emscripten.jam b/src/tools/emscripten.jam new file mode 100644 index 000000000..292e0f092 --- /dev/null +++ b/src/tools/emscripten.jam @@ -0,0 +1,106 @@ +# Copyright Rene Rivera 2016 +# 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 feature ; +import os ; +import toolset ; +import common ; +import gcc ; +import type ; + +feature.feature embind : off on : propagated ; +feature.feature closure : off on full : propagated ; +feature.feature link-optimization : off on full : propagated ; + +rule init ( version ? : command * : options * ) +{ + command = [ common.get-invocation-command emscripten + : emcc + : $(command) ] ; + + # Determine the version + local command-string = $(command:J=" ") ; + if $(command) + { + version ?= [ MATCH "([0-9.]+)" + : [ SHELL "$(command-string) --version" ] ] ; + } + + local condition = [ common.check-init-parameters emscripten + : version $(version) ] ; + + common.handle-options emscripten : $(condition) : $(command) : $(options) ; +} + +feature.extend toolset : emscripten ; + +toolset.inherit-generators emscripten emscripten + : gcc + : gcc.mingw.link gcc.mingw.link.dll gcc.compile.c.pch gcc.compile.c++.pch + ; +toolset.inherit-rules emscripten : gcc ; +toolset.inherit-flags emscripten : gcc + : + off speed space + off on + off on full + off all on + off on + off on + off on + ; + +type.set-generated-target-suffix EXE : emscripten : "js" ; +type.set-generated-target-suffix OBJ : emscripten : "bc" ; + +toolset.flags emscripten.compile OPTIONS ; +toolset.flags emscripten.compile OPTIONS ; +toolset.flags emscripten.compile.c++ OPTIONS ; + +toolset.flags emscripten.compile OPTIONS off : -O0 ; +toolset.flags emscripten.compile OPTIONS speed : -O3 ; +toolset.flags emscripten.compile OPTIONS space : -Oz ; +toolset.flags emscripten.link OPTIONS off : -O0 ; +toolset.flags emscripten.link OPTIONS speed : -O3 ; +toolset.flags emscripten.link OPTIONS space : -O3 ; + +toolset.flags emscripten.compile OPTIONS on : --profiling-funcs ; + +toolset.flags emscripten.compile OPTIONS off : -fno-inline ; +toolset.flags emscripten.compile OPTIONS on : -Wno-inline ; +toolset.flags emscripten.compile OPTIONS full : -Wno-inline ; + +toolset.flags emscripten.compile OPTIONS off : -w ; +toolset.flags emscripten.compile OPTIONS on : -Wall ; +toolset.flags emscripten.compile OPTIONS all : -Wall -pedantic ; +toolset.flags emscripten.compile OPTIONS on : -Werror ; + +toolset.flags emscripten OPTIONS off : -g0 ; +toolset.flags emscripten OPTIONS on : -g4 ; +toolset.flags emscripten OPTIONS off : -fno-rtti ; + +toolset.flags emscripten OPTIONS on : --bind ; +toolset.flags emscripten.link OPTIONS on : --closure 1 ; +toolset.flags emscripten.link OPTIONS full : --closure 2 ; +toolset.flags emscripten.link OPTIONS off : --llvm-lto 0 ; +toolset.flags emscripten.link OPTIONS on : --llvm-lto 1 ; +toolset.flags emscripten.link OPTIONS full : --llvm-lto 3 ; + +actions compile.c +{ + "$(CONFIG_COMMAND)" -x c $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +actions compile.c++ +{ + "$(CONFIG_COMMAND)" -x c++ $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" +} + +toolset.flags emscripten.link USER_OPTIONS ; + +actions link bind LIBRARIES +{ + "$(CONFIG_COMMAND)" $(USER_OPTIONS) -L"$(LINKPATH)" -o "$(<)" "$(>)" "$(LIBRARIES)" $(START-GROUP) $(FINDLIBS-ST-PFX) -l$(FINDLIBS-ST) $(FINDLIBS-SA-PFX) -l$(FINDLIBS-SA) $(END-GROUP) $(OPTIONS) +} From 833a0abbea3095dc865ecd4f00e7dc7fbeeb270e Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Thu, 4 Aug 2016 09:01:46 -0500 Subject: [PATCH 040/158] Support static libs for emscripten building. --- src/tools/emscripten.jam | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tools/emscripten.jam b/src/tools/emscripten.jam index 292e0f092..74e3c200a 100644 --- a/src/tools/emscripten.jam +++ b/src/tools/emscripten.jam @@ -54,6 +54,7 @@ toolset.inherit-flags emscripten : gcc type.set-generated-target-suffix EXE : emscripten : "js" ; type.set-generated-target-suffix OBJ : emscripten : "bc" ; +type.set-generated-target-suffix STATIC_LIB : emscripten : "bc" ; toolset.flags emscripten.compile OPTIONS ; toolset.flags emscripten.compile OPTIONS ; @@ -81,7 +82,7 @@ toolset.flags emscripten OPTIONS off : -g0 ; toolset.flags emscripten OPTIONS on : -g4 ; toolset.flags emscripten OPTIONS off : -fno-rtti ; -toolset.flags emscripten OPTIONS on : --bind ; +toolset.flags emscripten.link OPTIONS on : --bind ; toolset.flags emscripten.link OPTIONS on : --closure 1 ; toolset.flags emscripten.link OPTIONS full : --closure 2 ; toolset.flags emscripten.link OPTIONS off : --llvm-lto 0 ; @@ -98,6 +99,11 @@ actions compile.c++ "$(CONFIG_COMMAND)" -x c++ $(OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -c -o "$(<)" "$(>)" } +actions archive +{ + "$(CONFIG_COMMAND)" $(AROPTIONS) -o "$(<)" "$(>)" +} + toolset.flags emscripten.link USER_OPTIONS ; actions link bind LIBRARIES From cf2bc83bd860030ded0c0fe5bd8774f675ebeced Mon Sep 17 00:00:00 2001 From: Thomas Brown Date: Fri, 5 Aug 2016 09:18:28 -0400 Subject: [PATCH 041/158] doc: Added a minimal README.rst file. The README provides a link to the Boost.Build website and also the contributing guidelines. --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 README.rst diff --git a/README.rst b/README.rst new file mode 100644 index 000000000..b2f9434a3 --- /dev/null +++ b/README.rst @@ -0,0 +1,6 @@ +Boost.Build +=========== + +See the Boost.Build website at https://boost.org/build. + +See the `guidelines for contributing <./notes/hacking.txt>`__. From 3349b63f8e42a7d5cde93e37cedb2d0fdad2b212 Mon Sep 17 00:00:00 2001 From: Thomas Brown Date: Fri, 5 Aug 2016 11:40:40 -0400 Subject: [PATCH 042/158] doc: Renamed hacking to reStructuredText. This does not modify the contents, just the name. --- README.rst | 2 +- notes/{hacking.txt => hacking.rst} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename notes/{hacking.txt => hacking.rst} (100%) diff --git a/README.rst b/README.rst index b2f9434a3..9c1da2ed0 100644 --- a/README.rst +++ b/README.rst @@ -3,4 +3,4 @@ Boost.Build See the Boost.Build website at https://boost.org/build. -See the `guidelines for contributing <./notes/hacking.txt>`__. +See the `guidelines for contributing <./notes/hacking.rst>`__. diff --git a/notes/hacking.txt b/notes/hacking.rst similarity index 100% rename from notes/hacking.txt rename to notes/hacking.rst From b708169c141341656389f96e35ab226138445ef7 Mon Sep 17 00:00:00 2001 From: Thomas Brown Date: Fri, 5 Aug 2016 12:14:03 -0400 Subject: [PATCH 043/158] doc: Minimal conversion to hacking.rst reStructuredText. This makes the minimum amount of changes to be reStructuredText. --- notes/hacking.rst | 145 +++++++++++++++++++++++++++------------------- 1 file changed, 84 insertions(+), 61 deletions(-) diff --git a/notes/hacking.rst b/notes/hacking.rst index 3c059173b..77a071dfe 100644 --- a/notes/hacking.rst +++ b/notes/hacking.rst @@ -1,11 +1,11 @@ -Copyright 2003, 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) +:Copyright: + Copyright 2003, 2006 Vladimir Prus +:License: + 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) - - ---------------------------------- - Boost.Build contributor guidelines - ---------------------------------- +Boost.Build contributor guidelines +================================== Boost.Build is an open-source project. This means that we welcome and appreciate all contributions --- be it ideas, bug reports, or patches. This document @@ -17,41 +17,50 @@ follow. But note, that 10 mins that you spare writing a comment, for example, might lead to significally longer delay for everyone. Before contributing, make sure you are subscribed to our mailing list - - boost-build@lists.boost.org +at boost-build@lists.boost.org. Additional resources include - - The issue tracker - http://trac.lvk.cs.msu.su/boost.build/ +- The issue tracker - - mailing list: - boost-build@lists.boost.org - http://lists.boost.org/boost-build/ + http://trac.lvk.cs.msu.su/boost.build/ +- mailing list + + boost-build@lists.boost.org + + http://lists.boost.org/boost-build/ BUGS and PATCHES +---------------- Both bugs and patches can be send to our mailing list. When reporting a bug, please try to provide the following information. - - What you did. A minimal reproducible testcase is very much appreciated. - Shell script with some annotations is much better than verbose description - of the problem. A regression test is the best (see test/test_system.html). - - What you got. - - What you expected. - - What version of Boost.Build and Boost.Jam did you use. If possible, - please try to test with the CVS HEAD state. +- What you did. + + - A minimal reproducible testcase is very much appreciated. + + - Shell script with some annotations is much better than verbose description + of the problem. + + - A regression test is the best (see test/test_system.html). + +- What you got. + +- What you expected. + +- What version of Boost.Build and Boost.Jam did you use. If possible, + please try to test with the CVS HEAD state. When submitting a patch, please: - - make a single patch for a single logical change - - follow the policies and coding conventions below, - - send patches in unified diff format, - (using either "cvs diff -u" or "diff -u") - - provide a log message together with the patch - - put the patch and the log message as attachment to your email. +- make a single patch for a single logical change +- follow the policies and coding conventions below, +- send patches in unified diff format, (using either "cvs diff -u" or "diff -u") +- provide a log message together with the patch +- put the patch and the log message as attachment to your email. The purpose of log message serves to communicate what was changed, and *why*. Without a good log message, you might spend a lot of time later, wondering where @@ -60,6 +69,8 @@ a strange piece of code came from and why it was necessary. The good log message mentions each changed file and each rule/method, saying what happend to it, and why. Consider, the following log message +:: + Better direct request handling. * new/build-request.jam @@ -79,60 +90,72 @@ The change to the first file is clearly undercommented. It's OK to use terse log messages for uninteresting changes, like ones induced by interface changes elsewhere. - POLICIES. +--------- 1. Testing. -All serious changes must be tested. New rules must be tested by the module where -they are declared. Test system (test/test_system.html) should be used to verify -user-observable behaviour. + All serious changes must be tested. New rules must be tested by the module where + they are declared. Test system (test/test_system.html) should be used to verify + user-observable behaviour. 2. Documentation. -It turns out that it's hard to have too much comments, but it's easy to have too -little. Please prepend each rule with a comment saying what the rule does and -what arguments mean. Stop for a minute and consider if the comment makes sense -for anybody else, and completely describes what the rules does. Generic phrases -like "adjusts properties" are really not enough. + It turns out that it's hard to have too much comments, but it's easy to have too + little. Please prepend each rule with a comment saying what the rule does and + what arguments mean. Stop for a minute and consider if the comment makes sense + for anybody else, and completely describes what the rules does. Generic phrases + like "adjusts properties" are really not enough. When applicable, make changes to the user documentation as well. - CODING CONVENTIONS. +------------------- - 1. All names of rules and variables are lowercase with "-" to separate - words. +1. All names of rules and variables are lowercase with "-" to separate + words. - rule call-me-ishmael ( ) ... + :: - 2. Names with dots in them are "intended globals". Ordinary globals use a - dot prefix: + rule call-me-ishmael ( ) ... - .foobar - $(.foobar) +2. Names with dots in them are "intended globals". Ordinary globals use a + dot prefix: - 3. Pseudofunctions or associations are .: + :: - $(argument).name = hello ; - $($(argument).name) + .foobar + $(.foobar) - 4. Class attribute names are prefixed with "self.": +3. Pseudofunctions or associations are .: - self.x - $(self.x) + :: - 5. Builtin rules are called via their ALL_UPPERCASE_NAMES: + $(argument).name = hello ; + $($(argument).name) - DEPENDS $(target) : $(sources) ; +4. Class attribute names are prefixed with "self.": - 6. Opening and closing braces go on separate lines: + :: - if $(a) - { - # - } - else - { - # - } + self.x + $(self.x) + +5. Builtin rules are called via their ALL_UPPERCASE_NAMES: + + :: + + DEPENDS $(target) : $(sources) ; + +6. Opening and closing braces go on separate lines: + + :: + + if $(a) + { + # + } + else + { + # + } From 61863389380d4fbc20af5f9cacb8e0d3473ef505 Mon Sep 17 00:00:00 2001 From: Thomas Brown Date: Sat, 30 Aug 2014 15:12:25 -0700 Subject: [PATCH 044/158] doc: Moved hacking document to CONTRIBUTING. This matches the policy of many open-source projects. On GitHub and similar hosting services, this will provide the user some guidance when creating issues or pull requests. --- notes/hacking.rst => CONTRIBUTING.rst | 0 README.rst | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename notes/hacking.rst => CONTRIBUTING.rst (100%) diff --git a/notes/hacking.rst b/CONTRIBUTING.rst similarity index 100% rename from notes/hacking.rst rename to CONTRIBUTING.rst diff --git a/README.rst b/README.rst index 9c1da2ed0..fe0a6f394 100644 --- a/README.rst +++ b/README.rst @@ -3,4 +3,4 @@ Boost.Build See the Boost.Build website at https://boost.org/build. -See the `guidelines for contributing <./notes/hacking.rst>`__. +See the `guidelines for contributing <./CONTRIBUTING.rst>`__. From 94816f80fff29a649ff52c3c675454d8fd6949ba Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Sat, 6 Aug 2016 14:48:39 -0500 Subject: [PATCH 045/158] Add emscripten debug option to get better runtime debug output. --- src/tools/emscripten.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/emscripten.jam b/src/tools/emscripten.jam index 74e3c200a..2ad1b804a 100644 --- a/src/tools/emscripten.jam +++ b/src/tools/emscripten.jam @@ -79,7 +79,7 @@ toolset.flags emscripten.compile OPTIONS all : -Wall -pedantic ; toolset.flags emscripten.compile OPTIONS on : -Werror ; toolset.flags emscripten OPTIONS off : -g0 ; -toolset.flags emscripten OPTIONS on : -g4 ; +toolset.flags emscripten OPTIONS on : -g4 -s DEMANGLE_SUPPORT=1 ; toolset.flags emscripten OPTIONS off : -fno-rtti ; toolset.flags emscripten.link OPTIONS on : --bind ; From 8806da64165df1e2266e05c451e4cae1071070fe Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Fri, 23 Sep 2016 22:58:47 -0500 Subject: [PATCH 046/158] Add support for perf meassuring native scopes. And add some perf scopes for the main interpreter function. --- src/engine/debug.c | 45 +++++---- src/engine/debug.h | 29 +++--- src/engine/function.c | 211 ++++++++++++++++++++++++++++++++++++++++++ src/engine/hash.c | 2 +- 4 files changed, 259 insertions(+), 28 deletions(-) diff --git a/src/engine/debug.c b/src/engine/debug.c index b4601066f..3dc353392 100644 --- a/src/engine/debug.c +++ b/src/engine/debug.c @@ -1,5 +1,5 @@ /* - * Copyright 2005. Rene Rivera + * Copyright 2005, 2016. Rene Rivera * 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) @@ -9,6 +9,7 @@ #include "debug.h" #include "output.h" #include "hash.h" +#include static profile_frame * profile_stack = 0; @@ -28,7 +29,7 @@ void profile_enter( OBJECT * rulename, profile_frame * frame ) { if ( DEBUG_PROFILE ) { - clock_t start = clock(); + double start = profile_clock(); profile_info * p; if ( !profile_hash && rulename ) @@ -53,15 +54,15 @@ void profile_enter( OBJECT * rulename, profile_frame * frame ) p = &profile_other; } - ++p->num_entries; - ++p->stack_count; + p->num_entries += 1; + p->stack_count += 1; frame->info = p; frame->caller = profile_stack; profile_stack = frame; - frame->entry_time = clock(); + frame->entry_time = profile_clock(); frame->overhead = 0; frame->subrules = 0; @@ -76,7 +77,7 @@ void profile_memory( long mem ) { if ( DEBUG_PROFILE ) if ( profile_stack && profile_stack->info ) - profile_stack->info->memory += mem; + profile_stack->info->memory += ((double)mem) / 1024; } @@ -85,7 +86,7 @@ void profile_exit( profile_frame * frame ) if ( DEBUG_PROFILE ) { /* Cumulative time for this call. */ - clock_t const t = clock() - frame->entry_time - frame->overhead; + double t = profile_clock() - frame->entry_time - frame->overhead; /* If this rule is already present on the stack, do not add the time for * this instance. */ @@ -111,22 +112,17 @@ void profile_exit( profile_frame * frame ) static void dump_profile_entry( void * p_, void * ignored ) { profile_info * p = (profile_info *)p_; - unsigned long mem_each = ( p->memory / ( p->num_entries ? p->num_entries : 1 + double mem_each = ( p->memory / ( p->num_entries ? p->num_entries : 1 ) ); - double cumulative = p->cumulative; - double net = p->net; double q = p->net; - q /= ( p->num_entries ? p->num_entries : 1 ); - cumulative /= CLOCKS_PER_SEC; - net /= CLOCKS_PER_SEC; - q /= CLOCKS_PER_SEC; + if (p->num_entries) q /= p->num_entries; if ( !ignored ) { profile_total.cumulative += p->net; profile_total.memory += p->memory; } - out_printf( "%10ld %12.6f %12.6f %12.8f %10ld %10ld %s\n", p->num_entries, - cumulative, net, q, p->memory, mem_each, object_str( p->name ) ); + out_printf( "%10ld %12.6f %12.6f %12.8f %10.2f %10.2f %s\n", p->num_entries, + p->cumulative, p->net, q, p->memory, mem_each, object_str( p->name ) ); } @@ -143,3 +139,20 @@ void profile_dump() dump_profile_entry( &profile_total, (void *)1 ); } } + +double profile_clock() +{ + return ((double) clock()) / CLOCKS_PER_SEC; +} + +OBJECT * profile_make_local( char const * scope ) +{ + if ( DEBUG_PROFILE ) + { + return object_new( scope ); + } + else + { + return 0; + } +} diff --git a/src/engine/debug.h b/src/engine/debug.h index 4151d27fa..b4e8472c9 100644 --- a/src/engine/debug.h +++ b/src/engine/debug.h @@ -1,5 +1,5 @@ /* - * Copyright 2005. Rene Rivera + * Copyright 2005, 2016. Rene Rivera * 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) @@ -10,23 +10,22 @@ #include "constants.h" #include "object.h" -#include typedef struct profile_info { /* name of rule being called */ OBJECT * name; - /* cumulative time spent in rule */ - clock_t cumulative; - /* time spent in rule proper */ - clock_t net; + /* cumulative time spent in rule, in seconds */ + double cumulative; + /* time spent in rule proper, in seconds */ + double net; /* number of time rule was entered */ unsigned long num_entries; /* number of the times this function is present in stack */ unsigned long stack_count; - /* bytes of memory allocated by the call */ - unsigned long memory; + /* memory allocated by the call, in KiB */ + double memory; } profile_info; typedef struct profile_frame @@ -34,13 +33,13 @@ typedef struct profile_frame /* permanent storage where data accumulates */ profile_info * info; /* overhead for profiling in this call */ - clock_t overhead; + double overhead; /* time of last entry to rule */ - clock_t entry_time; + double entry_time; /* stack frame of caller */ struct profile_frame * caller; /* time spent in subrules */ - clock_t subrules; + double subrules; } profile_frame; profile_frame * profile_init( OBJECT * rulename, profile_frame * ); @@ -48,8 +47,16 @@ void profile_enter( OBJECT * rulename, profile_frame * ); void profile_memory( long mem ); void profile_exit( profile_frame * ); void profile_dump(); +double profile_clock(); #define PROFILE_ENTER( scope ) profile_frame PROF_ ## scope, *PROF_ ## scope ## _p = profile_init( constant_ ## scope, &PROF_ ## scope ) #define PROFILE_EXIT( scope ) profile_exit( PROF_ ## scope ## _p ) +OBJECT * profile_make_local( char const * ); +#define PROFILE_ENTER_LOCAL( scope ) \ + static OBJECT * constant_LOCAL_##scope = 0; \ + if (DEBUG_PROFILE && !constant_LOCAL_##scope) constant_LOCAL_##scope = profile_make_local( #scope ); \ + PROFILE_ENTER( LOCAL_##scope ) +#define PROFILE_EXIT_LOCAL( scope ) PROFILE_EXIT( LOCAL_##scope ) + #endif diff --git a/src/engine/function.c b/src/engine/function.c index 510acbde4..ecf6c5177 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -1,5 +1,6 @@ /* * Copyright 2011 Steven Watanabe + * Copyright 2016 Rene Rivera * 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) @@ -26,6 +27,15 @@ #include #include +/* * +#define FUNCTION_DEBUG_PROFILE +/* */ + +#ifndef FUNCTION_DEBUG_PROFILE +#define PROFILE_ENTER_LOCAL(x) +#define PROFILE_EXIT_LOCAL(x) +#endif + int glob( char const * s, char const * c ); void backtrace( FRAME * ); void backtrace_line( FRAME * ); @@ -3766,12 +3776,15 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) LIST * result = L0; void * saved_stack = s->data; + PROFILE_ENTER_LOCAL(function_run); + if ( function_->type == FUNCTION_BUILTIN ) { BUILTIN_FUNCTION const * const f = (BUILTIN_FUNCTION *)function_; if ( function_->formal_arguments ) argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame ); + PROFILE_EXIT_LOCAL(function_run); return f->func( frame, f->flags ); } @@ -3779,6 +3792,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) else if ( function_->type == FUNCTION_PYTHON ) { PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_; + PROFILE_EXIT_LOCAL(function_run); return call_python_function( f, frame ); } #endif @@ -3801,31 +3815,50 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) */ case INSTR_PUSH_EMPTY: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_EMPTY); stack_push( s, L0 ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_EMPTY); break; + } case INSTR_PUSH_CONSTANT: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_CONSTANT); OBJECT * value = function_get_constant( function, code->arg ); stack_push( s, list_new( object_copy( value ) ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_CONSTANT); break; } case INSTR_PUSH_ARG: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_ARG); stack_push( s, frame_get_local( frame, code->arg ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_ARG); break; + } case INSTR_PUSH_VAR: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_VAR); stack_push( s, function_get_variable( function, frame, code->arg ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_VAR); break; + } case INSTR_PUSH_VAR_FIXED: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_VAR_FIXED); stack_push( s, list_copy( frame->module->fixed_variables[ code->arg ] ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_VAR_FIXED); break; + } case INSTR_PUSH_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_GROUP); LIST * value = L0; LISTITER iter; LISTITER end; @@ -3836,121 +3869,183 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) function, frame, list_item( iter ) ) ); list_free( l ); stack_push( s, value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_GROUP); break; } case INSTR_PUSH_APPEND: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_APPEND); r = stack_pop( s ); l = stack_pop( s ); stack_push( s, list_append( l, r ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_APPEND); break; + } case INSTR_SWAP: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_SWAP); l = stack_top( s ); stack_set( s, 0, stack_at( s, code->arg ) ); stack_set( s, code->arg, l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_SWAP); break; + } case INSTR_POP: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_POP); list_free( stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_POP); break; + } /* * Branch instructions */ case INSTR_JUMP: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP); code += code->arg; + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP); break; + } case INSTR_JUMP_EMPTY: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_EMPTY); l = stack_pop( s ); if ( !list_cmp( l, L0 ) ) code += code->arg; list_free( l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_EMPTY); break; + } case INSTR_JUMP_NOT_EMPTY: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NOT_EMPTY); l = stack_pop( s ); if ( list_cmp( l, L0 ) ) code += code->arg; list_free( l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NOT_EMPTY); break; + } case INSTR_JUMP_LT: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_LT); r = stack_pop( s ); l = stack_pop( s ); if ( list_cmp( l, r ) < 0 ) code += code->arg; list_free( l ); list_free( r ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_LT); break; + } case INSTR_JUMP_LE: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_LE); r = stack_pop( s ); l = stack_pop( s ); if ( list_cmp( l, r ) <= 0 ) code += code->arg; list_free( l ); list_free( r ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_LE); break; + } case INSTR_JUMP_GT: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_GT); r = stack_pop( s ); l = stack_pop( s ); if ( list_cmp( l, r ) > 0 ) code += code->arg; list_free( l ); list_free( r ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_GT); break; + } case INSTR_JUMP_GE: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_GE); r = stack_pop( s ); l = stack_pop( s ); if ( list_cmp( l, r ) >= 0 ) code += code->arg; list_free( l ); list_free( r ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_GE); break; + } case INSTR_JUMP_EQ: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_EQ); r = stack_pop( s ); l = stack_pop( s ); if ( list_cmp( l, r ) == 0 ) code += code->arg; list_free( l ); list_free( r ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_EQ); break; + } case INSTR_JUMP_NE: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NE); r = stack_pop(s); l = stack_pop(s); if ( list_cmp(l, r) != 0 ) code += code->arg; list_free(l); list_free(r); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NE); break; + } case INSTR_JUMP_IN: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_IN); r = stack_pop(s); l = stack_pop(s); if ( list_is_sublist( l, r ) ) code += code->arg; list_free(l); list_free(r); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_IN); break; + } case INSTR_JUMP_NOT_IN: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NOT_IN); r = stack_pop( s ); l = stack_pop( s ); if ( !list_is_sublist( l, r ) ) code += code->arg; list_free( l ); list_free( r ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NOT_IN); break; + } /* * For */ case INSTR_FOR_INIT: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_FOR_INIT); l = stack_top( s ); *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) = list_begin( l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_FOR_INIT); break; + } case INSTR_FOR_LOOP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_FOR_LOOP); LISTITER iter = *(LISTITER *)stack_get( s ); stack_deallocate( s, sizeof( LISTITER ) ); l = stack_top( s ); @@ -3966,13 +4061,16 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) *(LISTITER *)stack_allocate( s, sizeof( LISTITER ) ) = iter; stack_push( s, r ); } + PROFILE_EXIT_LOCAL(function_run_INSTR_FOR_LOOP); break; } case INSTR_FOR_POP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_FOR_POP); stack_deallocate( s, sizeof( LISTITER ) ); list_free( stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_FOR_POP); break; } @@ -3982,6 +4080,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) case INSTR_JUMP_NOT_GLOB: { + PROFILE_ENTER_LOCAL(function_run_INSTR_JUMP_NOT_GLOB); char const * pattern; char const * match; l = stack_pop( s ); @@ -3993,6 +4092,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) else list_free( stack_pop( s ) ); list_free( l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_JUMP_NOT_GLOB); break; } @@ -4001,20 +4101,29 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) */ case INSTR_SET_RESULT: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_SET_RESULT); list_free( result ); if ( !code->arg ) result = stack_pop( s ); else result = list_copy( stack_top( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_SET_RESULT); break; + } case INSTR_PUSH_RESULT: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_RESULT); stack_push( s, result ); result = L0; + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_RESULT); break; + } case INSTR_RETURN: { + PROFILE_ENTER_LOCAL(function_run_INSTR_RETURN); if ( function_->formal_arguments ) argument_list_pop( function_->formal_arguments, function_->num_formal_arguments, frame, s ); @@ -4030,6 +4139,8 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) } #endif assert( saved_stack == s->data ); + PROFILE_EXIT_LOCAL(function_run_INSTR_RETURN); + PROFILE_EXIT_LOCAL(function_run); return result; } @@ -4039,38 +4150,49 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) case INSTR_PUSH_LOCAL: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_LOCAL); LIST * value = stack_pop( s ); stack_push( s, function_swap_variable( function, frame, code->arg, value ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_LOCAL); break; } case INSTR_POP_LOCAL: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_POP_LOCAL); function_set_variable( function, frame, code->arg, stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_POP_LOCAL); break; + } case INSTR_PUSH_LOCAL_FIXED: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_LOCAL_FIXED); LIST * value = stack_pop( s ); LIST * * ptr = &frame->module->fixed_variables[ code->arg ]; assert( code->arg < frame->module->num_fixed_variables ); stack_push( s, *ptr ); *ptr = value; + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_LOCAL_FIXED); break; } case INSTR_POP_LOCAL_FIXED: { + PROFILE_ENTER_LOCAL(function_run_INSTR_POP_LOCAL_FIXED); LIST * value = stack_pop( s ); LIST * * ptr = &frame->module->fixed_variables[ code->arg ]; assert( code->arg < frame->module->num_fixed_variables ); list_free( *ptr ); *ptr = value; + PROFILE_EXIT_LOCAL(function_run_INSTR_POP_LOCAL_FIXED); break; } case INSTR_PUSH_LOCAL_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_LOCAL_GROUP); LIST * const value = stack_pop( s ); LISTITER iter; LISTITER end; @@ -4081,11 +4203,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_item( iter ), list_copy( value ) ) ); list_free( value ); stack_push( s, l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_LOCAL_GROUP); break; } case INSTR_POP_LOCAL_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_POP_LOCAL_GROUP); LISTITER iter; LISTITER end; r = stack_pop( s ); @@ -4096,6 +4220,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) function_set_named_variable( function, frame, list_item( iter ), stack_pop( s ) ); list_free( l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_POP_LOCAL_GROUP); break; } @@ -4105,6 +4230,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) case INSTR_PUSH_ON: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_ON); LIST * targets = stack_top( s ); if ( !list_empty( targets ) ) { @@ -4121,11 +4247,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) stack_push( s, L0 ); code += code->arg; } + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_ON); break; } case INSTR_POP_ON: { + PROFILE_ENTER_LOCAL(function_run_INSTR_POP_ON); LIST * result = stack_pop( s ); LIST * targets = stack_pop( s ); if ( !list_empty( targets ) ) @@ -4135,11 +4263,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) } list_free( targets ); stack_push( s, result ); + PROFILE_EXIT_LOCAL(function_run_INSTR_POP_ON); break; } case INSTR_SET_ON: { + PROFILE_ENTER_LOCAL(function_run_INSTR_SET_ON); LIST * targets = stack_pop( s ); LIST * value = stack_pop( s ); LIST * vars = stack_pop( s ); @@ -4158,11 +4288,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_free( vars ); list_free( targets ); stack_push( s, value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_SET_ON); break; } case INSTR_APPEND_ON: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_ON); LIST * targets = stack_pop( s ); LIST * value = stack_pop( s ); LIST * vars = stack_pop( s ); @@ -4181,11 +4313,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_free( vars ); list_free( targets ); stack_push( s, value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_ON); break; } case INSTR_DEFAULT_ON: { + PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT_ON); LIST * targets = stack_pop( s ); LIST * value = stack_pop( s ); LIST * vars = stack_pop( s ); @@ -4204,12 +4338,14 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_free( vars ); list_free( targets ); stack_push( s, value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT_ON); break; } /* [ on $(target) return $(variable) ] */ case INSTR_GET_ON: { + PROFILE_ENTER_LOCAL(function_run_INSTR_GET_ON); LIST * targets = stack_pop( s ); LIST * result = L0; if ( !list_empty( targets ) ) @@ -4234,6 +4370,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) } list_free( targets ); stack_push( s, list_copy( result ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_GET_ON); break; } @@ -4242,39 +4379,56 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) */ case INSTR_SET: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_SET); function_set_variable( function, frame, code->arg, stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_SET); break; + } case INSTR_APPEND: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND); function_append_variable( function, frame, code->arg, stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND); break; + } case INSTR_DEFAULT: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT); function_default_variable( function, frame, code->arg, stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT); break; + } case INSTR_SET_FIXED: { + PROFILE_ENTER_LOCAL(function_run_INSTR_SET_FIXED); LIST * * ptr = &frame->module->fixed_variables[ code->arg ]; assert( code->arg < frame->module->num_fixed_variables ); list_free( *ptr ); *ptr = stack_pop( s ); + PROFILE_EXIT_LOCAL(function_run_INSTR_SET_FIXED); break; } case INSTR_APPEND_FIXED: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_FIXED); LIST * * ptr = &frame->module->fixed_variables[ code->arg ]; assert( code->arg < frame->module->num_fixed_variables ); *ptr = list_append( *ptr, stack_pop( s ) ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_FIXED); break; } case INSTR_DEFAULT_FIXED: { + PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT_FIXED); LIST * * ptr = &frame->module->fixed_variables[ code->arg ]; LIST * value = stack_pop( s ); assert( code->arg < frame->module->num_fixed_variables ); @@ -4282,11 +4436,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) *ptr = value; else list_free( value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT_FIXED); break; } case INSTR_SET_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_SET_GROUP); LIST * value = stack_pop( s ); LIST * vars = stack_pop( s ); LISTITER iter = list_begin( vars ); @@ -4296,11 +4452,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_copy( value ) ); list_free( vars ); list_free( value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_SET_GROUP); break; } case INSTR_APPEND_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_GROUP); LIST * value = stack_pop( s ); LIST * vars = stack_pop( s ); LISTITER iter = list_begin( vars ); @@ -4310,11 +4468,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) ), list_copy( value ) ); list_free( vars ); list_free( value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_GROUP); break; } case INSTR_DEFAULT_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_DEFAULT_GROUP); LIST * value = stack_pop( s ); LIST * vars = stack_pop( s ); LISTITER iter = list_begin( vars ); @@ -4324,6 +4484,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) iter ), list_copy( value ) ); list_free( vars ); list_free( value ); + PROFILE_EXIT_LOCAL(function_run_INSTR_DEFAULT_GROUP); break; } @@ -4333,31 +4494,43 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) case INSTR_CALL_RULE: { + PROFILE_ENTER_LOCAL(function_run_INSTR_CALL_RULE); char const * unexpanded = object_str( function_get_constant( function, code[ 1 ].op_code ) ); LIST * result = function_call_rule( function, frame, s, code->arg, unexpanded, function->file, code[ 1 ].arg ); stack_push( s, result ); ++code; + PROFILE_EXIT_LOCAL(function_run_INSTR_CALL_RULE); break; } case INSTR_CALL_MEMBER_RULE: { + PROFILE_ENTER_LOCAL(function_run_INSTR_CALL_MEMBER_RULE); OBJECT * rule_name = function_get_constant( function, code[1].op_code ); LIST * result = function_call_member_rule( function, frame, s, code->arg, rule_name, function->file, code[1].arg ); stack_push( s, result ); ++code; + PROFILE_EXIT_LOCAL(function_run_INSTR_CALL_MEMBER_RULE); break; } case INSTR_RULE: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_RULE); function_set_rule( function, frame, s, code->arg ); + PROFILE_EXIT_LOCAL(function_run_INSTR_RULE); break; + } case INSTR_ACTIONS: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_ACTIONS); function_set_actions( function, frame, s, code->arg ); + PROFILE_EXIT_LOCAL(function_run_INSTR_ACTIONS); break; + } /* * Variable expansion @@ -4365,6 +4538,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) case INSTR_APPLY_MODIFIERS: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_MODIFIERS); int n; int i; l = stack_pop( s ); @@ -4376,18 +4550,24 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) for ( i = 0; i < code->arg; ++i ) list_free( stack_pop( s ) ); /* pop modifiers */ stack_push( s, l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_MODIFIERS); break; } case INSTR_APPLY_INDEX: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX); l = apply_subscript( s ); list_free( stack_pop( s ) ); list_free( stack_pop( s ) ); stack_push( s, l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX); break; + } case INSTR_APPLY_INDEX_MODIFIERS: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS); int i; int n; l = stack_pop( s ); @@ -4402,11 +4582,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) for ( i = 0; i < code->arg; ++i ) list_free( stack_pop( s ) ); /* pop modifiers */ stack_push( s, l ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS); break; } case INSTR_APPLY_MODIFIERS_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_MODIFIERS_GROUP); int i; LIST * const vars = stack_pop( s ); int const n = expand_modifiers( s, code->arg ); @@ -4425,11 +4607,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) for ( i = 0; i < code->arg; ++i ) list_free( stack_pop( s ) ); /* pop modifiers */ stack_push( s, result ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_MODIFIERS_GROUP); break; } case INSTR_APPLY_INDEX_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX_GROUP); LIST * vars = stack_pop( s ); LIST * result = L0; LISTITER iter = list_begin( vars ); @@ -4444,11 +4628,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_free( vars ); list_free( stack_pop( s ) ); stack_push( s, result ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX_GROUP); break; } case INSTR_APPLY_INDEX_MODIFIERS_GROUP: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS_GROUP); int i; LIST * const vars = stack_pop( s ); LIST * const r = stack_pop( s ); @@ -4471,11 +4657,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) for ( i = 0; i < code->arg; ++i ) list_free( stack_pop( s ) ); /* pop modifiers */ stack_push( s, result ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPLY_INDEX_MODIFIERS_GROUP); break; } case INSTR_COMBINE_STRINGS: { + PROFILE_ENTER_LOCAL(function_run_INSTR_COMBINE_STRINGS); size_t const buffer_size = code->arg * sizeof( expansion_item ); LIST * * const stack_pos = stack_get( s ); expansion_item * items = stack_allocate( s, buffer_size ); @@ -4488,11 +4676,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) for ( i = 0; i < code->arg; ++i ) list_free( stack_pop( s ) ); stack_push( s, result ); + PROFILE_EXIT_LOCAL(function_run_INSTR_COMBINE_STRINGS); break; } case INSTR_GET_GRIST: { + PROFILE_ENTER_LOCAL(function_run_INSTR_GET_GRIST); LIST * vals = stack_pop( s ); LIST * result = L0; LISTITER iter, end; @@ -4518,11 +4708,13 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_free( vals ); stack_push( s, result ); + PROFILE_EXIT_LOCAL(function_run_INSTR_GET_GRIST); break; } case INSTR_INCLUDE: { + PROFILE_ENTER_LOCAL(function_run_INSTR_INCLUDE); LIST * nt = stack_pop( s ); if ( !list_empty( nt ) ) { @@ -4551,6 +4743,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) parse_file( t->boundname, frame ); } + PROFILE_EXIT_LOCAL(function_run_INSTR_INCLUDE); break; } @@ -4560,6 +4753,7 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) case INSTR_PUSH_MODULE: { + PROFILE_ENTER_LOCAL(function_run_INSTR_PUSH_MODULE); LIST * const module_name = stack_pop( s ); module_t * const outer_module = frame->module; frame->module = !list_empty( module_name ) @@ -4568,19 +4762,23 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) list_free( module_name ); *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module; + PROFILE_EXIT_LOCAL(function_run_INSTR_PUSH_MODULE); break; } case INSTR_POP_MODULE: { + PROFILE_ENTER_LOCAL(function_run_INSTR_POP_MODULE); module_t * const outer_module = *(module_t * *)stack_get( s ); stack_deallocate( s, sizeof( module_t * ) ); frame->module = outer_module; + PROFILE_EXIT_LOCAL(function_run_INSTR_POP_MODULE); break; } case INSTR_CLASS: { + PROFILE_ENTER_LOCAL(function_run_INSTR_CLASS); LIST * bases = stack_pop( s ); LIST * name = stack_pop( s ); OBJECT * class_module = make_class_module( name, bases, frame ); @@ -4591,25 +4789,33 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) *(module_t * *)stack_allocate( s, sizeof( module_t * ) ) = outer_module; + PROFILE_EXIT_LOCAL(function_run_INSTR_CLASS); break; } case INSTR_BIND_MODULE_VARIABLES: + { + PROFILE_ENTER_LOCAL(function_run_INSTR_BIND_MODULE_VARIABLES); module_bind_variables( frame->module ); + PROFILE_EXIT_LOCAL(function_run_INSTR_BIND_MODULE_VARIABLES); break; + } case INSTR_APPEND_STRINGS: { + PROFILE_ENTER_LOCAL(function_run_INSTR_APPEND_STRINGS); string buf[ 1 ]; string_new( buf ); combine_strings( s, code->arg, buf ); stack_push( s, list_new( object_new( buf->value ) ) ); string_free( buf ); + PROFILE_EXIT_LOCAL(function_run_INSTR_APPEND_STRINGS); break; } case INSTR_WRITE_FILE: { + PROFILE_ENTER_LOCAL(function_run_INSTR_WRITE_FILE); string buf[ 1 ]; char const * out; OBJECT * tmp_filename = 0; @@ -4715,20 +4921,25 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) object_free( tmp_filename ); if ( out_debug ) out_putc( '\n' ); + PROFILE_EXIT_LOCAL(function_run_INSTR_WRITE_FILE); break; } case INSTR_OUTPUT_STRINGS: { + PROFILE_ENTER_LOCAL(function_run_INSTR_OUTPUT_STRINGS); string * const buf = *(string * *)( (char *)stack_get( s ) + ( code->arg * sizeof( LIST * ) ) ); combine_strings( s, code->arg, buf ); + PROFILE_EXIT_LOCAL(function_run_INSTR_OUTPUT_STRINGS); break; } } ++code; } + + PROFILE_EXIT_LOCAL(function_run); } diff --git a/src/engine/hash.c b/src/engine/hash.c index 772087a22..b2685a860 100644 --- a/src/engine/hash.c +++ b/src/engine/hash.c @@ -24,7 +24,7 @@ #include -/* */ +/* * #define HASH_DEBUG_PROFILE 1 /* */ From 590cbb42b561f2a21d328ece1dc99b4b76408974 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 27 Sep 2016 06:15:54 -0500 Subject: [PATCH 047/158] Add some missing profile scopes in function_run. --- src/engine/function.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/engine/function.c b/src/engine/function.c index ecf6c5177..bd42237e0 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -3780,10 +3780,12 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) if ( function_->type == FUNCTION_BUILTIN ) { + PROFILE_ENTER_LOCAL(function_run_FUNCTION_BUILTIN); BUILTIN_FUNCTION const * const f = (BUILTIN_FUNCTION *)function_; if ( function_->formal_arguments ) argument_list_check( function_->formal_arguments, function_->num_formal_arguments, function_, frame ); + PROFILE_EXIT_LOCAL(function_run_FUNCTION_BUILTIN); PROFILE_EXIT_LOCAL(function_run); return f->func( frame, f->flags ); } @@ -3791,7 +3793,9 @@ LIST * function_run( FUNCTION * function_, FRAME * frame, STACK * s ) #ifdef HAVE_PYTHON else if ( function_->type == FUNCTION_PYTHON ) { + PROFILE_ENTER_LOCAL(function_run_FUNCTION_PYTHON); PYTHON_FUNCTION * f = (PYTHON_FUNCTION *)function_; + PROFILE_EXIT_LOCAL(function_run_FUNCTION_PYTHON); PROFILE_EXIT_LOCAL(function_run); return call_python_function( f, frame ); } From 2591785b6ed74d50d926dd042048e53abc91c174 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Thu, 29 Sep 2016 21:56:07 +0100 Subject: [PATCH 048/158] Replace '.has_key()' with 'in'. --- src/build/engine.py | 2 +- src/build/feature.py | 26 +++++++++++++------------- src/build/generators.py | 8 ++++---- src/build/project.py | 10 +++++----- src/build/property.py | 2 +- src/build/property_set.py | 10 +++++----- src/build/scanner.py | 6 +++--- src/build/targets.py | 12 ++++++------ src/build/type.py | 8 ++++---- src/build/virtual_target.py | 8 ++++---- src/tools/common.py | 10 +++++----- src/tools/doxproc.py | 14 +++++++------- src/tools/msvc.py | 2 +- src/tools/rc.py | 2 +- src/util/option.py | 2 +- 15 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/build/engine.py b/src/build/engine.py index 4c2c97eaf..9d6b99c50 100644 --- a/src/build/engine.py +++ b/src/build/engine.py @@ -206,7 +206,7 @@ class Engine: # action is already registered. assert isinstance(action_name, basestring) assert function is None or callable(function) - if not self.actions.has_key(action_name): + if action_name not in self.actions: self.actions[action_name] = BjamNativeAction(action_name, function) # Overridables diff --git a/src/build/feature.py b/src/build/feature.py index 6cf81a1a1..a8abf6969 100644 --- a/src/build/feature.py +++ b/src/build/feature.py @@ -260,12 +260,12 @@ def is_implicit_value (value_string): of an implicit feature. """ assert isinstance(value_string, basestring) - if __implicit_features.has_key(value_string): + if value_string in __implicit_features: return __implicit_features[value_string] v = value_string.split('-') - if not __implicit_features.has_key(v[0]): + if v[0] not in __implicit_features: return False feature = __implicit_features[v[0]] @@ -282,7 +282,7 @@ def implied_feature (implicit_value): assert isinstance(implicit_value, basestring) components = implicit_value.split('-') - if not __implicit_features.has_key(components[0]): + if components[0] not in __implicit_features: raise InvalidValue ("'%s' is not a value of an implicit feature" % implicit_value) return __implicit_features[components[0]] @@ -318,7 +318,7 @@ def validate_feature (name): """ Checks if all name is a valid feature. Otherwise, raises an exception. """ assert isinstance(name, basestring) - if not __all_features.has_key(name): + if name not in __all_features: raise InvalidFeature ("'%s' is not a valid feature name" % name) else: return __all_features[name] @@ -432,7 +432,7 @@ def extend (name, values): if feature.implicit(): for v in values: - if __implicit_features.has_key(v): + if v in __implicit_features: raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) __implicit_features[v] = feature @@ -503,11 +503,11 @@ def extend_subfeature (feature_name, value_string, subfeature_name, subvalues): if value_string == None: value_string = '' - if not __subfeature_from_value.has_key(feature): - __subfeature_from_value [feature] = {} + if feature not in __subfeature_from_value: + __subfeature_from_value[feature] = {} - if not __subfeature_from_value[feature].has_key(value_string): - __subfeature_from_value [feature][value_string] = {} + if value_string not in __subfeature_from_value[feature]: + __subfeature_from_value[feature][value_string] = {} for subvalue in subvalues: __subfeature_from_value [feature][value_string][subvalue] = subfeature @@ -564,7 +564,7 @@ def compose (composite_property_s, component_properties_s): if not f.composite(): raise BaseException ("'%s' is not a composite feature" % f) - if __composite_properties.has_key(property): + if property in __composite_properties: raise BaseException ('components of "%s" already set: %s' % (composite_property, str (__composite_properties[composite_property]))) if composite_property in component_properties: @@ -578,7 +578,7 @@ def expand_composite(property_): from .property import Property assert isinstance(property_, Property) result = [ property_ ] - if __composite_properties.has_key(property_): + if property_ in __composite_properties: for p in __composite_properties[property_]: result.extend(expand_composite(p)) return result @@ -776,7 +776,7 @@ def minimize (properties): # remove properties implied by composite features components = [] for property in properties: - if __composite_properties.has_key (property): + if property in __composite_properties: components.extend(__composite_properties[property]) properties = b2.util.set.difference (properties, components) @@ -935,7 +935,7 @@ def __validate_feature (feature): """ Generates an error if the feature is unknown. """ assert isinstance(feature, basestring) - if not __all_features.has_key (feature): + if feature not in __all_features: raise BaseException ('unknown feature "%s"' % feature) diff --git a/src/build/generators.py b/src/build/generators.py index f1c514556..c2e21510c 100644 --- a/src/build/generators.py +++ b/src/build/generators.py @@ -138,7 +138,7 @@ def invalidate_extendable_viable_source_target_type_cache(): __vstg_cached_generators = [] for g in generators_with_cached_source_types: - if __viable_source_types_cache.has_key(g): + if g in __viable_source_types_cache: if __viable_source_types_cache[g] == ["*"]: __vstg_cached_generators.append(g) else: @@ -148,7 +148,7 @@ def invalidate_extendable_viable_source_target_type_cache(): types_with_cached_sources_types = __vst_cached_types __vst_cached_types = [] for t in types_with_cached_sources_types: - if __viable_source_types_cache.has_key(t): + if t in __viable_source_types_cache: if __viable_source_types_cache[t] == ["*"]: __vst_cached_types.append(t) else: @@ -831,7 +831,7 @@ def viable_source_types (target_type): """ Helper rule, caches the result of '__viable_source_types_real'. """ assert isinstance(target_type, basestring) - if not __viable_source_types_cache.has_key(target_type): + if target_type not in __viable_source_types_cache: __vst_cached_types.append(target_type) __viable_source_types_cache [target_type] = __viable_source_types_real (target_type) return __viable_source_types_cache [target_type] @@ -867,7 +867,7 @@ def viable_source_types_for_generator (generator): """ Caches the result of 'viable_source_types_for_generator'. """ assert isinstance(generator, Generator) - if not __viable_source_types_cache.has_key(generator): + if generator not in __viable_source_types_cache: __vstg_cached_generators.append(generator) __viable_source_types_cache[generator] = viable_source_types_for_generator_real (generator) diff --git a/src/build/project.py b/src/build/project.py index ea8fe0106..44429e301 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -452,7 +452,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # If it's jamroot, inherit from user-config. if location: # If project-config module exist, inherit from it. - if self.module2attributes.has_key("project-config"): + if "project-config" in self.module2attributes: parent_module = "project-config" else: parent_module = "user-config" ; @@ -470,7 +470,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) if parent_module: parent = self.target(parent_module) - if not self.module2target.has_key(module_name): + if module_name not in self.module2target: target = b2.build.targets.ProjectTarget(self.manager, module_name, module_name, parent, self.attribute(module_name, "requirements"), @@ -577,7 +577,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) def target(self, project_module): """Returns the project target corresponding to the 'project-module'.""" assert isinstance(project_module, basestring) - if not self.module2target.has_key(project_module): + if project_module not in self.module2target: self.module2target[project_module] = \ b2.build.targets.ProjectTarget(project_module, project_module, self.attribute(project_module, "requirements")) @@ -595,7 +595,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) if not declared_id or declared_id != id: # The project at 'location' either have no id or # that id is not equal to the 'id' parameter. - if self.id2module.has_key(id) and self.id2module[id] != project_module: + if id in self.id2module and self.id2module[id] != project_module: self.manager.errors()( """Attempt to redeclare already existing project id '%s' at location '%s'""" % (id, location)) self.id2module[id] = project_module @@ -1167,7 +1167,7 @@ attribute is allowed only for top-level 'project' invocations""") location = current.get('location') m = self.registry.load_module(toolset[0], [location]) - if not m.__dict__.has_key("init"): + if "init" not in m.__dict__: self.registry.manager.errors()( "Tool module '%s' does not define the 'init' method" % toolset[0]) m.init(*args) diff --git a/src/build/property.py b/src/build/property.py index 11a18ff38..72de89825 100644 --- a/src/build/property.py +++ b/src/build/property.py @@ -210,7 +210,7 @@ def refine (properties, requirements): elif p.feature().free(): result.add(p) else: - if required.has_key(p.feature()): + if p.feature() in required: result.add(required[p.feature()]) else: result.add(p) diff --git a/src/build/property_set.py b/src/build/property_set.py index 494a5b1b7..d9a1bd97a 100644 --- a/src/build/property_set.py +++ b/src/build/property_set.py @@ -51,7 +51,7 @@ def create (raw_properties = []): # hash value of the list? key = tuple(x) - if not __cache.has_key (key): + if key not in __cache: __cache [key] = PropertySet(x) return __cache [key] @@ -294,7 +294,7 @@ class PropertySet: """ Refines this set's properties using the requirements passed as an argument. """ assert isinstance(requirements, PropertySet) - if not self.refined_.has_key (requirements): + if requirements not in self.refined_: r = property.refine(self.all_, requirements.all_) self.refined_[requirements] = create(r) @@ -317,7 +317,7 @@ class PropertySet: if not context: context = self - if not self.evaluated_.has_key(context): + if context not in self.evaluated_: # FIXME: figure why the call messes up first parameter self.evaluated_[context] = create( property.evaluate_conditionals_in_context(self.all(), context)) @@ -421,7 +421,7 @@ class PropertySet: plus the ones of the property set passed as argument. """ assert isinstance(ps, PropertySet) - if not self.added_.has_key(ps): + if ps not in self.added_: self.added_[ps] = create(self.all_ + ps.all()) return self.added_[ps] @@ -445,7 +445,7 @@ class PropertySet: self.feature_map_ = {} for v in self.all_: - if not self.feature_map_.has_key(v.feature()): + if v.feature() not in self.feature_map_: self.feature_map_[v.feature()] = [] self.feature_map_[v.feature()].append(v.value()) diff --git a/src/build/scanner.py b/src/build/scanner.py index ada5d8325..a9720b74b 100644 --- a/src/build/scanner.py +++ b/src/build/scanner.py @@ -65,7 +65,7 @@ def register(scanner_class, relevant_properties): def registered(scanner_class): """ Returns true iff a scanner of that class is registered """ - return __scanners.has_key(str(scanner_class)) + return str(scanner_class) in __scanners def get(scanner_class, properties): """ Returns an instance of previously registered scanner @@ -83,7 +83,7 @@ def get(scanner_class, properties): scanner_id = scanner_name + '.' + '-'.join(r) - if not __scanner_cache.has_key(scanner_id): + if scanner_id not in __scanner_cache: __scanner_cache[scanner_id] = scanner_class(r) return __scanner_cache[scanner_id] @@ -141,7 +141,7 @@ class ScannerRegistry: assert isinstance(vtarget, basestring) engine = self.manager_.engine() engine.set_target_variable(target, "HDRSCAN", scanner.pattern()) - if not self.exported_scanners_.has_key(scanner): + if scanner not in self.exported_scanners_: exported_name = "scanner_" + str(self.count_) self.count_ = self.count_ + 1 self.exported_scanners_[scanner] = exported_name diff --git a/src/build/targets.py b/src/build/targets.py index 043d90666..7b3025476 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -202,7 +202,7 @@ class TargetRegistry: """ Helper rules to detect cycles in main target references. """ assert isinstance(main_target_instance, MainTarget) - if self.targets_being_built_.has_key(id(main_target_instance)): + if id(main_target_instance) in self.targets_being_built_: names = [] for t in self.targets_being_built_.values() + [main_target_instance]: names.append (t.full_name()) @@ -213,7 +213,7 @@ class TargetRegistry: def end_building (self, main_target_instance): assert isinstance(main_target_instance, MainTarget) - assert (self.targets_being_built_.has_key (id (main_target_instance))) + assert (id(main_target_instance) in self.targets_being_built_) del self.targets_being_built_ [id (main_target_instance)] def create_typed_target (self, type, project, name, sources, requirements, default_build, usage_requirements): @@ -499,7 +499,7 @@ class ProjectTarget (AbstractTarget): if not self.built_main_targets_: self.build_main_targets() - return self.main_target_.has_key(name) + return name in self.main_target_ def create_main_target (self, name): """ Returns a 'MainTarget' class instance corresponding to the 'name'. @@ -595,7 +595,7 @@ class ProjectTarget (AbstractTarget): for a in self.alternatives_: name = a.name () - if not self.main_target_.has_key (name): + if name not in self.main_target_: t = MainTarget (name, self.project_) self.main_target_ [name] = t @@ -962,7 +962,7 @@ class BasicTarget (AbstractTarget): other = property_set.create(other) key = (build_request, other) - if not self.request_cache.has_key(key): + if key not in self.request_cache: self.request_cache[key] = self.__common_properties2 (build_request, other) return self.request_cache[key].add_raw(free_unconditional) @@ -1179,7 +1179,7 @@ class BasicTarget (AbstractTarget): self.manager().targets().push_target(self) - if not self.generated_.has_key(ps): + if ps not in self.generated_: # Apply free features form the command line. If user # said diff --git a/src/build/type.py b/src/build/type.py index c8d6334c7..6797f19be 100644 --- a/src/build/type.py +++ b/src/build/type.py @@ -71,7 +71,7 @@ def register (type, suffixes = [], base_type = None): if __re_hyphen.search (type): raise BaseException ('type name "%s" contains a hyphen' % type) - if __types.has_key (type): + if type in __types: raise BaseException ('Type "%s" is already registered.' % type) entry = {} @@ -122,7 +122,7 @@ def register_suffixes (suffixes, type): assert is_iterable_typed(suffixes, basestring) assert isinstance(type, basestring) for s in suffixes: - if __suffixes_to_types.has_key (s): + if s in __suffixes_to_types: old_type = __suffixes_to_types [s] if old_type != type: raise BaseException ('Attempting to specify type for suffix "%s"\nOld type: "%s", New type "%s"' % (s, old_type, type)) @@ -133,7 +133,7 @@ def registered (type): """ Returns true iff type has been registered. """ assert isinstance(type, basestring) - return __types.has_key (type) + return type in __types def validate (type): """ Issues an error if 'type' is unknown. @@ -349,7 +349,7 @@ def type(filename): if not suffix: return None suffix = suffix[1:] - if __suffixes_to_types.has_key(suffix): + if suffix in __suffixes_to_types: return __suffixes_to_types[suffix] # NOTE: moved from tools/types/register diff --git a/src/build/virtual_target.py b/src/build/virtual_target.py index ea4b24d82..0ae214a25 100644 --- a/src/build/virtual_target.py +++ b/src/build/virtual_target.py @@ -117,7 +117,7 @@ class VirtualTargetRegistry: signature = "-" + target.name() result = None - if not self.cache_.has_key (signature): + if signature not in self.cache_: self.cache_ [signature] = [] for t in self.cache_ [signature]: @@ -166,7 +166,7 @@ class VirtualTargetRegistry: path = os.path.join(os.getcwd(), file_location, file) path = os.path.normpath(path) - if self.files_.has_key (path): + if path in self.files_: return self.files_ [path] file_type = b2.build.type.type (file) @@ -200,7 +200,7 @@ class VirtualTargetRegistry: def register_actual_name (self, actual_name, virtual_target): assert isinstance(actual_name, basestring) assert isinstance(virtual_target, VirtualTarget) - if self.actual_.has_key (actual_name): + if actual_name in self.actual_: cs1 = self.actual_ [actual_name].creating_subvariant () cs2 = virtual_target.creating_subvariant () cmt1 = cs1.main_target () @@ -334,7 +334,7 @@ class VirtualTarget: name = replace_grist (actual_name, '<' + g + '>') - if not self.made_.has_key (name): + if name not in self.made_: self.made_ [name] = True self.project_.manager ().engine ().add_dependency (name, actual_name) diff --git a/src/tools/common.py b/src/tools/common.py index 3f30baa56..18ea0542b 100644 --- a/src/tools/common.py +++ b/src/tools/common.py @@ -204,7 +204,7 @@ def check_init_parameters(toolset, requirement, *args): ### if $(value)-is-not-empty if value is not None: condition = condition + '-' + value - if __had_unspecified_value.has_key(str_toolset_name): + if str_toolset_name in __had_unspecified_value: raise BaseException("'%s' initialization: parameter '%s' inconsistent\n" \ "no value was specified in earlier initialization\n" \ "an explicit value is specified now" % (toolset, name)) @@ -220,8 +220,8 @@ def check_init_parameters(toolset, requirement, *args): if m: t = m.group(1) - if not __had_value.has_key(str_toolset_name): - if not __declared_subfeature.has_key(str((t, name))): + if str_toolset_name not in __had_value: + if str((t, name)) not in __declared_subfeature: feature.subfeature('toolset', t, name, [], ['propagated']) __declared_subfeature[str((t, name))] = True @@ -231,7 +231,7 @@ def check_init_parameters(toolset, requirement, *args): subcondition += ['' + value ] else: - if __had_value.has_key(str_toolset_name): + if str_toolset_name in __had_value: raise BaseException ("'%s' initialization: parameter '%s' inconsistent\n" \ "an explicit value was specified in an earlier initialization\n" \ "no value is specified now" % (toolset, name)) @@ -247,7 +247,7 @@ def check_init_parameters(toolset, requirement, *args): if requirement: sig += '-' + '-'.join(requirement) - if __all_signatures.has_key(sig): + if sig in __all_signatures: message = "duplicate initialization of '%s' with the following parameters: " % toolset for arg in args: diff --git a/src/tools/doxproc.py b/src/tools/doxproc.py index c41d7fde1..d415133e1 100644 --- a/src/tools/doxproc.py +++ b/src/tools/doxproc.py @@ -50,7 +50,7 @@ def get_args( argv = sys.argv[1:] ): ( option_pairs, other ) = getopt.getopt( argv, '', spec ) map( lambda x: options.__setitem__( x[0], x[1] ), option_pairs ) - if options.has_key( '--help' ): + if '--help' in options: usage() sys.exit(1) @@ -59,7 +59,7 @@ def get_args( argv = sys.argv[1:] ): 'output' : options['--output'], 'id' : options['--id'], 'title' : options['--title'], - 'index' : options.has_key('--enable-index') + 'index' : '--enable-index' in options } def if_attribute(node, attribute, true_value, false_value=None): @@ -151,13 +151,13 @@ class Doxygen2BoostBook: #~ BoostBook references. def _rewriteIDs( self, node ): if node.nodeName in ('link'): - if (self.idmap.has_key(node.getAttribute('linkend'))): + if node.getAttribute('linkend') in self.idmap: #~ A link, and we have someplace to repoint it at. node.setAttribute('linkend',self.idmap[node.getAttribute('linkend')]) else: #~ A link, but we don't have a generated target for it. node.removeAttribute('linkend') - elif hasattr(node,'hasAttribute') and node.hasAttribute('id') and self.idmap.has_key(node.getAttribute('id')): + elif hasattr(node,'hasAttribute') and node.hasAttribute('id') and node.getAttribute('id') in self.idmap: #~ Simple ID, and we have a translation. node.setAttribute('id',self.idmap[node.getAttribute('id')]) #~ Recurse, and iterate, depth-first traversal which turns out to be @@ -333,7 +333,7 @@ class Doxygen2BoostBook: 'detailed' : self._getChildData('detaileddescription',root=node), 'parsed' : False } - if self.symbols.has_key(namespace['name']): + if namespace['name'] in self.symbols: if not self.symbols[namespace['name']]['parsed']: self.symbols[namespace['name']]['parsed'] = True #~ for n in node.childNodes: @@ -385,7 +385,7 @@ class Doxygen2BoostBook: #~ Translate a ..., def _translate_compounddef_includes_( self, node, target=None, **kwargs ): name = node.firstChild.data - if not self.symbols.has_key(name): + if name not in self.symbols: self._setID(node.getAttribute('refid'),name) self.symbols[name] = { 'kind' : 'header', @@ -800,7 +800,7 @@ class Doxygen2BoostBook: namespace = '::'.join(result['namespace']) while ( len(result['namespace']) > 0 and ( - not self.symbols.has_key(namespace) or + namespace not in self.symbols or self.symbols[namespace]['kind'] != 'namespace') ): result['name'] = result['namespace'].pop()+'::'+result['name'] diff --git a/src/tools/msvc.py b/src/tools/msvc.py index 1115af334..c3ac2034b 100644 --- a/src/tools/msvc.py +++ b/src/tools/msvc.py @@ -344,7 +344,7 @@ class SetupAction: def register_setup_action(action_name,setup_function,function=None): global engine - if engine.actions.has_key(action_name): + if action_name in engine.actions: raise "Bjam action %s is already defined" % action_name engine.actions[action_name] = SetupAction(setup_function, function) diff --git a/src/tools/rc.py b/src/tools/rc.py index 5bdebb9be..79a373e8b 100644 --- a/src/tools/rc.py +++ b/src/tools/rc.py @@ -91,7 +91,7 @@ class RCAction: # FIXME: What is the proper way to dispatch actions? def rc_register_action(action_name, function = None): global engine - if engine.actions.has_key(action_name): + if action_name in engine.actions: raise AlreadyDefined("Bjam action %s is already defined" % action_name) engine.actions[action_name] = RCAction(action_name, function) diff --git a/src/util/option.py b/src/util/option.py index 120c2a32c..b23a7257c 100644 --- a/src/util/option.py +++ b/src/util/option.py @@ -29,7 +29,7 @@ def get(name, default_value=None, implied_value=None): m = b2.util.regex.transform(sys.argv, "--(" + re.escape(name) + ")") if m and implied_value: return implied_value - elif options.has_key(name) and options[name] != None: + elif options.get(name) is not None: return options[name] else: return default_value From a5a25364991183ae1b6600f4fb5df12abb77c0c4 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Fri, 7 Oct 2016 23:07:37 -0500 Subject: [PATCH 049/158] Add, and update, documentation build targets. --- src/tools/python.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 23aab658f..8f6a97360 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -1221,7 +1221,7 @@ local rule pyd-pythonpath ( source ) # The flag settings on testing.capture-output do not apply to python.capture # output at the moment. Redo this explicitly. toolset.flags python.capture-output ARGS ; - +toolset.flags python.capture-output INPUT_FILES ; rule capture-output ( target : sources * : properties * ) { From 79543a04dc186d41df8accf13b701142a7f69d9e Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 8 Oct 2016 14:44:54 +0300 Subject: [PATCH 050/158] Fix typo. Closes #12317. --- doc/bjam.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/bjam.qbk b/doc/bjam.qbk index 6b754d13d..27adf472a 100644 --- a/doc/bjam.qbk +++ b/doc/bjam.qbk @@ -364,7 +364,7 @@ The arguments starting with the "=--option=" forms are passed to the =build.jam= [[[literal --gc]] [Enables use of the Boehm Garbage Collector. The build will look for the Boehm-GC source in a "boehm_gc" subdirectory from the =b2= sources.]] [[[literal --duma]] - [Enables use of the DUMA (Detect Uintended Memory Access) debugging memory allocator. The build expects to find the DUMA source files in a "duma" subdirectory from the =b2= sources.]] + [Enables use of the DUMA (Detect Unintended Memory Access) debugging memory allocator. The build expects to find the DUMA source files in a "duma" subdirectory from the =b2= sources.]] [[[literal --toolset-root=/path/]] [Indicates where the toolset used to build is located. This option is passed in by the bootstrap (=build.bat= or =build.sh=) script.]] [[[literal --show-locate-target]] From 99715a535ccd768f4c7dd1bae6671ba754ef4346 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Sat, 8 Oct 2016 14:55:19 +0300 Subject: [PATCH 051/158] Fix typo. Closes #12396 --- index.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.html b/index.html index fd08ee93b..a42dc05f9 100644 --- a/index.html +++ b/index.html @@ -37,8 +37,7 @@

Boost.Build makes it easy to build C++ projects, everywhere.

- You - name you executables and libraries and list their sources. Boost.Build + You name your executables and libraries and list their sources. Boost.Build takes care about compiling your sources with right options, creating static and shared libraries, making executables, and other chores — whether you're using gcc, msvc, or a dozen more supported C++ From 2effafb5df3d26419a0047bf8ee651de101c08a6 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 11 Oct 2016 10:09:44 -0500 Subject: [PATCH 052/158] Better timing information. Add wall clock info to -d+4 output. And use wait4 which gives better resource usage times on Nix. --- src/engine/execunix.c | 21 ++++----------------- src/engine/make1.c | 4 +++- src/engine/timestamp.c | 8 ++++++++ src/engine/timestamp.h | 1 + 4 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/engine/execunix.c b/src/engine/execunix.c index 8ee4d9dbf..21a223d9e 100644 --- a/src/engine/execunix.c +++ b/src/engine/execunix.c @@ -64,8 +64,6 @@ static int get_free_cmdtab_slot(); /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ static clock_t tps; -static int old_time_initialized; -static struct tms old_time; /* We hold stdout & stderr child process information in two element arrays * indexed as follows. @@ -178,13 +176,6 @@ void exec_cmd exit( EXITBAD ); } - /* Initialize old_time only once. */ - if ( !old_time_initialized ) - { - times( &old_time ); - old_time_initialized = 1; - } - /* Start the command */ timestamp_current( &cmdtab[ slot ].start_dt ); @@ -513,6 +504,7 @@ void exec_wait() int status; int rstat; timing_info time_info; + struct rusage cmd_usage; /* We found a terminated child process - our search is done. */ finished = 1; @@ -523,7 +515,7 @@ void exec_wait() close_streams( i, ERR ); /* Reap the child and release resources. */ - while ( ( pid = waitpid( cmdtab[ i ].pid, &status, 0 ) ) == -1 ) + while ( ( pid = wait4( cmdtab[ i ].pid, &status, 0, &cmd_usage ) ) == -1 ) if ( errno != EINTR ) break; if ( pid != cmdtab[ i ].pid ) @@ -539,15 +531,10 @@ void exec_wait() : EXIT_OK; { - struct tms new_time; - times( &new_time ); - time_info.system = (double)( new_time.tms_cstime - - old_time.tms_cstime ) / CLOCKS_PER_SEC; - time_info.user = (double)( new_time.tms_cutime - - old_time.tms_cutime ) / CLOCKS_PER_SEC; + time_info.system = ((double)(cmd_usage.ru_stime.tv_sec)*1000000.0+(double)(cmd_usage.ru_stime.tv_usec))/1000000.0; + time_info.user = ((double)(cmd_usage.ru_utime.tv_sec)*1000000.0+(double)(cmd_usage.ru_utime.tv_usec))/1000000.0; timestamp_copy( &time_info.start, &cmdtab[ i ].start_dt ); timestamp_current( &time_info.end ); - old_time = new_time; } /* Drive the completion. */ diff --git a/src/engine/make1.c b/src/engine/make1.c index 7dbf7c8da..b7fe51728 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -854,7 +854,9 @@ static void make1c_closure { call_timing_rule( t, time ); if ( DEBUG_EXECCMD ) - out_printf( "%f sec system; %f sec user\n", time->system, time->user ); + out_printf( "%f sec system; %f sec user, %f sec clock\n", + time->system, time->user, + timestamp_delta_seconds(&time->start, &time->end) ); /* Assume -p0 is in effect, i.e. cmd_stdout contains merged output. */ call_action_rule( t, status_orig, time, cmd->buf->value, cmd_stdout ); diff --git a/src/engine/timestamp.c b/src/engine/timestamp.c index 17510bcd0..b6fd906ef 100644 --- a/src/engine/timestamp.c +++ b/src/engine/timestamp.c @@ -261,3 +261,11 @@ void timestamp_done() hashdone( bindhash ); } } + +/* + * timestamp_delta_seconds() - seconds from time a to b. + */ +double timestamp_delta_seconds( timestamp const * const a , timestamp const * const b ) +{ + return ((b->secs*1000000.0+b->nsecs)-(a->secs*1000000.0+a->nsecs))/1000000.0; +} diff --git a/src/engine/timestamp.h b/src/engine/timestamp.h index ecedb5f92..e9b41753c 100644 --- a/src/engine/timestamp.h +++ b/src/engine/timestamp.h @@ -42,5 +42,6 @@ void timestamp_from_filetime( timestamp * const, FILETIME const * const ); #endif void timestamp_done(); +double timestamp_delta_seconds( timestamp const * const, timestamp const * const ); #endif From a94e1d0727f8ffeb6ee0e24e51236702fdf4734c Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 11 Oct 2016 23:29:20 -0500 Subject: [PATCH 053/158] Fix testing.time feature and add clock value to it. The old testing.time feature was horribly broken in the face of the current b2 virtual target design. This redoes the feature in a friendly manner to the virtual targets. This also adds the clock (aka wall clock) timing value to __TIMING_RULE__ invocations. --- src/engine/make1.c | 12 +++++++----- src/tools/testing.jam | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/engine/make1.c b/src/engine/make1.c index b7fe51728..8282279cf 100644 --- a/src/engine/make1.c +++ b/src/engine/make1.c @@ -689,7 +689,7 @@ static void call_timing_rule( TARGET * target, timing_info const * const time ) if ( !list_empty( timing_rule ) ) { - /* rule timing-rule ( args * : target : start end user system ) */ + /* rule timing-rule ( args * : target : start end user system clock ) */ /* Prepare the argument list. */ FRAME frame[ 1 ]; @@ -703,12 +703,14 @@ static void call_timing_rule( TARGET * target, timing_info const * const time ) /* target :: the name of the target */ lol_add( frame->args, list_new( object_copy( target->name ) ) ); - /* start end user system :: info about the action command */ - lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_new( + /* start end user system clock :: info about the action command */ + lol_add( frame->args, list_push_back( list_push_back( list_push_back( list_push_back( list_new( outf_time( &time->start ) ), outf_time( &time->end ) ), outf_double( time->user ) ), - outf_double( time->system ) ) ); + outf_double( time->system ) ), + outf_double( timestamp_delta_seconds(&time->start, &time->end) ) ) + ); /* Call the rule. */ evaluate_rule( bindrule( rulename , root_module() ), rulename, frame ); @@ -854,7 +856,7 @@ static void make1c_closure { call_timing_rule( t, time ); if ( DEBUG_EXECCMD ) - out_printf( "%f sec system; %f sec user, %f sec clock\n", + out_printf( "%f sec system; %f sec user; %f sec clock\n", time->system, time->user, timestamp_delta_seconds(&time->start, &time->end) ); diff --git a/src/tools/testing.jam b/src/tools/testing.jam index 7fbb692a1..98d33039d 100644 --- a/src/tools/testing.jam +++ b/src/tools/testing.jam @@ -750,20 +750,37 @@ generators.register-composing testing.time : : TIME ; # there are multiple actions operating on the same target in sequence. One such # example are msvc exe targets first created by a linker action and then updated # with an embedded manifest file by a separate action. -rule record-time ( target : source : start end user system ) +rule record-time ( target : source : start end user system clock ) { local src-string = [$(source:G=:J=",")"] " ; USER_TIME on $(target) += $(src-string)$(user) ; SYSTEM_TIME on $(target) += $(src-string)$(system) ; + CLOCK_TIME on $(target) += $(src-string)$(clock) ; # We need the following variables because attempting to perform such # variable expansion in actions would not work due to quotes getting treated # as regular characters. USER_TIME_SECONDS on $(target) += $(src-string)$(user)" seconds" ; SYSTEM_TIME_SECONDS on $(target) += $(src-string)$(system)" seconds" ; + CLOCK_TIME_SECONDS on $(target) += $(src-string)$(clock)" seconds" ; } +# Support for generating timing information for any main target. To use +# declare a custom make target that uses the testing.time generator rule +# specified here. For example: +# +# make main.cpp : main_cpp.pro : @do-something ; +# make main.time : main.cpp : @testing.time ; +# actions do-something +# { +# sleep 2 && echo "$(<)" > "$(<)" +# } +# +# The above will generate a "main.time", and echo to output, timing +# information for the action of source "main.cpp". + + IMPORT testing : record-time : : testing.record-time ; @@ -774,7 +791,14 @@ IMPORT testing : record-time : : testing.record-time ; rule time ( target : sources + : properties * ) { # Set up rule for recording timing information. - __TIMING_RULE__ on $(sources) = testing.record-time $(target) ; + local action = [ on $(target) return $(.action) ] ; + for local action.source in [ $(action).sources ] + { + # Yes, this uses the private "actual-name" of the target action. + # But it's the only way to get at the real name of the sources + # given the context of header scanners. + __TIMING_RULE__ on [ $(action.source).actual-name ] = testing.record-time $(target) ; + } # Make sure the sources get rebuilt any time we need to retrieve that # information. @@ -786,9 +810,11 @@ actions time { echo user: $(USER_TIME) echo system: $(SYSTEM_TIME) + echo clock: $(CLOCK_TIME) echo user: $(USER_TIME_SECONDS) > "$(<)" echo system: $(SYSTEM_TIME_SECONDS) >> "$(<)" + echo clock: $(CLOCK_TIME_SECONDS) >> "$(<)" } if [ os.name ] = VMS @@ -797,8 +823,10 @@ if [ os.name ] = VMS { WRITE SYS$OUTPUT "user: ", "$(USER_TIME)" WRITE SYS$OUTPUT "system: ", "(SYSTEM_TIME)" + WRITE SYS$OUTPUT "clock: ", "(CLOCK_TIME)" PIPE WRITE SYS$OUTPUT "user: ", "$(USER_TIME_SECONDS)" | TYPE SYS$INPUT /OUT=$(<:W) PIPE WRITE SYS$OUTPUT "system: ", "$(SYSTEM_TIME_SECONDS)" | APPEND /NEW SYS$INPUT $(<:W) + PIPE WRITE SYS$OUTPUT "clock: ", "$(CLOCK_TIME_SECONDS)" | APPEND /NEW SYS$INPUT $(<:W) } } From 895196b73970a73c75dd1ee7306a55c7ee07e810 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Wed, 12 Oct 2016 08:50:23 -0500 Subject: [PATCH 054/158] Fix time data test for added clock field. --- src/tools/testing.jam | 2 +- test/timedata.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/tools/testing.jam b/src/tools/testing.jam index 98d33039d..0f6359d20 100644 --- a/src/tools/testing.jam +++ b/src/tools/testing.jam @@ -771,7 +771,7 @@ rule record-time ( target : source : start end user system clock ) # specified here. For example: # # make main.cpp : main_cpp.pro : @do-something ; -# make main.time : main.cpp : @testing.time ; +# time main.time : main.cpp ; # actions do-something # { # sleep 2 && echo "$(<)" > "$(<)" diff --git a/test/timedata.py b/test/timedata.py index 20a95c2a2..2bfc3ef31 100644 --- a/test/timedata.py +++ b/test/timedata.py @@ -49,14 +49,15 @@ rule time actions time { - echo $(>) user: $(__USER_TIME__) system: $(__SYSTEM_TIME__) + echo $(>) user: $(__USER_TIME__) system: $(__SYSTEM_TIME__) clock: $(__CLOCK_TIME__) echo timed from $(>) >> $(<) } -rule record_time ( target : source : start end user system ) +rule record_time ( target : source : start end user system clock ) { __USER_TIME__ on $(target) = $(user) ; __SYSTEM_TIME__ on $(target) = $(system) ; + __CLOCK_TIME__ on $(target) = $(clock) ; } rule make @@ -80,7 +81,7 @@ make bar : baz ; \.\.\.updating 2 targets\.\.\. make bar time foo -bar +user: [0-9\.]+ +system: +[0-9\.]+ * +bar +user: [0-9\.]+ +system: +[0-9\.]+ +clock: +[0-9\.]+ * \.\.\.updated 2 targets\.\.\.$ """ @@ -125,6 +126,8 @@ time my-time : my-exe ; "user: *[0-9] seconds") t.expect_content_lines("bin/$toolset/debug/my-time.time", "system: *[0-9] seconds") + t.expect_content_lines("bin/$toolset/debug/my-time.time", + "clock: *[0-9] seconds") t.cleanup() From 22f41dfa3260e023737a67ef572cca94723d12b0 Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Thu, 13 Oct 2016 21:16:29 -0400 Subject: [PATCH 055/158] Add support for NumPy extension. --- src/tools/python.jam | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/tools/python.jam b/src/tools/python.jam index 8f6a97360..4d72f7ae0 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -829,6 +829,25 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : debug-message " DLL search path:" \"$(exec-prefix:E=)\" ; } + # + # Discover the presence of NumPy + # + local full-cmd = "import sys; sys.stderr = sys.stdout; import numpy; print(numpy.get_include())" ; + local full-cmd = $(interpreter-cmd)" -c \"$(full-cmd)\"" ; + local result = [ SHELL $(full-cmd) : strip-eol : exit-status ] ; + if $(result[2]) = 0 + { + .numpy = true ; + numpy-include = $(result[1]) ; + } + else + { + .numpy = false ; + debug-message "NumPy not configured. Reason:" ; + debug-message " $(full-cmd) aborted with " ; + debug-message " $(result[1])" ; + } + # # End autoconfiguration sequence. # @@ -1012,6 +1031,11 @@ rule configured ( ) return $(.configured) ; } +rule numpy ( ) +{ + return $(.numpy) ; +} + type.register PYTHON_EXTENSION : : SHARED_LIB ; @@ -1268,5 +1292,20 @@ rule bpl-test ( name : sources * : requirements * ) : $(requirements) : $(name) ] ; } +# The same as bpl-test but additionally require (and link to) boost_numpy. +# Masked whenever NumPy is not enabled. +rule numpy-test ( name : sources * : requirements * ) +{ + # yuk ! + if $(.numpy) = false + { + requirements += no ; + } + sources ?= $(name).py $(name).cpp ; + return [ testing.make-test run-pyd + : $(sources) /boost/python//boost_numpy /boost/python//boost_python + : $(requirements) : $(name) ] ; +} IMPORT $(__name__) : bpl-test : : bpl-test ; +IMPORT $(__name__) : numpy-test : : numpy-test ; From 4b099e76b06c771958366281c7e343b68bb63646 Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Thu, 20 Oct 2016 17:24:36 -0400 Subject: [PATCH 056/158] Add include path for NumPy extension. --- src/tools/python.jam | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 4d72f7ae0..d2d47b866 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -838,11 +838,10 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : if $(result[2]) = 0 { .numpy = true ; - numpy-include = $(result[1]) ; + .numpy-include = $(result[1]) ; } else { - .numpy = false ; debug-message "NumPy not configured. Reason:" ; debug-message " $(full-cmd) aborted with " ; debug-message " $(result[1])" ; @@ -1036,6 +1035,11 @@ rule numpy ( ) return $(.numpy) ; } +rule numpy-include ( ) +{ + return $(.numpy-include) ; +} + type.register PYTHON_EXTENSION : : SHARED_LIB ; @@ -1296,6 +1300,7 @@ rule bpl-test ( name : sources * : requirements * ) # Masked whenever NumPy is not enabled. rule numpy-test ( name : sources * : requirements * ) { + numpy-include = [ python.numpy-include ] ; # yuk ! if $(.numpy) = false { @@ -1304,7 +1309,8 @@ rule numpy-test ( name : sources * : requirements * ) sources ?= $(name).py $(name).cpp ; return [ testing.make-test run-pyd : $(sources) /boost/python//boost_numpy /boost/python//boost_python - : $(requirements) : $(name) ] ; + : $(requirements) $(numpy-include) + : $(name) ] ; } IMPORT $(__name__) : bpl-test : : bpl-test ; From 8e17e84d41f1377b387201b0290dd552eaa58e28 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 24 Oct 2016 18:10:19 -0500 Subject: [PATCH 057/158] Some examples to: illustrate use of timing info use, and more complex testing options. --- example/complex-testing/compile-fail.cpp | 17 +++++++++++++++++ example/complex-testing/fail.cpp | 17 +++++++++++++++++ example/complex-testing/jamroot.jam | 10 ++++++++++ example/complex-testing/success.cpp | 17 +++++++++++++++++ example/time/jamroot.jam | 13 +++++++++++++ example/time/main_cpp.pro | 1 + 6 files changed, 75 insertions(+) create mode 100644 example/complex-testing/compile-fail.cpp create mode 100644 example/complex-testing/fail.cpp create mode 100644 example/complex-testing/jamroot.jam create mode 100644 example/complex-testing/success.cpp create mode 100644 example/time/jamroot.jam create mode 100644 example/time/main_cpp.pro diff --git a/example/complex-testing/compile-fail.cpp b/example/complex-testing/compile-fail.cpp new file mode 100644 index 000000000..a219fa5c6 --- /dev/null +++ b/example/complex-testing/compile-fail.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2014 Rene Rivera +// +// 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) +// +// http://www.boost.org +// + +#include +#include + +int main() +{ + std::cout << "Bye!\n"; + return EXIT_FAILURE +} diff --git a/example/complex-testing/fail.cpp b/example/complex-testing/fail.cpp new file mode 100644 index 000000000..965661188 --- /dev/null +++ b/example/complex-testing/fail.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2014 Rene Rivera +// +// 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) +// +// http://www.boost.org +// + +#include +#include + +int main() +{ + std::cout << "Bye!\n"; + return EXIT_FAILURE; +} diff --git a/example/complex-testing/jamroot.jam b/example/complex-testing/jamroot.jam new file mode 100644 index 000000000..be4ebddd5 --- /dev/null +++ b/example/complex-testing/jamroot.jam @@ -0,0 +1,10 @@ +# Copyright 2016 Rene Rivera +# 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) + +using testing ; + +exe success : success.cpp ; + +run success : arg1 arg2 : : : success-a : ; +run success : arg3 arg4 : : : success-b : ; diff --git a/example/complex-testing/success.cpp b/example/complex-testing/success.cpp new file mode 100644 index 000000000..bf5588062 --- /dev/null +++ b/example/complex-testing/success.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2014 Rene Rivera +// +// 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) +// +// http://www.boost.org +// + +#include +#include + +int main() +{ + std::cout << "Hi!\n"; + return EXIT_SUCCESS; +} diff --git a/example/time/jamroot.jam b/example/time/jamroot.jam new file mode 100644 index 000000000..9419b4437 --- /dev/null +++ b/example/time/jamroot.jam @@ -0,0 +1,13 @@ +import feature ; +import toolset ; +import os ; +import testing ; + +path-constant HERE : . ; +make main.cpp : main_cpp.pro : @do-something ; +time main.time : main.cpp ; + +actions do-something +{ + sleep 2 && echo "$(<)" > "$(<)" +} diff --git a/example/time/main_cpp.pro b/example/time/main_cpp.pro new file mode 100644 index 000000000..237c8ce18 --- /dev/null +++ b/example/time/main_cpp.pro @@ -0,0 +1 @@ +int main() {} From 581030e2efdd643e3d3213649175064251114be1 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 24 Oct 2016 23:55:54 -0500 Subject: [PATCH 058/158] Add example of running a post test program to that accepts a path to a dependent test. --- example/complex-testing/jamroot.jam | 9 +++++++-- example/complex-testing/post.cpp | 17 +++++++++++++++++ example/complex-testing/success.cpp | 2 +- 3 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 example/complex-testing/post.cpp diff --git a/example/complex-testing/jamroot.jam b/example/complex-testing/jamroot.jam index be4ebddd5..a5942a239 100644 --- a/example/complex-testing/jamroot.jam +++ b/example/complex-testing/jamroot.jam @@ -3,8 +3,13 @@ # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) using testing ; +import property-set ; +import path ; exe success : success.cpp ; -run success : arg1 arg2 : : : success-a : ; -run success : arg3 arg4 : : : success-b : ; +run success : arg1 arg2 : : : success-a ; +run success : arg3 arg4 : : : success-b ; + +run post.cpp : : success-a : : post-a ; +run post.cpp : : success-b : : post-b ; diff --git a/example/complex-testing/post.cpp b/example/complex-testing/post.cpp new file mode 100644 index 000000000..6282e8f24 --- /dev/null +++ b/example/complex-testing/post.cpp @@ -0,0 +1,17 @@ +// Copyright (c) 2014 Rene Rivera +// +// 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) +// +// http://www.boost.org +// + +#include +#include + +int main(int argc, char *argv[]) +{ + std::cout << argv[1] << "\n"; + return EXIT_SUCCESS; +} diff --git a/example/complex-testing/success.cpp b/example/complex-testing/success.cpp index bf5588062..a7e2b6ca0 100644 --- a/example/complex-testing/success.cpp +++ b/example/complex-testing/success.cpp @@ -10,7 +10,7 @@ #include #include -int main() +int main(int argc, char *argv[]) { std::cout << "Hi!\n"; return EXIT_SUCCESS; From 8c861588d4f05de587d1455006ac0b55e0dffa31 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 25 Oct 2016 11:53:23 +0300 Subject: [PATCH 059/158] Add example of configure check. --- example/try_compile/Jamroot.jam | 29 +++++++++++++++++++++++++++++ example/try_compile/feature.cpp | 5 +++++ example/try_compile/main.cpp | 8 ++++++++ 3 files changed, 42 insertions(+) create mode 100644 example/try_compile/Jamroot.jam create mode 100644 example/try_compile/feature.cpp create mode 100644 example/try_compile/main.cpp diff --git a/example/try_compile/Jamroot.jam b/example/try_compile/Jamroot.jam new file mode 100644 index 000000000..70e35df1d --- /dev/null +++ b/example/try_compile/Jamroot.jam @@ -0,0 +1,29 @@ + +# This example shows performing system feature checks in Boost.Build, +# e.g. to check for some system function or compiler feature. + +# First, declare a metatarget that we'll try to build. +obj feature : feature.cpp ; +# Make it explicit so that it's only build if used by a configure check +explicit feature ; + +# Declare a target that uses a feature. +exe main + : main.cpp + # The check-target-builds invocation in requirements section will + # - build the specified metataget + # - if it builds OK, add the properties in the second parameter + # - otherwise, add the properties in the third parameter + : [ check-target-builds feature : FEATURE=1 : FEATURE=0 ] + ; + +# To test this: +# +# 1. Build with "b2". You should see a "feature builds: yes" message, and running +# the produced executable will show that feature is present. +# 2. Modify feature.cpp to contain a compile error, rebuild with +# "b2 -a --reconfigure". You should see a "feature builds: no" message, and running +# the produced executable should show that the feature is not present. +# +# The output from check checks is not shown on the console, instead it is +# redirected to the bin/config.log file diff --git a/example/try_compile/feature.cpp b/example/try_compile/feature.cpp new file mode 100644 index 000000000..d59f90806 --- /dev/null +++ b/example/try_compile/feature.cpp @@ -0,0 +1,5 @@ + +int foo() +{ + return 0; +} \ No newline at end of file diff --git a/example/try_compile/main.cpp b/example/try_compile/main.cpp new file mode 100644 index 000000000..ce5889e0d --- /dev/null +++ b/example/try_compile/main.cpp @@ -0,0 +1,8 @@ + +#include +using namespace std; + +int main() +{ + std::cout << "Feature: " << FEATURE << "\n"; +} \ No newline at end of file From 30f772c1309d56e7c9ad362c28b11aa48978a609 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Tue, 25 Oct 2016 12:29:02 +0300 Subject: [PATCH 060/158] Rename 'feature' to 'foo'. --- example/try_compile/Jamroot.jam | 22 ++++++++++---------- example/try_compile/{feature.cpp => foo.cpp} | 1 + example/try_compile/main.cpp | 2 +- 3 files changed, 13 insertions(+), 12 deletions(-) rename example/try_compile/{feature.cpp => foo.cpp} (96%) diff --git a/example/try_compile/Jamroot.jam b/example/try_compile/Jamroot.jam index 70e35df1d..41c705162 100644 --- a/example/try_compile/Jamroot.jam +++ b/example/try_compile/Jamroot.jam @@ -1,29 +1,29 @@ -# This example shows performing system feature checks in Boost.Build, -# e.g. to check for some system function or compiler feature. +# This example shows performing configure checks in Boost.Build, +# e.g. to check for some system function or compiler quirk. # First, declare a metatarget that we'll try to build. -obj feature : feature.cpp ; +obj foo : foo.cpp ; # Make it explicit so that it's only build if used by a configure check -explicit feature ; +explicit foo ; -# Declare a target that uses a feature. +# Declare a target that depends on configure check result. exe main : main.cpp # The check-target-builds invocation in requirements section will # - build the specified metataget # - if it builds OK, add the properties in the second parameter # - otherwise, add the properties in the third parameter - : [ check-target-builds feature : FEATURE=1 : FEATURE=0 ] + : [ check-target-builds foo : FOO=1 : FOO=0 ] ; # To test this: # -# 1. Build with "b2". You should see a "feature builds: yes" message, and running -# the produced executable will show that feature is present. -# 2. Modify feature.cpp to contain a compile error, rebuild with -# "b2 -a --reconfigure". You should see a "feature builds: no" message, and running -# the produced executable should show that the feature is not present. +# 1. Build with "b2". You should see a "foo builds: yes" message, and running +# the produced executable will show that FOO is set to 1. +# 2. Modify foo.cpp to contain a compile error, rebuild with +# "b2 -a --reconfigure". You should see a "foo builds: no" message, and running +# the produced executable should show that the FOO is set to 0. # # The output from check checks is not shown on the console, instead it is # redirected to the bin/config.log file diff --git a/example/try_compile/feature.cpp b/example/try_compile/foo.cpp similarity index 96% rename from example/try_compile/feature.cpp rename to example/try_compile/foo.cpp index d59f90806..c9107f937 100644 --- a/example/try_compile/feature.cpp +++ b/example/try_compile/foo.cpp @@ -1,4 +1,5 @@ + int foo() { return 0; diff --git a/example/try_compile/main.cpp b/example/try_compile/main.cpp index ce5889e0d..12f64995b 100644 --- a/example/try_compile/main.cpp +++ b/example/try_compile/main.cpp @@ -4,5 +4,5 @@ using namespace std; int main() { - std::cout << "Feature: " << FEATURE << "\n"; + std::cout << "Foo: " << FOO << "\n"; } \ No newline at end of file From 3f6deabb571a7ec8abf4b02d0f91fd3e3651f0dd Mon Sep 17 00:00:00 2001 From: neutric Date: Wed, 26 Oct 2016 07:42:09 +0200 Subject: [PATCH 061/158] Fix typo --- doc/src/faq.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/faq.xml b/doc/src/faq.xml index 9a7f9c458..3b6894b77 100644 --- a/doc/src/faq.xml +++ b/doc/src/faq.xml @@ -414,7 +414,7 @@ exe hello : hello.cpp /site-config//zlib ; external libraries it becomes problematic to remember which libraries are header only, and which ones you have to link to. However, with Boost.Build a header-only library can be declared as Boost.Build target and all - dependents can use such library without having to remeber whether it is a + dependents can use such library without having to remember whether it is a header-only library or not. From 15956504d0e1cf1d22339e9ec011161de76eb576 Mon Sep 17 00:00:00 2001 From: DD Date: Tue, 25 Oct 2016 11:58:31 +0200 Subject: [PATCH 062/158] Minor doc changes Didn't change line 28, but "check checks" reads bizarrely IMHO. (warning: not native speaker here) --- example/try_compile/Jamroot.jam | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/example/try_compile/Jamroot.jam b/example/try_compile/Jamroot.jam index 41c705162..2255e6f5b 100644 --- a/example/try_compile/Jamroot.jam +++ b/example/try_compile/Jamroot.jam @@ -4,14 +4,14 @@ # First, declare a metatarget that we'll try to build. obj foo : foo.cpp ; -# Make it explicit so that it's only build if used by a configure check +# Make it explicit so that it's only built if used by a configure check explicit foo ; # Declare a target that depends on configure check result. exe main : main.cpp # The check-target-builds invocation in requirements section will - # - build the specified metataget + # - build the specified metatarget # - if it builds OK, add the properties in the second parameter # - otherwise, add the properties in the third parameter : [ check-target-builds foo : FOO=1 : FOO=0 ] @@ -23,7 +23,7 @@ exe main # the produced executable will show that FOO is set to 1. # 2. Modify foo.cpp to contain a compile error, rebuild with # "b2 -a --reconfigure". You should see a "foo builds: no" message, and running -# the produced executable should show that the FOO is set to 0. +# the produced executable should show that FOO is now set to 0. # # The output from check checks is not shown on the console, instead it is # redirected to the bin/config.log file From 2d664c40aeca9d8d46559ddd9235ae84e83af928 Mon Sep 17 00:00:00 2001 From: Vladimir Prus Date: Wed, 26 Oct 2016 11:55:53 +0300 Subject: [PATCH 063/158] Fix typo. --- example/try_compile/Jamroot.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/try_compile/Jamroot.jam b/example/try_compile/Jamroot.jam index 2255e6f5b..893a03fdc 100644 --- a/example/try_compile/Jamroot.jam +++ b/example/try_compile/Jamroot.jam @@ -25,5 +25,5 @@ exe main # "b2 -a --reconfigure". You should see a "foo builds: no" message, and running # the produced executable should show that FOO is now set to 0. # -# The output from check checks is not shown on the console, instead it is +# The output from the check is not shown on the console, instead it is # redirected to the bin/config.log file From 594ef7b1dadf89a1d466d415cd86a709cea41f57 Mon Sep 17 00:00:00 2001 From: Sergiu Deitsch Date: Sun, 23 Oct 2016 19:35:06 +0200 Subject: [PATCH 064/158] added Intel C++ compiler 17.0 support --- src/tools/intel-win.jam | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tools/intel-win.jam b/src/tools/intel-win.jam index d50116796..21392e7bf 100644 --- a/src/tools/intel-win.jam +++ b/src/tools/intel-win.jam @@ -475,6 +475,7 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] .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-16.0-supported-vcs = "14.0 12.0 11.0 10.0 9.0" ; +.iclvars-17.0-supported-vcs = "14.0 12.0 11.0 10.0" ; .iclvars-version-alias-vc14 = vs2015 ; .iclvars-version-alias-vc12 = vs2013 ; .iclvars-version-alias-vc11 = vs2012 ; From ee9a70268b96367e0bf426f6635e829bc280cfbf Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Wed, 26 Oct 2016 16:43:55 -0500 Subject: [PATCH 065/158] Fix missing numpy tests. We ensure that we don't have tests with subdirectories in the name to avoid a log processing defficiency (and not easily resolved) of not supporting subdirs for individual tests. --- src/tools/python.jam | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index d2d47b866..8e1adf976 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -1307,10 +1307,11 @@ rule numpy-test ( name : sources * : requirements * ) requirements += no ; } sources ?= $(name).py $(name).cpp ; + name = [ regex.replace $(name) "[/]" "~" ] ; return [ testing.make-test run-pyd : $(sources) /boost/python//boost_numpy /boost/python//boost_python : $(requirements) $(numpy-include) - : $(name) ] ; + : $(name) ] ; } IMPORT $(__name__) : bpl-test : : bpl-test ; From a1979fe91c9fa01a622b9dc3e7b40edcfae5669c Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Wed, 26 Oct 2016 20:32:58 -0400 Subject: [PATCH 066/158] Improve logging. --- src/tools/python.jam | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 8e1adf976..ae1675596 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -832,17 +832,20 @@ local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? : # # Discover the presence of NumPy # + debug-message "Checking for NumPy..." ; local full-cmd = "import sys; sys.stderr = sys.stdout; import numpy; print(numpy.get_include())" ; local full-cmd = $(interpreter-cmd)" -c \"$(full-cmd)\"" ; + debug-message "running command '$(full-cmd)'" ; local result = [ SHELL $(full-cmd) : strip-eol : exit-status ] ; if $(result[2]) = 0 { .numpy = true ; .numpy-include = $(result[1]) ; + debug-message "NumPy enabled" ; } else { - debug-message "NumPy not configured. Reason:" ; + debug-message "NumPy disabled. Reason:" ; debug-message " $(full-cmd) aborted with " ; debug-message " $(result[1])" ; } From 3fc825730311bf00608c3d53ad37a5fd179c58d9 Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Thu, 27 Oct 2016 08:38:50 -0400 Subject: [PATCH 067/158] Remove obsolete code. --- src/tools/python.jam | 33 ++------------------------------- 1 file changed, 2 insertions(+), 31 deletions(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index ae1675596..1d5c306f3 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -1098,19 +1098,6 @@ rule python-extension ( name : sources * : requirements * : default-build * : IMPORT python : python-extension : : python-extension ; -rule py2to3 -{ - common.copy $(<) : $(>) ; - 2to3 $(<) ; -} - -actions 2to3 -{ - 2to3 -wn --no-diffs "$(<)" - 2to3 -dwn --no-diffs "$(<)" -} - - # Support for testing. type.register PY : py ; type.register RUN_PYD_OUTPUT ; @@ -1133,22 +1120,6 @@ class python-test-generator : generator local python ; local other-pythons ; - # Make new target that converting Python source by 2to3 when running with Python 3. - local rule make-2to3-source ( source ) - { - if $(pyversion) >= 3.0 - { - local a = [ new action $(source) : python.py2to3 : $(property-set) ] ; - local t = [ utility.basename [ $(s).name ] ] ; - local p = [ new file-target $(t) : PY : $(project) : $(a) ] ; - return $(p) ; - } - else - { - return $(source) ; - } - } - for local s in $(sources) { if [ $(s).type ] = PY @@ -1156,13 +1127,13 @@ class python-test-generator : generator if ! $(python) { # First Python source ends up on command line. - python = [ make-2to3-source $(s) ] ; + python = $(s) ; } else { # Other Python sources become dependencies. - other-pythons += [ make-2to3-source $(s) ] ; + other-pythons += $(s) ; } } } From eee3ebdb2cf3e025294d387316b2601feb2a8ce6 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 15:58:38 -0500 Subject: [PATCH 068/158] Allow for actions to be empty. This allows for an updating rule to not run an action itself, rather it allows for that rule to delegate to other updating actions. --- src/build/engine.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/build/engine.py b/src/build/engine.py index 9d6b99c50..c409276b6 100644 --- a/src/build/engine.py +++ b/src/build/engine.py @@ -16,21 +16,23 @@ from b2.util import set_jam_action, is_iterable class BjamAction(object): """Class representing bjam action defined from Python.""" - def __init__(self, action_name, function): + def __init__(self, action_name, function, has_command=False): assert isinstance(action_name, basestring) assert callable(function) or function is None self.action_name = action_name self.function = function + self.has_command = has_command def __call__(self, targets, sources, property_set_): assert is_iterable(targets) assert is_iterable(sources) assert isinstance(property_set_, property_set.PropertySet) - # Bjam actions defined from Python have only the command - # to execute, and no associated jam procedural code. So - # passing 'property_set' to it is not necessary. - bjam_interface.call("set-update-action", self.action_name, - targets, sources, []) + if self.has_command: + # Bjam actions defined from Python have only the command + # to execute, and no associated jam procedural code. So + # passing 'property_set' to it is not necessary. + bjam_interface.call("set-update-action", self.action_name, + targets, sources, []) if self.function: self.function(targets, sources, property_set_) @@ -158,7 +160,7 @@ class Engine: self.do_set_update_action (action_name, targets, sources, properties) - def register_action (self, action_name, command, bound_list = [], flags = [], + def register_action (self, action_name, command='', bound_list = [], flags = [], function = None): """Creates a new build engine action. @@ -190,7 +192,8 @@ class Engine: if command: bjam_interface.define_action(action_name, command, bound_list, bjam_flags) - self.actions[action_name] = BjamAction(action_name, function) + self.actions[action_name] = BjamAction( + action_name, function, has_command=bool(command)) def register_bjam_action (self, action_name, function=None): """Informs self that 'action_name' is declared in bjam. From 9bee7e8d2074b0df2c56ed1529d856e01798ca24 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:08:09 -0500 Subject: [PATCH 069/158] Port errors.nearest_user_location(). --- src/build/errors.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/build/errors.py b/src/build/errors.py index 69d8a37d3..dd517395f 100644 --- a/src/build/errors.py +++ b/src/build/errors.py @@ -123,5 +123,13 @@ class Errors: stack=traceback.extract_stack()) - - +def nearest_user_location(): + """ + Returns: + tuple: the filename and line number of the nearest user location + """ + bt = bjam.backtrace() + if not bt: + return None + last = bt[-1] + return last[0], last[1] From fbb42355eb87b678325455354d9953473b16529a Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:53:56 -0500 Subject: [PATCH 070/158] Clean up exceptions.py Run pep8. BaseException is a builtin class. This renames BaseException to BaseBoostBuildException. All other custom exceptions that deal with the Boost.Build framework should inherit from this class. This makes "catching" all Boost.Build specific exceptions much easier. --- src/exceptions.py | 65 +++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/exceptions.py b/src/exceptions.py index 5750abfe3..70d4d9831 100644 --- a/src/exceptions.py +++ b/src/exceptions.py @@ -2,43 +2,54 @@ # Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -# TODO: add more exception types? -class BaseException (Exception): - def __init__ (self, message = ''): Exception.__init__ (self, message) +class BaseBoostBuildException(Exception): + """A base Exception class for all other Boost.Build exceptions to inherit from.""" -class UserError (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) -class FeatureConflict (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) +class UserError(BaseBoostBuildException): + pass -class InvalidSource (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) -class InvalidFeature (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) +class FeatureConflict(BaseBoostBuildException): + pass -class InvalidProperty (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) -class InvalidValue (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) +class InvalidSource(BaseBoostBuildException): + pass -class InvalidAttribute (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) -class AlreadyDefined (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) +class InvalidFeature(BaseBoostBuildException): + pass -class IllegalOperation (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) -class Recursion (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) +class InvalidProperty(BaseBoostBuildException): + pass -class NoBestMatchingAlternative (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) -class NoAction (BaseException): - def __init__ (self, message = ''): BaseException.__init__ (self, message) +class InvalidValue(BaseBoostBuildException): + pass + + +class InvalidAttribute(BaseBoostBuildException): + pass + + +class AlreadyDefined(BaseBoostBuildException): + pass + + +class IllegalOperation(BaseBoostBuildException): + pass + + +class Recursion(BaseBoostBuildException): + pass + + +class NoBestMatchingAlternative(BaseBoostBuildException): + pass + + +class NoAction(BaseBoostBuildException): + pass From c07100423ea07b25f209414052bc2edfafa58a81 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:13:11 -0500 Subject: [PATCH 071/158] Provide help message when generator is handed empty list of sources. In Jam, the language itself would raise an error when the sources list was empty. In the Python port, it was assumed that sources was never empty and would run into an IndexError when the empty sources list tried to access the first element. This change checks sources first and provides an error message in the event that sources is empty. An empty source list can be passed in when the best alternative evalutates to an empty list of sources. This target is then added to a typed target, e.g. lib, which requires sources. --- src/build/generators.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/build/generators.py b/src/build/generators.py index c2e21510c..a87a0d33a 100644 --- a/src/build/generators.py +++ b/src/build/generators.py @@ -53,6 +53,7 @@ import os.path from virtual_target import Subvariant from . import virtual_target, type, property_set, property +from b2.exceptions import BaseBoostBuildException from b2.util.logger import * from b2.util.utility import * from b2.util import set as set_, is_iterable_typed, is_iterable @@ -158,6 +159,13 @@ def dout(message): if debug(): print __indent + message + +class InvalidTargetSource(BaseBoostBuildException): + """ + Should be raised when a target contains a source that is invalid. + """ + + class Generator: """ Creates a generator. manager: the build manager. @@ -336,11 +344,16 @@ class Generator: assert isinstance(name, basestring) or name is None assert isinstance(prop_set, property_set.PropertySet) assert is_iterable_typed(sources, virtual_target.VirtualTarget) - if project.manager ().logger ().on (): project.manager ().logger ().log (__name__, " generator '%s'" % self.id_) project.manager ().logger ().log (__name__, " composing: '%s'" % self.composing_) + if not sources: + s = 'An empty source list was passed in to the "{}" generator'.format(self.id_) + if name: + s += ' for target "{}"'.format(name) + raise InvalidTargetSource(s) + if not self.composing_ and len (sources) > 1 and len (self.source_types_) > 1: raise BaseException ("Unsupported source/source_type combination") From 8039dc0fd820f17dc6387d9d5b92bfa77cc657c5 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:19:07 -0500 Subject: [PATCH 072/158] Update generators to match Jam. The generator methods referred to `bypassed` and `consumed`. `bypassed` is no longer present in Jam and so any reference to that variable has been removed. --- src/build/generators.py | 81 +++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 51 deletions(-) diff --git a/src/build/generators.py b/src/build/generators.py index a87a0d33a..d12be7e33 100644 --- a/src/build/generators.py +++ b/src/build/generators.py @@ -381,24 +381,22 @@ class Generator: assert isinstance(prop_set, property_set.PropertySet) assert is_iterable_typed(sources, virtual_target.VirtualTarget) # consumed: Targets that this generator will consume directly. - # bypassed: Targets that can't be consumed and will be returned as-is. if self.composing_: - (consumed, bypassed) = self.convert_multiple_sources_to_consumable_types (project, prop_set, sources) + consumed = self.convert_multiple_sources_to_consumable_types (project, prop_set, sources) else: - (consumed, bypassed) = self.convert_to_consumable_types (project, name, prop_set, sources) + consumed = self.convert_to_consumable_types (project, name, prop_set, sources) result = [] if consumed: result = self.construct_result (consumed, project, name, prop_set) - result.extend (bypassed) if result: if project.manager ().logger ().on (): project.manager ().logger ().log (__name__, " SUCCESS: ", result) else: - project.manager ().logger ().log (__name__, " FAILURE") + project.manager ().logger ().log (__name__, " FAILURE") return result @@ -425,12 +423,9 @@ class Generator: if len (self.source_types_) < 2 and not self.composing_: for r in consumed: - result.extend (self.generated_targets ([r], prop_set, project, name)) - - else: - - if consumed: - result.extend (self.generated_targets (consumed, prop_set, project, name)) + result.extend(self.generated_targets([r], prop_set, project, name)) + elif consumed: + result.extend(self.generated_targets(consumed, prop_set, project, name)) return result @@ -540,7 +535,6 @@ class Generator: Returns a pair: consumed: all targets that can be consumed. - bypassed: all targets that cannot be consumed. """ if __debug__: from .targets import ProjectTarget @@ -550,7 +544,6 @@ class Generator: assert is_iterable_typed(sources, virtual_target.VirtualTarget) assert isinstance(only_one, bool) consumed = [] - bypassed = [] missing_types = [] if len (sources) > 1: @@ -587,59 +580,45 @@ class Generator: if t.type() in missing_types: consumed.append(t) - else: - bypassed.append(t) - consumed = unique(consumed) - bypassed = unique(bypassed) - # remove elements of 'bypassed' that are in 'consumed' - - # Suppose the target type of current generator, X is produced from - # X_1 and X_2, which are produced from Y by one generator. - # When creating X_1 from Y, X_2 will be added to 'bypassed' - # Likewise, when creating X_2 from Y, X_1 will be added to 'bypassed' - # But they are also in 'consumed'. We have to remove them from - # bypassed, so that generators up the call stack don't try to convert - # them. - - # In this particular case, X_1 instance in 'consumed' and X_1 instance - # in 'bypassed' will be the same: because they have the same source and - # action name, and 'virtual-target.register' won't allow two different - # instances. Therefore, it's OK to use 'set.difference'. - - bypassed = set.difference(bypassed, consumed) - - return (consumed, bypassed) + return consumed def convert_multiple_sources_to_consumable_types (self, project, prop_set, sources): """ Converts several files to consumable types. """ - consumed = [] - bypassed = [] if __debug__: from .targets import ProjectTarget assert isinstance(project, ProjectTarget) assert isinstance(prop_set, property_set.PropertySet) assert is_iterable_typed(sources, virtual_target.VirtualTarget) + if not self.source_types_: + return list(sources) - assert isinstance(project, ProjectTarget) - assert isinstance(prop_set, property_set.PropertySet) - assert is_iterable_typed(sources, virtual_target.VirtualTarget) - # We process each source one-by-one, trying to convert it to - # a usable type. - for s in sources: - # TODO: need to check for failure on each source. - (c, b) = self.convert_to_consumable_types (project, None, prop_set, [s], True) - if not c: - project.manager ().logger ().log (__name__, " failed to convert ", s) + acceptable_types = set() + for t in self.source_types_: + acceptable_types.update(type.all_derived(t)) + + result = [] + for source in sources: + if source.type() not in acceptable_types: + transformed = construct_types( + project, None,self.source_types_, prop_set, [source]) + # construct_types returns [prop_set, [targets]] + for t in transformed[1]: + if t.type() in self.source_types_: + result.append(t) + if not transformed: + project.manager().logger().log(__name__, " failed to convert ", source) + else: + result.append(source) + + result = sequence.unique(result, stable=True) + return result - consumed.extend (c) - bypassed.extend (b) - return (consumed, bypassed) def consume_directly (self, source): assert isinstance(source, virtual_target.VirtualTarget) @@ -655,7 +634,7 @@ class Generator: for st in source_types: # The 'source' if of right type already) if real_source_type == st or type.is_derived (real_source_type, st): - consumed.append (source) + consumed = [source] else: missing_types.append (st) From 7737c858ace42b33b6aef740360a546f2ddae7f8 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:25:56 -0500 Subject: [PATCH 073/158] Remove unnecessary file. --- src/build/project.ann.py | 996 --------------------------------------- 1 file changed, 996 deletions(-) delete mode 100644 src/build/project.ann.py diff --git a/src/build/project.ann.py b/src/build/project.ann.py deleted file mode 100644 index 349f54955..000000000 --- a/src/build/project.ann.py +++ /dev/null @@ -1,996 +0,0 @@ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 1) # Status: being ported by Vladimir Prus -ddc17f01 (vladimir_prus 2007-10-26 14:57:56 +0000 2) # Base revision: 40480 -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 3) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 4) # Copyright 2002, 2003 Dave Abrahams -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 5) # Copyright 2002, 2005, 2006 Rene Rivera -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 6) # Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 7) # Distributed under the Boost Software License, Version 1.0. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 8) # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 9) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 10) # Implements project representation and loading. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 11) # Each project is represented by -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 12) # - a module where all the Jamfile content live. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 13) # - an instance of 'project-attributes' class. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 14) # (given module name, can be obtained by 'attributes' rule) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 15) # - an instance of 'project-target' class (from targets.jam) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 16) # (given a module name, can be obtained by 'target' rule) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 17) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 18) # Typically, projects are created as result of loading Jamfile, which is -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 19) # do by rules 'load' and 'initialize', below. First, module for Jamfile -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 20) # is loaded and new project-attributes instance is created. Some rules -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 21) # necessary for project are added to the module (see 'project-rules' module) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 22) # at the bottom of this file. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 23) # Default project attributes are set (inheriting attributes of parent project, if -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 24) # it exists). After that, Jamfile is read. It can declare its own attributes, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 25) # via 'project' rule, which will be combined with already set attributes. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 26) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 27) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 28) # The 'project' rule can also declare project id, which will be associated with -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 29) # the project module. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 30) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 31) # There can also be 'standalone' projects. They are created by calling 'initialize' -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 32) # on arbitrary module, and not specifying location. After the call, the module can -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 33) # call 'project' rule, declare main target and behave as regular projects. However, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 34) # since it's not associated with any location, it's better declare only prebuilt -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 35) # targets. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 36) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 37) # The list of all loaded Jamfile is stored in variable .project-locations. It's possible -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 38) # to obtain module name for a location using 'module-name' rule. The standalone projects -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 39) # are not recorded, the only way to use them is by project id. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 40) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 41) import b2.util.path -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 42) from b2.build import property_set, property -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 43) from b2.build.errors import ExceptionWithUserContext -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 44) import b2.build.targets -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 45) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 46) import bjam -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 47) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 48) import re -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 49) import sys -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 50) import os -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 51) import string -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 52) import imp -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 53) import traceback -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 54) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 55) class ProjectRegistry: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 56) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 57) def __init__(self, manager, global_build_dir): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 58) self.manager = manager -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 59) self.global_build_dir = None -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 60) self.project_rules_ = ProjectRules(self) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 61) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 62) # The target corresponding to the project being loaded now -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 63) self.current_project = None -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 64) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 65) # The set of names of loaded project modules -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 66) self.jamfile_modules = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 67) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 68) # Mapping from location to module name -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 69) self.location2module = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 70) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 71) # Mapping from project id to project module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 72) self.id2module = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 73) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 74) # Map from Jamfile directory to parent Jamfile/Jamroot -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 75) # location. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 76) self.dir2parent_jamfile = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 77) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 78) # Map from directory to the name of Jamfile in -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 79) # that directory (or None). -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 80) self.dir2jamfile = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 81) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 82) # Map from project module to attributes object. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 83) self.module2attributes = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 84) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 85) # Map from project module to target for the project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 86) self.module2target = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 87) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 88) # Map from names to Python modules, for modules loaded -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 89) # via 'using' and 'import' rules in Jamfiles. -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 90) self.loaded_tool_modules_ = {} -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 91) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 92) # Map from project target to the list of -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 93) # (id,location) pairs corresponding to all 'use-project' -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 94) # invocations. -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 95) # TODO: should not have a global map, keep this -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 96) # in ProjectTarget. -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 97) self.used_projects = {} -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 98) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 99) self.saved_current_project = [] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 100) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 101) self.JAMROOT = self.manager.getenv("JAMROOT"); -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 102) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 103) # Note the use of character groups, as opposed to listing -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 104) # 'Jamroot' and 'jamroot'. With the latter, we'd get duplicate -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 105) # matches on windows and would have to eliminate duplicates. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 106) if not self.JAMROOT: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 107) self.JAMROOT = ["project-root.jam", "[Jj]amroot", "[Jj]amroot.jam"] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 108) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 109) # Default patterns to search for the Jamfiles to use for build -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 110) # declarations. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 111) self.JAMFILE = self.manager.getenv("JAMFILE") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 112) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 113) if not self.JAMFILE: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 114) self.JAMFILE = ["[Bb]uild.jam", "[Jj]amfile.v2", "[Jj]amfile", -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 115) "[Jj]amfile.jam"] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 116) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 117) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 118) def load (self, jamfile_location): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 119) """Loads jamfile at the given location. After loading, project global -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 120) file and jamfile needed by the loaded one will be loaded recursively. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 121) If the jamfile at that location is loaded already, does nothing. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 122) Returns the project module for the Jamfile.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 123) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 124) absolute = os.path.join(os.getcwd(), jamfile_location) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 125) absolute = os.path.normpath(absolute) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 126) jamfile_location = b2.util.path.relpath(os.getcwd(), absolute) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 127) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 128) if "--debug-loading" in self.manager.argv(): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 129) print "Loading Jamfile at '%s'" % jamfile_location -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 130) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 131) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 132) mname = self.module_name(jamfile_location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 133) # If Jamfile is already loaded, don't try again. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 134) if not mname in self.jamfile_modules: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 135) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 136) self.load_jamfile(jamfile_location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 137) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 138) # We want to make sure that child project are loaded only -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 139) # after parent projects. In particular, because parent projects -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 140) # define attributes whch are inherited by children, and we don't -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 141) # want children to be loaded before parents has defined everything. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 142) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 143) # While "build-project" and "use-project" can potentially refer -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 144) # to child projects from parent projects, we don't immediately -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 145) # load child projects when seing those attributes. Instead, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 146) # we record the minimal information that will be used only later. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 147) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 148) self.load_used_projects(mname) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 149) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 150) return mname -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 151) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 152) def load_used_projects(self, module_name): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 153) # local used = [ modules.peek $(module-name) : .used-projects ] ; -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 154) used = self.used_projects[module_name] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 155) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 156) location = self.attribute(module_name, "location") -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 157) for u in used: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 158) id = u[0] -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 159) where = u[1] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 160) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 161) self.use(id, os.path.join(location, where)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 162) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 163) def load_parent(self, location): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 164) """Loads parent of Jamfile at 'location'. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 165) Issues an error if nothing is found.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 166) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 167) found = b2.util.path.glob_in_parents( -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 168) location, self.JAMROOT + self.JAMFILE) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 169) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 170) if not found: -1674e2d9 (jhunold 2008-08-08 19:52:05 +0000 171) print "error: Could not find parent for project at '%s'" % location -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 172) print "error: Did not find Jamfile or project-root.jam in any parent directory." -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 173) sys.exit(1) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 174) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 175) return self.load(os.path.dirname(found[0])) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 176) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 177) def act_as_jamfile(self, module, location): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 178) """Makes the specified 'module' act as if it were a regularly loaded Jamfile -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 179) at 'location'. If Jamfile is already located for that location, it's an -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 180) error.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 181) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 182) if self.module_name(location) in self.jamfile_modules: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 183) self.manager.errors()( -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 184) "Jamfile was already loaded for '%s'" % location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 185) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 186) # Set up non-default mapping from location to module. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 187) self.location2module[location] = module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 188) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 189) # Add the location to the list of project locations -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 190) # so that we don't try to load Jamfile in future -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 191) self.jamfile_modules.append(location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 192) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 193) self.initialize(module, location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 194) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 195) def find(self, name, current_location): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 196) """Given 'name' which can be project-id or plain directory name, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 197) return project module corresponding to that id or directory. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 198) Returns nothing of project is not found.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 199) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 200) project_module = None -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 201) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 202) # Try interpreting name as project id. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 203) if name[0] == '/': -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 204) project_module = self.id2module.get(name) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 205) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 206) if not project_module: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 207) location = os.path.join(current_location, name) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 208) # If no project is registered for the given location, try to -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 209) # load it. First see if we have Jamfile. If not we might have project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 210) # root, willing to act as Jamfile. In that case, project-root -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 211) # must be placed in the directory referred by id. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 212) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 213) project_module = self.module_name(location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 214) if not project_module in self.jamfile_modules and \ -49c03622 (jhunold 2008-07-23 09:57:41 +0000 215) b2.util.path.glob([location], self.JAMROOT + self.JAMFILE): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 216) project_module = self.load(location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 217) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 218) return project_module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 219) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 220) def module_name(self, jamfile_location): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 221) """Returns the name of module corresponding to 'jamfile-location'. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 222) If no module corresponds to location yet, associates default -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 223) module name with that location.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 224) module = self.location2module.get(jamfile_location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 225) if not module: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 226) # Root the path, so that locations are always umbiguious. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 227) # Without this, we can't decide if '../../exe/program1' and '.' -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 228) # are the same paths, or not. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 229) jamfile_location = os.path.realpath( -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 230) os.path.join(os.getcwd(), jamfile_location)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 231) module = "Jamfile<%s>" % jamfile_location -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 232) self.location2module[jamfile_location] = module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 233) return module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 234) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 235) def find_jamfile (self, dir, parent_root=0, no_errors=0): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 236) """Find the Jamfile at the given location. This returns the -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 237) exact names of all the Jamfiles in the given directory. The optional -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 238) parent-root argument causes this to search not the given directory -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 239) but the ones above it up to the directory given in it.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 240) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 241) # Glob for all the possible Jamfiles according to the match pattern. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 242) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 243) jamfile_glob = None -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 244) if parent_root: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 245) parent = self.dir2parent_jamfile.get(dir) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 246) if not parent: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 247) parent = b2.util.path.glob_in_parents(dir, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 248) self.JAMFILE) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 249) self.dir2parent_jamfile[dir] = parent -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 250) jamfile_glob = parent -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 251) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 252) jamfile = self.dir2jamfile.get(dir) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 253) if not jamfile: -49c03622 (jhunold 2008-07-23 09:57:41 +0000 254) jamfile = b2.util.path.glob([dir], self.JAMFILE) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 255) self.dir2jamfile[dir] = jamfile -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 256) jamfile_glob = jamfile -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 257) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 258) if len(jamfile_glob): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 259) # Multiple Jamfiles found in the same place. Warn about this. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 260) # And ensure we use only one of them. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 261) # As a temporary convenience measure, if there's Jamfile.v2 amount -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 262) # found files, suppress the warning and use it. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 263) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 264) pattern = "(.*[Jj]amfile\\.v2)|(.*[Bb]uild\\.jam)" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 265) v2_jamfiles = [x for x in jamfile_glob if re.match(pattern, x)] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 266) if len(v2_jamfiles) == 1: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 267) jamfile_glob = v2_jamfiles -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 268) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 269) print """warning: Found multiple Jamfiles at '%s'! -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 270) Loading the first one: '%s'.""" % (dir, jamfile_glob[0]) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 271) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 272) # Could not find it, error. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 273) if not no_errors and not jamfile_glob: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 274) self.manager.errors()( -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 275) """Unable to load Jamfile. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 276) Could not find a Jamfile in directory '%s' -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 277) Attempted to find it with pattern '%s'. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 278) Please consult the documentation at 'http://boost.org/b2.'.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 279) % (dir, string.join(self.JAMFILE))) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 280) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 281) return jamfile_glob[0] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 282) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 283) def load_jamfile(self, dir): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 284) """Load a Jamfile at the given directory. Returns nothing. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 285) Will attempt to load the file as indicated by the JAMFILE patterns. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 286) Effect of calling this rule twice with the same 'dir' is underfined.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 287) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 288) # See if the Jamfile is where it should be. -49c03622 (jhunold 2008-07-23 09:57:41 +0000 289) jamfile_to_load = b2.util.path.glob([dir], self.JAMROOT) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 290) if not jamfile_to_load: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 291) jamfile_to_load = self.find_jamfile(dir) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 292) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 293) jamfile_to_load = jamfile_to_load[0] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 294) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 295) # The module of the jamfile. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 296) dir = os.path.realpath(os.path.dirname(jamfile_to_load)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 297) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 298) jamfile_module = self.module_name (dir) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 299) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 300) # Initialize the jamfile module before loading. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 301) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 302) self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 303) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 304) saved_project = self.current_project -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 305) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 306) self.used_projects[jamfile_module] = [] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 307) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 308) # Now load the Jamfile in it's own context. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 309) # Initialization might have load parent Jamfiles, which might have -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 310) # loaded the current Jamfile with use-project. Do a final check to make -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 311) # sure it's not loaded already. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 312) if not jamfile_module in self.jamfile_modules: -49c03622 (jhunold 2008-07-23 09:57:41 +0000 313) self.jamfile_modules[jamfile_module] = True -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 314) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 315) # FIXME: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 316) # mark-as-user $(jamfile-module) ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 317) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 318) bjam.call("load", jamfile_module, jamfile_to_load) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 319) basename = os.path.basename(jamfile_to_load) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 320) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 321) # Now do some checks -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 322) if self.current_project != saved_project: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 323) self.manager.errors()( -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 324) """The value of the .current-project variable -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 325) has magically changed after loading a Jamfile. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 326) This means some of the targets might be defined a the wrong project. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 327) after loading %s -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 328) expected value %s -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 329) actual value %s""" % (jamfile_module, saved_project, self.current_project)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 330) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 331) if self.global_build_dir: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 332) id = self.attribute(jamfile_module, "id") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 333) project_root = self.attribute(jamfile_module, "project-root") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 334) location = self.attribute(jamfile_module, "location") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 335) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 336) if location and project_root == dir: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 337) # This is Jamroot -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 338) if not id: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 339) # FIXME: go via errors module, so that contexts are -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 340) # shown? -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 341) print "warning: the --build-dir option was specified" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 342) print "warning: but Jamroot at '%s'" % dir -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 343) print "warning: specified no project id" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 344) print "warning: the --build-dir option will be ignored" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 345) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 346) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 347) def load_standalone(self, jamfile_module, file): -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 348) """Loads 'file' as standalone project that has no location -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 349) associated with it. This is mostly useful for user-config.jam, -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 350) which should be able to define targets, but although it has -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 351) some location in filesystem, we don't want any build to -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 352) happen in user's HOME, for example. -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 353) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 354) The caller is required to never call this method twice on -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 355) the same file. -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 356) """ -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 357) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 358) self.initialize(jamfile_module) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 359) self.used_projects[jamfile_module] = [] -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 360) bjam.call("load", jamfile_module, file) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 361) self.load_used_projects(jamfile_module) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 362) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 363) def is_jamroot(self, basename): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 364) match = [ pat for pat in self.JAMROOT if re.match(pat, basename)] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 365) if match: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 366) return 1 -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 367) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 368) return 0 -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 369) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 370) def initialize(self, module_name, location=None, basename=None): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 371) """Initialize the module for a project. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 372) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 373) module-name is the name of the project module. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 374) location is the location (directory) of the project to initialize. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 375) If not specified, stanalone project will be initialized -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 376) """ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 377) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 378) if "--debug-loading" in self.manager.argv(): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 379) print "Initializing project '%s'" % module_name -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 380) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 381) # TODO: need to consider if standalone projects can do anything but defining -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 382) # prebuilt targets. If so, we need to give more sensible "location", so that -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 383) # source paths are correct. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 384) if not location: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 385) location = "" -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 386) else: -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 387) location = b2.util.path.relpath(os.getcwd(), location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 388) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 389) attributes = ProjectAttributes(self.manager, location, module_name) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 390) self.module2attributes[module_name] = attributes -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 391) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 392) if location: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 393) attributes.set("source-location", location, exact=1) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 394) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 395) attributes.set("source-location", "", exact=1) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 396) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 397) attributes.set("requirements", property_set.empty(), exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 398) attributes.set("usage-requirements", property_set.empty(), exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 399) attributes.set("default-build", [], exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 400) attributes.set("projects-to-build", [], exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 401) attributes.set("project-root", None, exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 402) attributes.set("build-dir", None, exact=True) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 403) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 404) self.project_rules_.init_project(module_name) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 405) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 406) jamroot = False -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 407) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 408) parent_module = None; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 409) if module_name == "site-config": -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 410) # No parent -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 411) pass -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 412) elif module_name == "user-config": -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 413) parent_module = "site-config" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 414) elif location and not self.is_jamroot(basename): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 415) # We search for parent/project-root only if jamfile was specified -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 416) # --- i.e -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 417) # if the project is not standalone. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 418) parent_module = self.load_parent(location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 419) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 420) # It's either jamroot, or standalone project. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 421) # If it's jamroot, inherit from user-config. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 422) if location: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 423) parent_module = "user-config" ; -49c03622 (jhunold 2008-07-23 09:57:41 +0000 424) jamroot = True ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 425) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 426) if parent_module: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 427) self.inherit_attributes(module_name, parent_module) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 428) attributes.set("parent-module", parent_module, exact=1) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 429) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 430) if jamroot: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 431) attributes.set("project-root", location, exact=1) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 432) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 433) parent = None -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 434) if parent_module: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 435) parent = self.target(parent_module) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 436) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 437) if not self.module2target.has_key(module_name): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 438) target = b2.build.targets.ProjectTarget(self.manager, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 439) module_name, module_name, parent, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 440) self.attribute(module_name,"requirements"), -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 441) # FIXME: why we need to pass this? It's not -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 442) # passed in jam code. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 443) self.attribute(module_name, "default-build")) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 444) self.module2target[module_name] = target -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 445) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 446) self.current_project = self.target(module_name) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 447) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 448) def inherit_attributes(self, project_module, parent_module): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 449) """Make 'project-module' inherit attributes of project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 450) root and parent module.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 451) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 452) attributes = self.module2attributes[project_module] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 453) pattributes = self.module2attributes[parent_module] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 454) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 455) # Parent module might be locationless user-config. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 456) # FIXME: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 457) #if [ modules.binding $(parent-module) ] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 458) #{ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 459) # $(attributes).set parent : [ path.parent -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 460) # [ path.make [ modules.binding $(parent-module) ] ] ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 461) # } -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 462) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 463) attributes.set("project-root", pattributes.get("project-root"), exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 464) attributes.set("default-build", pattributes.get("default-build"), exact=True) -49c03622 (jhunold 2008-07-23 09:57:41 +0000 465) attributes.set("requirements", pattributes.get("requirements"), exact=True) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 466) attributes.set("usage-requirements", -cde6f09a (vladimir_prus 2007-10-19 23:12:33 +0000 467) pattributes.get("usage-requirements"), exact=1) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 468) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 469) parent_build_dir = pattributes.get("build-dir") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 470) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 471) if parent_build_dir: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 472) # Have to compute relative path from parent dir to our dir -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 473) # Convert both paths to absolute, since we cannot -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 474) # find relative path from ".." to "." -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 475) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 476) location = attributes.get("location") -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 477) parent_location = pattributes.get("location") -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 478) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 479) our_dir = os.path.join(os.getcwd(), location) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 480) parent_dir = os.path.join(os.getcwd(), parent_location) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 481) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 482) build_dir = os.path.join(parent_build_dir, -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 483) b2.util.path.relpath(parent_dir, -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 484) our_dir)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 485) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 486) def register_id(self, id, module): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 487) """Associate the given id with the given project module.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 488) self.id2module[id] = module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 489) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 490) def current(self): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 491) """Returns the project which is currently being loaded.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 492) return self.current_project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 493) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 494) def push_current(self, project): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 495) """Temporary changes the current project to 'project'. Should -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 496) be followed by 'pop-current'.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 497) self.saved_current_project.append(self.current_project) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 498) self.current_project = project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 499) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 500) def pop_current(self): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 501) self.current_project = self.saved_current_project[-1] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 502) del self.saved_current_project[-1] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 503) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 504) def attributes(self, project): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 505) """Returns the project-attribute instance for the -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 506) specified jamfile module.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 507) return self.module2attributes[project] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 508) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 509) def attribute(self, project, attribute): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 510) """Returns the value of the specified attribute in the -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 511) specified jamfile module.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 512) return self.module2attributes[project].get(attribute) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 513) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 514) def target(self, project_module): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 515) """Returns the project target corresponding to the 'project-module'.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 516) if not self.module2target[project_module]: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 517) self.module2target[project_module] = \ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 518) ProjectTarget(project_module, project_module, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 519) self.attribute(project_module, "requirements")) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 520) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 521) return self.module2target[project_module] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 522) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 523) def use(self, id, location): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 524) # Use/load a project. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 525) saved_project = self.current_project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 526) project_module = self.load(location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 527) declared_id = self.attribute(project_module, "id") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 528) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 529) if not declared_id or declared_id != id: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 530) # The project at 'location' either have no id or -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 531) # that id is not equal to the 'id' parameter. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 532) if self.id2module[id] and self.id2module[id] != project_module: -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 533) self.manager.errors()( -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 534) """Attempt to redeclare already existing project id '%s'""" % id) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 535) self.id2module[id] = project_module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 536) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 537) self.current_module = saved_project -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 538) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 539) def add_rule(self, name, callable): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 540) """Makes rule 'name' available to all subsequently loaded Jamfiles. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 541) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 542) Calling that rule wil relay to 'callable'.""" -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 543) self.project_rules_.add_rule(name, callable) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 544) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 545) def project_rules(self): -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 546) return self.project_rules_ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 547) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 548) def glob_internal(self, project, wildcards, excludes, rule_name): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 549) location = project.get("source-location") -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 550) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 551) result = [] -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 552) callable = b2.util.path.__dict__[rule_name] -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 553) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 554) paths = callable(location, wildcards, excludes) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 555) has_dir = 0 -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 556) for w in wildcards: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 557) if os.path.dirname(w): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 558) has_dir = 1 -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 559) break -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 560) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 561) if has_dir or rule_name != "glob": -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 562) # The paths we've found are relative to current directory, -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 563) # but the names specified in sources list are assumed to -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 564) # be relative to source directory of the corresponding -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 565) # prject. So, just make the name absolute. -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 566) result = [os.path.join(os.getcwd(), p) for p in paths] -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 567) else: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 568) # There were not directory in wildcard, so the files are all -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 569) # in the source directory of the project. Just drop the -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 570) # directory, instead of making paths absolute. -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 571) result = [os.path.basename(p) for p in paths] -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 572) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 573) return result -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 574) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 575) def load_module(self, name, extra_path=None): -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 576) """Classic Boost.Build 'modules' are in fact global variables. -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 577) Therefore, try to find an already loaded Python module called 'name' in sys.modules. -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 578) If the module ist not loaded, find it Boost.Build search -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 579) path and load it. The new module is not entered in sys.modules. -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 580) The motivation here is to have disjoint namespace of modules -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 581) loaded via 'import/using' in Jamfile, and ordinary Python -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 582) modules. We don't want 'using foo' in Jamfile to load ordinary -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 583) Python module 'foo' which is going to not work. And we -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 584) also don't want 'import foo' in regular Python module to -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 585) accidentally grab module named foo that is internal to -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 586) Boost.Build and intended to provide interface to Jamfiles.""" -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 587) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 588) existing = self.loaded_tool_modules_.get(name) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 589) if existing: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 590) return existing -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 591) -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 592) modules = sys.modules -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 593) for class_name in modules: -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 594) if name in class_name: -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 595) module = modules[class_name] -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 596) self.loaded_tool_modules_[name] = module -53b0faa2 (jhunold 2008-08-10 18:25:50 +0000 597) return module -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 598) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 599) path = extra_path -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 600) if not path: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 601) path = [] -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 602) path.extend(self.manager.b2.path()) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 603) location = None -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 604) for p in path: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 605) l = os.path.join(p, name + ".py") -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 606) if os.path.exists(l): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 607) location = l -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 608) break -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 609) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 610) if not location: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 611) self.manager.errors()("Cannot find module '%s'" % name) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 612) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 613) mname = "__build_build_temporary__" -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 614) file = open(location) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 615) try: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 616) # TODO: this means we'll never make use of .pyc module, -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 617) # which might be a problem, or not. -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 618) module = imp.load_module(mname, file, os.path.basename(location), -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 619) (".py", "r", imp.PY_SOURCE)) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 620) del sys.modules[mname] -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 621) self.loaded_tool_modules_[name] = module -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 622) return module -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 623) finally: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 624) file.close() -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 625) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 626) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 627) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 628) # FIXME: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 629) # Defines a Boost.Build extension project. Such extensions usually -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 630) # contain library targets and features that can be used by many people. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 631) # Even though extensions are really projects, they can be initialize as -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 632) # a module would be with the "using" (project.project-rules.using) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 633) # mechanism. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 634) #rule extension ( id : options * : * ) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 635) #{ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 636) # # The caller is a standalone module for the extension. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 637) # local mod = [ CALLER_MODULE ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 638) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 639) # # We need to do the rest within the extension module. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 640) # module $(mod) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 641) # { -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 642) # import path ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 643) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 644) # # Find the root project. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 645) # local root-project = [ project.current ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 646) # root-project = [ $(root-project).project-module ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 647) # while -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 648) # [ project.attribute $(root-project) parent-module ] && -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 649) # [ project.attribute $(root-project) parent-module ] != user-config -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 650) # { -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 651) # root-project = [ project.attribute $(root-project) parent-module ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 652) # } -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 653) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 654) # # Create the project data, and bring in the project rules -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 655) # # into the module. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 656) # project.initialize $(__name__) : -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 657) # [ path.join [ project.attribute $(root-project) location ] ext $(1:L) ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 658) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 659) # # Create the project itself, i.e. the attributes. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 660) # # All extensions are created in the "/ext" project space. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 661) # project /ext/$(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 662) # local attributes = [ project.attributes $(__name__) ] ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 663) # -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 664) # # Inherit from the root project of whomever is defining us. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 665) # project.inherit-attributes $(__name__) : $(root-project) ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 666) # $(attributes).set parent-module : $(root-project) : exact ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 667) # } -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 668) #} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 669) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 670) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 671) class ProjectAttributes: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 672) """Class keeping all the attributes of a project. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 673) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 674) The standard attributes are 'id', "location", "project-root", "parent" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 675) "requirements", "default-build", "source-location" and "projects-to-build". -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 676) """ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 677) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 678) def __init__(self, manager, location, project_module): -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 679) self.manager = manager -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 680) self.location = location -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 681) self.project_module = project_module -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 682) self.attributes = {} -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 683) self.usage_requirements = None -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 684) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 685) def set(self, attribute, specification, exact): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 686) """Set the named attribute from the specification given by the user. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 687) The value actually set may be different.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 688) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 689) if exact: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 690) self.__dict__[attribute] = specification -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 691) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 692) elif attribute == "requirements": -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 693) self.requirements = property_set.refine_from_user_input( -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 694) self.requirements, specification, -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 695) self.project_module, self.location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 696) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 697) elif attribute == "usage-requirements": -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 698) unconditional = [] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 699) for p in specification: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 700) split = property.split_conditional(p) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 701) if split: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 702) unconditional.append(split[1]) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 703) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 704) unconditional.append(p) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 705) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 706) non_free = property.remove("free", unconditional) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 707) if non_free: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 708) pass -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 709) # FIXME: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 710) #errors.error "usage-requirements" $(specification) "have non-free properties" $(non-free) ; -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 711) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 712) t = property.translate_paths(specification, self.location) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 713) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 714) existing = self.__dict__.get("usage-requirements") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 715) if existing: -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 716) new = property_set.create(existing.raw() + t) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 717) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 718) new = property_set.create(t) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 719) self.__dict__["usage-requirements"] = new -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 720) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 721) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 722) elif attribute == "default-build": -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 723) self.__dict__["default-build"] = property_set.create(specification) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 724) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 725) elif attribute == "source-location": -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 726) source_location = [] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 727) for path in specification: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 728) source_location += os.path.join(self.location, path) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 729) self.__dict__["source-location"] = source_location -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 730) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 731) elif attribute == "build-dir": -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 732) self.__dict__["build-dir"] = os.path.join(self.location, specification) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 733) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 734) elif not attribute in ["id", "default-build", "location", -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 735) "source-location", "parent", -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 736) "projects-to-build", "project-root"]: -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 737) self.manager.errors()( -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 738) """Invalid project attribute '%s' specified -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 739) for project at '%s'""" % (attribute, self.location)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 740) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 741) self.__dict__[attribute] = specification -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 742) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 743) def get(self, attribute): -cde6f09a (vladimir_prus 2007-10-19 23:12:33 +0000 744) return self.__dict__[attribute] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 745) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 746) def dump(self): -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 747) """Prints the project attributes.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 748) id = self.get("id") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 749) if not id: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 750) id = "(none)" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 751) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 752) id = id[0] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 753) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 754) parent = self.get("parent") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 755) if not parent: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 756) parent = "(none)" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 757) else: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 758) parent = parent[0] -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 759) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 760) print "'%s'" % id -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 761) print "Parent project:%s", parent -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 762) print "Requirements:%s", self.get("requirements") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 763) print "Default build:%s", string.join(self.get("debuild-build")) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 764) print "Source location:%s", string.join(self.get("source-location")) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 765) print "Projects to build:%s", string.join(self.get("projects-to-build").sort()); -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 766) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 767) class ProjectRules: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 768) """Class keeping all rules that are made available to Jamfile.""" -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 769) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 770) def __init__(self, registry): -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 771) self.registry = registry -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 772) self.manager_ = registry.manager -38d984eb (vladimir_prus 2007-10-13 17:52:25 +0000 773) self.rules = {} -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 774) self.local_names = [x for x in self.__class__.__dict__ -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 775) if x not in ["__init__", "init_project", "add_rule", -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 776) "error_reporting_wrapper", "add_rule_for_type"]] -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 777) self.all_names_ = [x for x in self.local_names] -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 778) -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 779) def add_rule_for_type(self, type): -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 780) rule_name = type.lower(); -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 781) -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 782) def xpto (name, sources, requirements = [], default_build = None, usage_requirements = []): -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 783) return self.manager_.targets().create_typed_target( -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 784) type, self.registry.current(), name[0], sources, -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 785) requirements, default_build, usage_requirements) -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 786) -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 787) self.add_rule(type.lower(), xpto) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 788) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 789) def add_rule(self, name, callable): -38d984eb (vladimir_prus 2007-10-13 17:52:25 +0000 790) self.rules[name] = callable -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 791) self.all_names_.append(name) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 792) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 793) def all_names(self): -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 794) return self.all_names_ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 795) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 796) def call_and_report_errors(self, callable, *args): -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 797) result = None -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 798) try: -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 799) self.manager_.errors().push_jamfile_context() -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 800) result = callable(*args) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 801) except ExceptionWithUserContext, e: -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 802) e.report() -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 803) except Exception, e: -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 804) try: -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 805) self.manager_.errors().handle_stray_exception (e) -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 806) except ExceptionWithUserContext, e: -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 807) e.report() -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 808) finally: -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 809) self.manager_.errors().pop_jamfile_context() -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 810) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 811) return result -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 812) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 813) def make_wrapper(self, callable): -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 814) """Given a free-standing function 'callable', return a new -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 815) callable that will call 'callable' and report all exceptins, -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 816) using 'call_and_report_errors'.""" -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 817) def wrapper(*args): -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 818) self.call_and_report_errors(callable, *args) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 819) return wrapper -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 820) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 821) def init_project(self, project_module): -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 822) -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 823) for n in self.local_names: -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 824) # Using 'getattr' here gives us a bound method, -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 825) # while using self.__dict__[r] would give unbound one. -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 826) v = getattr(self, n) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 827) if callable(v): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 828) if n == "import_": -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 829) n = "import" -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 830) else: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 831) n = string.replace(n, "_", "-") -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 832) -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 833) bjam.import_rule(project_module, n, -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 834) self.make_wrapper(v)) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 835) -38d984eb (vladimir_prus 2007-10-13 17:52:25 +0000 836) for n in self.rules: -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 837) bjam.import_rule(project_module, n, -0317671e (vladimir_prus 2007-10-28 14:02:06 +0000 838) self.make_wrapper(self.rules[n])) -38d984eb (vladimir_prus 2007-10-13 17:52:25 +0000 839) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 840) def project(self, *args): -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 841) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 842) jamfile_module = self.registry.current().project_module() -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 843) attributes = self.registry.attributes(jamfile_module) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 844) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 845) id = None -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 846) if args and args[0]: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 847) id = args[0][0] -092119e3 (vladimir_prus 2007-10-16 05:45:31 +0000 848) args = args[1:] -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 849) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 850) if id: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 851) if id[0] != '/': -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 852) id = '/' + id -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 853) self.registry.register_id (id, jamfile_module) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 854) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 855) explicit_build_dir = None -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 856) for a in args: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 857) if a: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 858) attributes.set(a[0], a[1:], exact=0) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 859) if a[0] == "build-dir": -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 860) explicit_build_dir = a[1] -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 861) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 862) # If '--build-dir' is specified, change the build dir for the project. -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 863) if self.registry.global_build_dir: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 864) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 865) location = attributes.get("location") -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 866) # Project with empty location is 'standalone' project, like -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 867) # user-config, or qt. It has no build dir. -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 868) # If we try to set build dir for user-config, we'll then -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 869) # try to inherit it, with either weird, or wrong consequences. -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 870) if location and location == attributes.get("project-root"): -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 871) # This is Jamroot. -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 872) if id: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 873) if explicit_build_dir and os.path.isabs(explicit_build_dir): -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 874) self.register.manager.errors()( -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 875) """Absolute directory specified via 'build-dir' project attribute -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 876) Don't know how to combine that with the --build-dir option.""") -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 877) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 878) rid = id -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 879) if rid[0] == '/': -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 880) rid = rid[1:] -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 881) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 882) p = os.path.join(self.registry.global_build_dir, -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 883) rid, explicit_build_dir) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 884) attributes.set("build-dir", p, exact=1) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 885) elif explicit_build_dir: -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 886) self.registry.manager.errors()( -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 887) """When --build-dir is specified, the 'build-project' -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 888) attribute is allowed only for top-level 'project' invocations""") -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 889) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 890) def constant(self, name, value): -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 891) """Declare and set a project global constant. -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 892) Project global constants are normal variables but should -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 893) not be changed. They are applied to every child Jamfile.""" -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 894) m = "Jamfile" -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 895) self.registry.current().add_constant(name[0], value) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 896) -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 897) def path_constant(self, name, value): -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 898) """Declare and set a project global constant, whose value is a path. The -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 899) path is adjusted to be relative to the invocation directory. The given -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 900) value path is taken to be either absolute, or relative to this project -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 901) root.""" -0ed8e16d (vladimir_prus 2007-10-13 21:34:05 +0000 902) self.registry.current().add_constant(name[0], value, path=1) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 903) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 904) def use_project(self, id, where): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 905) # See comment in 'load' for explanation why we record the -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 906) # parameters as opposed to loading the project now. -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 907) m = self.registry.current().project_module(); -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 908) self.registry.used_projects[m].append((id, where)) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 909) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 910) def build_project(self, dir): -1674e2d9 (jhunold 2008-08-08 19:52:05 +0000 911) assert(isinstance(dir, list)) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 912) jamfile_module = self.registry.current().project_module() -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 913) attributes = self.registry.attributes(jamfile_module) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 914) now = attributes.get("projects-to-build") -1674e2d9 (jhunold 2008-08-08 19:52:05 +0000 915) attributes.set("projects-to-build", now + dir, exact=True) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 916) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 917) def explicit(self, target_names): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 918) t = self.registry.current() -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 919) for n in target_names: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 920) t.mark_target_as_explicit(n) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 921) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 922) def glob(self, wildcards, excludes=None): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 923) return self.registry.glob_internal(self.registry.current(), -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 924) wildcards, excludes, "glob") -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 925) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 926) def glob_tree(self, wildcards, excludes=None): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 927) bad = 0 -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 928) for p in wildcards: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 929) if os.path.dirname(p): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 930) bad = 1 -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 931) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 932) if excludes: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 933) for p in excludes: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 934) if os.path.dirname(p): -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 935) bad = 1 -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 936) -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 937) if bad: -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 938) self.registry.manager().errors()( -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 939) "The patterns to 'glob-tree' may not include directory") -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 940) return self.registry.glob_internal(self.registry.current(), -2a36874b (vladimir_prus 2007-10-14 07:20:55 +0000 941) wildcards, excludes, "glob_tree") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 942) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 943) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 944) def using(self, toolset, *args): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 945) # The module referred by 'using' can be placed in -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 946) # the same directory as Jamfile, and the user -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 947) # will expect the module to be found even though -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 948) # the directory is not in BOOST_BUILD_PATH. -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 949) # So temporary change the search path. -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 950) jamfile_module = self.registry.current().project_module() -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 951) attributes = self.registry.attributes(jamfile_module) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 952) location = attributes.get("location") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 953) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 954) m = self.registry.load_module(toolset[0], [location]) -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 955) if not m.__dict__.has_key("init"): -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 956) self.registry.manager.errors()( -7da7f9c1 (vladimir_prus 2008-05-18 04:29:53 +0000 957) "Tool module '%s' does not define the 'init' method" % toolset[0]) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 958) m.init(*args) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 959) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 960) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 961) def import_(self, name, names_to_import=None, local_names=None): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 962) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 963) name = name[0] -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 964) jamfile_module = self.registry.current().project_module() -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 965) attributes = self.registry.attributes(jamfile_module) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 966) location = attributes.get("location") -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 967) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 968) m = self.registry.load_module(name, [location]) -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 969) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 970) for f in m.__dict__: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 971) v = m.__dict__[f] -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 972) if callable(v): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 973) bjam.import_rule(jamfile_module, name + "." + f, v) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 974) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 975) if names_to_import: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 976) if not local_names: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 977) local_names = names_to_import -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 978) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 979) if len(names_to_import) != len(local_names): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 980) self.registry.manager.errors()( -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 981) """The number of names to import and local names do not match.""") -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 982) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 983) for n, l in zip(names_to_import, local_names): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 984) bjam.import_rule(jamfile_module, l, m.__dict__[n]) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 985) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 986) def conditional(self, condition, requirements): -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 987) """Calculates conditional requirements for multiple requirements -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 988) at once. This is a shorthand to be reduce duplication and to -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 989) keep an inline declarative syntax. For example: -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 990) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 991) lib x : x.cpp : [ conditional gcc debug : -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 992) DEBUG_EXCEPTION DEBUG_TRACE ] ; -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 993) """ -f049766b (vladimir_prus 2007-10-10 09:31:06 +0000 994) -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 995) c = string.join(condition, ",") -f2aef897 (vladimir_prus 2007-10-14 09:19:52 +0000 996) return [c + ":" + r for r in requirements] From b3d45f8694c672a02816c3051764c95d5c95653b Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:29:22 -0500 Subject: [PATCH 074/158] Fix project initialization and loading. The recently added __python_module_cache broke project.initialize(). This fixes the standalone Python file loading. --- src/build/project.py | 218 +++++++++++++++++++++++++------------------ 1 file changed, 126 insertions(+), 92 deletions(-) diff --git a/src/build/project.py b/src/build/project.py index 44429e301..7c8ce6823 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -321,47 +321,68 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" # same project we're loading now. Checking inside .jamfile-modules # prevents that second attempt from messing up. if not jamfile_module in self.jamfile_modules: - self.jamfile_modules[jamfile_module] = True - + previous_project = self.current_project # Initialize the jamfile module before loading. - # self.initialize(jamfile_module, dir, os.path.basename(jamfile_to_load)) - saved_project = self.current_project + if not jamfile_module in self.jamfile_modules: + saved_project = self.current_project + self.jamfile_modules[jamfile_module] = True - bjam.call("load", jamfile_module, jamfile_to_load) - basename = os.path.basename(jamfile_to_load) + bjam.call("load", jamfile_module, jamfile_to_load) + basename = os.path.basename(jamfile_to_load) - if is_jamroot: - jamfile = self.find_jamfile(dir, no_errors=True) - if jamfile: - bjam.call("load", jamfile_module, jamfile) + if is_jamroot: + jamfile = self.find_jamfile(dir, no_errors=True) + if jamfile: + bjam.call("load", jamfile_module, jamfile) - # Now do some checks - if self.current_project != saved_project: + # Now do some checks + if self.current_project != saved_project: + from textwrap import dedent + self.manager.errors()(dedent( + """ + The value of the .current-project variable has magically changed + after loading a Jamfile. This means some of the targets might be + defined a the wrong project. + after loading %s + expected value %s + actual value %s + """ + % (jamfile_module, saved_project, self.current_project) + )) + + self.end_load(previous_project) + + if self.global_build_dir: + id = self.attributeDefault(jamfile_module, "id", None) + project_root = self.attribute(jamfile_module, "project-root") + location = self.attribute(jamfile_module, "location") + + if location and project_root == dir: + # This is Jamroot + if not id: + # FIXME: go via errors module, so that contexts are + # shown? + print "warning: the --build-dir option was specified" + print "warning: but Jamroot at '%s'" % dir + print "warning: specified no project id" + print "warning: the --build-dir option will be ignored" + + def end_load(self, previous_project): + if not self.current_project: self.manager.errors()( -"""The value of the .current-project variable -has magically changed after loading a Jamfile. -This means some of the targets might be defined a the wrong project. -after loading %s -expected value %s -actual value %s""" % (jamfile_module, saved_project, self.current_project)) + 'Ending project loading requested when there was no project currently ' + 'being loaded.' + ) - if self.global_build_dir: - id = self.attributeDefault(jamfile_module, "id", None) - project_root = self.attribute(jamfile_module, "project-root") - location = self.attribute(jamfile_module, "location") - - if location and project_root == dir: - # This is Jamroot - if not id: - # FIXME: go via errors module, so that contexts are - # shown? - print "warning: the --build-dir option was specified" - print "warning: but Jamroot at '%s'" % dir - print "warning: specified no project id" - print "warning: the --build-dir option will be ignored" + if not previous_project and self.saved_current_project: + self.manager.errors()( + 'Ending project loading requested with no "previous project" when there ' + 'other projects still being loaded recursively.' + ) + self.current_project = previous_project def load_standalone(self, jamfile_module, file): """Loads 'file' as standalone project that has no location @@ -388,49 +409,20 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) else: return 0 - def initialize(self, module_name, location=None, basename=None): + def initialize(self, module_name, location=None, basename=None, standalone_path=''): """Initialize the module for a project. module-name is the name of the project module. location is the location (directory) of the project to initialize. If not specified, standalone project will be initialized + standalone_path is the path to the source-location. + this should only be called from the python side. """ assert isinstance(module_name, basestring) assert isinstance(location, basestring) or location is None assert isinstance(basename, basestring) or basename is None - if "--debug-loading" in self.manager.argv(): - print "Initializing project '%s'" % module_name - - # TODO: need to consider if standalone projects can do anything but defining - # prebuilt targets. If so, we need to give more sensible "location", so that - # source paths are correct. - if not location: - location = "" - - attributes = ProjectAttributes(self.manager, location, module_name) - self.module2attributes[module_name] = attributes - - python_standalone = False - if location: - attributes.set("source-location", [location], exact=1) - elif not module_name in ["test-config", "site-config", "user-config", "project-config"]: - # This is a standalone project with known location. Set source location - # so that it can declare targets. This is intended so that you can put - # a .jam file in your sources and use it via 'using'. Standard modules - # (in 'tools' subdir) may not assume source dir is set. - attributes.set("source-location", self.loaded_tool_module_path_[module_name], exact=1) - python_standalone = True - - attributes.set("requirements", property_set.empty(), exact=True) - attributes.set("usage-requirements", property_set.empty(), exact=True) - attributes.set("default-build", property_set.empty(), exact=True) - attributes.set("projects-to-build", [], exact=True) - attributes.set("project-root", None, exact=True) - attributes.set("build-dir", None, exact=True) - - self.project_rules_.init_project(module_name, python_standalone) - jamroot = False + parent_module = None parent_module = None; if module_name == "test-config": @@ -447,37 +439,74 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # --- i.e # if the project is not standalone. parent_module = self.load_parent(location) - else: + elif location: # It's either jamroot, or standalone project. # If it's jamroot, inherit from user-config. + # If project-config module exist, inherit from it. + parent_module = 'user-config' + if 'project-config' in self.module2attributes: + parent_module = 'project-config' + jamroot = True + + # TODO: need to consider if standalone projects can do anything but defining + # prebuilt targets. If so, we need to give more sensible "location", so that + # source paths are correct. + if not location: + location = "" + + # the call to load_parent() above can end up loading this module again + # make sure we don't reinitialize the module's attributes + if module_name not in self.module2attributes: + if "--debug-loading" in self.manager.argv(): + print "Initializing project '%s'" % module_name + attributes = ProjectAttributes(self.manager, location, module_name) + self.module2attributes[module_name] = attributes + + python_standalone = False if location: - # If project-config module exist, inherit from it. - if "project-config" in self.module2attributes: - parent_module = "project-config" - else: - parent_module = "user-config" ; + attributes.set("source-location", [location], exact=1) + elif not module_name in ["test-config", "site-config", "user-config", "project-config"]: + # This is a standalone project with known location. Set source location + # so that it can declare targets. This is intended so that you can put + # a .jam file in your sources and use it via 'using'. Standard modules + # (in 'tools' subdir) may not assume source dir is set. + source_location = standalone_path + if not source_location: + source_location = self.loaded_tool_module_path_.get(module_name) + if not source_location: + self.manager.errors()('Standalone module path not found for "{}"' + .format(module_name)) + attributes.set("source-location", [source_location], exact=1) + python_standalone = True - jamroot = True ; + attributes.set("requirements", property_set.empty(), exact=True) + attributes.set("usage-requirements", property_set.empty(), exact=True) + attributes.set("default-build", property_set.empty(), exact=True) + attributes.set("projects-to-build", [], exact=True) + attributes.set("project-root", None, exact=True) + attributes.set("build-dir", None, exact=True) - if parent_module: - self.inherit_attributes(module_name, parent_module) - attributes.set("parent-module", parent_module, exact=1) + self.project_rules_.init_project(module_name, python_standalone) - if jamroot: - attributes.set("project-root", location, exact=1) + if parent_module: + self.inherit_attributes(module_name, parent_module) + attributes.set("parent-module", parent_module, exact=1) - parent = None - if parent_module: - parent = self.target(parent_module) + if jamroot: + attributes.set("project-root", location, exact=1) - if module_name not in self.module2target: - target = b2.build.targets.ProjectTarget(self.manager, - module_name, module_name, parent, - self.attribute(module_name, "requirements"), - # FIXME: why we need to pass this? It's not - # passed in jam code. - self.attribute(module_name, "default-build")) - self.module2target[module_name] = target + parent = None + if parent_module: + parent = self.target(parent_module) + + if module_name not in self.module2target: + target = b2.build.targets.ProjectTarget(self.manager, + module_name, module_name, parent, + self.attribute(module_name, "requirements"), + # FIXME: why we need to pass this? It's not + # passed in jam code. + self.attribute(module_name, "default-build")) + self.module2target[module_name] = target self.current_project = self.target(module_name) @@ -600,7 +629,7 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) """Attempt to redeclare already existing project id '%s' at location '%s'""" % (id, location)) self.id2module[id] = project_module - self.current_module = saved_project + self.current_project = saved_project def add_rule(self, name, callable_): """Makes rule 'name' available to all subsequently loaded Jamfiles. @@ -750,12 +779,17 @@ actual value %s""" % (jamfile_module, saved_project, self.current_project)) # 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. + # in some cases, self.loaded_tool_module_path_ needs to + # have the path to the file during the import + # (project.initialize() for example), + # so the path needs to be set *before* importing the module. + path = os.path.join(b2.__path__[0], *mname.split('.')[1:]) + self.loaded_tool_module_path_[mname] = path + # mname is guaranteed to be importable since it was + # found within the cache __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) From 3b453b85e5d0b6a9c00dbd53677abe4bcefc3c37 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:31:12 -0500 Subject: [PATCH 075/158] Fix typos in project.py --- src/build/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/build/project.py b/src/build/project.py index 7c8ce6823..46888cb2a 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -1138,8 +1138,8 @@ attribute is allowed only for top-level 'project' invocations""") assert is_iterable_typed(name, basestring) assert is_iterable_typed(value, basestring) if len(value) > 1: - self.registry.manager.error()("path constant should have one element") - self.registry.current().add_constant(name[0], value[0], path=1) + self.registry.manager.errors()("path constant should have one element") + self.registry.current().add_constant(name[0], value, path=1) def use_project(self, id, where): # See comment in 'load' for explanation why we record the @@ -1162,7 +1162,7 @@ attribute is allowed only for top-level 'project' invocations""") def always(self, target_names): assert is_iterable_typed(target_names, basestring) - self.registry.current().mark_targets_as_alays(target_names) + self.registry.current().mark_targets_as_always(target_names) def glob(self, wildcards, excludes=None): assert is_iterable_typed(wildcards, basestring) From 98f1c4b92f46e6c0454ea73c2490235a1c14b3c1 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:33:19 -0500 Subject: [PATCH 076/158] Remove unused import in scanners.py and update base Scanner.process signature. --- src/build/scanner.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/build/scanner.py b/src/build/scanner.py index a9720b74b..ec3b31b40 100644 --- a/src/build/scanner.py +++ b/src/build/scanner.py @@ -28,11 +28,9 @@ # but different instances, and lead in unneeded duplication of # actual targets. However, actions can also create scanners in a special # way, instead of relying on just target type. - import property import bjam import os -from b2.exceptions import * from b2.manager import get_manager from b2.util import is_iterable_typed @@ -99,7 +97,7 @@ class Scanner: """ raise BaseException ("method must be overriden") - def process (self, target, matches): + def process (self, target, matches, binding): """ Establish necessary relationship between targets, given actual target beeing scanned, and a list of pattern matches in that file. From 707a56e9b5941460d28ff500fd7c0f2e045e7cb0 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:37:47 -0500 Subject: [PATCH 077/158] Prevent already registered type error. A type can be registered as inheriting from a base type, however, due to lazy loading, it's possible for that base type to not have been registered yet. Originally, calling type.register() with an unregistered base type would have registered the base type. Later, when the base type itself was registered, an error would have been raised saying that the base type was already registered. This change allows for lazy loading to occur such that a base type can be registered after a subtype is has already inherited from it. --- src/build/type.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/build/type.py b/src/build/type.py index 6797f19be..f2eff8853 100644 --- a/src/build/type.py +++ b/src/build/type.py @@ -71,14 +71,19 @@ def register (type, suffixes = [], base_type = None): if __re_hyphen.search (type): raise BaseException ('type name "%s" contains a hyphen' % type) - if type in __types: + # it's possible for a type to be registered with a + # base type that hasn't been registered yet. in the + # check for base_type below and the following calls to setdefault() + # the key `type` will be added to __types. When the base type + # actually gets registered, it would fail after the simple check + # of "type in __types"; thus the check for "'base' in __types[type]" + if type in __types and 'base' in __types[type]: raise BaseException ('Type "%s" is already registered.' % type) - entry = {} - entry ['base'] = base_type - entry ['derived'] = [] - entry ['scanner'] = None - __types [type] = entry + entry = __types.setdefault(type, {}) + entry['base'] = base_type + entry.setdefault('derived', []) + entry.setdefault('scanner', None) if base_type: __types.setdefault(base_type, {}).setdefault('derived', []).append(type) From 5471945b4de4b44532b4b8a6d37c96cd38a2dfe5 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:45:45 -0500 Subject: [PATCH 078/158] Fix bjam_signature for set_generated_target_prefix(). Update docs. --- src/build/type.py | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/build/type.py b/src/build/type.py index f2eff8853..3d9b7c1b2 100644 --- a/src/build/type.py +++ b/src/build/type.py @@ -255,16 +255,23 @@ def generated_target_suffix(type, properties): assert isinstance(properties, PropertySet) return generated_target_ps(1, type, properties) -# Sets a target prefix that should be used when generating targets of 'type' -# with the specified properties. Can be called with empty properties if no -# prefix for 'type' has been specified yet. -# -# The 'prefix' parameter can be empty string ("") to indicate that no prefix -# should be used. -# -# Usage example: library names use the "lib" prefix on unix. -@bjam_signature((["type"], ["properties", "*"], ["suffix"])) + +@bjam_signature((["type"], ["properties", "*"], ["prefix"])) def set_generated_target_prefix(type, properties, prefix): + """ + Sets a file prefix to be used when generating a target of 'type' with the + specified properties. Can be called with no properties if no prefix has + already been specified for the 'type'. The 'prefix' parameter can be an empty + string ("") to indicate that no prefix should be used. + + Note that this does not cause files with 'prefix' to be automatically + recognized as being of 'type'. Two different types can use the same prefix for + their generated files but only one type can be auto-detected for a file with + that prefix. User should explicitly specify which one using the + register-prefixes rule. + + Usage example: library names use the "lib" prefix on unix. + """ set_generated_target_ps(0, type, properties, prefix) # Change the prefix previously registered for this type/properties combination. From 4a37e4b147b2d9b5838c58fe6e888f0258df95f0 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:46:43 -0500 Subject: [PATCH 079/158] Update version.py --- src/build/version.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/build/version.py b/src/build/version.py index 1efe3b5c5..88299060e 100644 --- a/src/build/version.py +++ b/src/build/version.py @@ -10,12 +10,12 @@ from b2.manager import get_manager MANAGER = get_manager() ERROR_HANDLER = MANAGER.errors() -_major = "2014" -_minor = "03" +_major = "2015" +_minor = "07" def boost_build(): - return "{}.{}-svn".format(_major, _minor) + return "{}.{}-git".format(_major, _minor) def verify_engine_version(): From 12814997199b9d89d5cc57be18901769027cf76d Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:49:10 -0500 Subject: [PATCH 080/158] Fix --ignore-toolset-requirements flag. --- src/build/toolset.py | 9 +++++---- src/build_system.py | 20 +++++++++----------- 2 files changed, 14 insertions(+), 15 deletions(-) diff --git a/src/build/toolset.py b/src/build/toolset.py index 672d18f5a..59ddd7378 100644 --- a/src/build/toolset.py +++ b/src/build/toolset.py @@ -9,6 +9,7 @@ """ Support for toolset definition. """ +import sys import feature, property, generators, property_set import b2.util.set @@ -23,6 +24,7 @@ __re_split_last_segment = re.compile (r'^(.+)\.([^\.])*') __re_two_ampersands = re.compile ('(&&)') __re_first_segment = re.compile ('([^.]*).*') __re_first_group = re.compile (r'[^.]*\.(.*)') +_ignore_toolset_requirements = '--ignore-toolset-requirements' not in sys.argv # Flag is a mechanism to set a value # A single toolset flag. Specifies that when certain @@ -393,10 +395,9 @@ def add_requirements(requirements): be conditional or indirect conditional.""" assert is_iterable_typed(requirements, basestring) - #if ! $(.ignore-requirements) - #{ - __requirements.extend(requirements) - #} + if _ignore_toolset_requirements: + __requirements.extend(requirements) + # Make toolset 'toolset', defined in a module of the same name, # inherit from 'base' diff --git a/src/build_system.py b/src/build_system.py index b5a3b2775..9d7e0d395 100644 --- a/src/build_system.py +++ b/src/build_system.py @@ -8,6 +8,15 @@ # 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 sys +import re + +import bjam + +# set this early on since some of the following modules +# require looking at the sys.argv +sys.argv = bjam.variable("ARGV") from b2.build.engine import Engine @@ -16,13 +25,11 @@ from b2.util.path import glob from b2.build import feature, property_set import b2.build.virtual_target from b2.build.targets import ProjectTarget -from b2.util.sequence import unique import b2.build.build_request from b2.build.errors import ExceptionWithUserContext import b2.tools.common from b2.build.toolset import using -import b2.build.project as project import b2.build.virtual_target as virtual_target import b2.build.build_request as build_request @@ -32,13 +39,6 @@ from b2.manager import get_manager from b2.util import cached from b2.util import option - -import bjam - -import os -import sys -import re - ################################################################################ # # Module global data. @@ -421,8 +421,6 @@ def should_clean_project(project): def main(): - sys.argv = bjam.variable("ARGV") - # FIXME: document this option. if "--profiling" in sys.argv: import cProfile From cb8402239d121ac34a8e3e6ee29d1e1ff60ece0a Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:50:04 -0500 Subject: [PATCH 081/158] Remove unnecesary comments in build_system.py --- src/build_system.py | 185 -------------------------------------------- 1 file changed, 185 deletions(-) diff --git a/src/build_system.py b/src/build_system.py index 9d7e0d395..96dca751b 100644 --- a/src/build_system.py +++ b/src/build_system.py @@ -622,191 +622,6 @@ def main_real(): for t in virtual_targets: actual_targets.append(t.actualize()) - - # FIXME: restore -## # If XML data output has been requested prepare additional rules and targets -## # so we can hook into Jam to collect build data while its building and have -## # it trigger the final XML report generation after all the planned targets -## # have been built. -## if $(.out-xml) -## { -## # Get a qualified virtual target name. -## rule full-target-name ( target ) -## { -## local name = [ $(target).name ] ; -## local project = [ $(target).project ] ; -## local project-path = [ $(project).get location ] ; -## return $(project-path)//$(name) ; -## } - -## # Generate an XML file containing build statistics for each constituent. -## # -## rule out-xml ( xml-file : constituents * ) -## { -## # Prepare valid XML header and footer with some basic info. -## local nl = " -## " ; -## local jam = [ version.jam ] ; -## local os = [ modules.peek : OS OSPLAT JAMUNAME ] "" ; -## local timestamp = [ modules.peek : JAMDATE ] ; -## local cwd = [ PWD ] ; -## local command = $(.sys.argv) ; -## local bb-version = [ version.boost-build ] ; -## .header on $(xml-file) = -## "" -## "$(nl)" -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## ; -## .footer on $(xml-file) = -## "$(nl)" ; - -## # Generate the target dependency graph. -## .contents on $(xml-file) += -## "$(nl) " ; -## for local t in [ virtual-target.all-targets ] -## { -## local action = [ $(t).action ] ; -## if $(action) -## # If a target has no action, it has no dependencies. -## { -## local name = [ full-target-name $(t) ] ; -## local sources = [ $(action).sources ] ; -## local dependencies ; -## for local s in $(sources) -## { -## dependencies += [ full-target-name $(s) ] ; -## } - -## local path = [ $(t).path ] ; -## local jam-target = [ $(t).actual-name ] ; - -## .contents on $(xml-file) += -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " -## ; -## } -## } -## .contents on $(xml-file) += -## "$(nl) " ; - -## # Build $(xml-file) after $(constituents). Do so even if a -## # constituent action fails and regenerate the xml on every bjam run. -## INCLUDES $(xml-file) : $(constituents) ; -## ALWAYS $(xml-file) ; -## __ACTION_RULE__ on $(xml-file) = build-system.out-xml.generate-action ; -## out-xml.generate $(xml-file) ; -## } - -## # The actual build actions are here; if we did this work in the actions -## # clause we would have to form a valid command line containing the -## # result of @(...) below (the name of the XML file). -## # -## rule out-xml.generate-action ( args * : xml-file -## : command status start end user system : output ? ) -## { -## local contents = -## [ on $(xml-file) return $(.header) $(.contents) $(.footer) ] ; -## local f = @($(xml-file):E=$(contents)) ; -## } - -## # Nothing to do here; the *real* actions happen in -## # out-xml.generate-action. -## actions quietly out-xml.generate { } - -## # Define the out-xml file target, which depends on all the targets so -## # that it runs the collection after the targets have run. -## out-xml $(.out-xml) : $(actual-targets) ; - -## # Set up a global __ACTION_RULE__ that records all the available -## # statistics about each actual target in a variable "on" the --out-xml -## # target. -## # -## rule out-xml.collect ( xml-file : target : command status start end user -## system : output ? ) -## { -## local nl = " -## " ; -## # Open the action with some basic info. -## .contents on $(xml-file) += -## "$(nl) " ; - -## # If we have an action object we can print out more detailed info. -## local action = [ on $(target) return $(.action) ] ; -## if $(action) -## { -## local action-name = [ $(action).action-name ] ; -## local action-sources = [ $(action).sources ] ; -## local action-props = [ $(action).properties ] ; - -## # The qualified name of the action which we created the target. -## .contents on $(xml-file) += -## "$(nl) " ; - -## # The sources that made up the target. -## .contents on $(xml-file) += -## "$(nl) " ; -## for local source in $(action-sources) -## { -## local source-actual = [ $(source).actual-name ] ; -## .contents on $(xml-file) += -## "$(nl) " ; -## } -## .contents on $(xml-file) += -## "$(nl) " ; - -## # The properties that define the conditions under which the -## # target was built. -## .contents on $(xml-file) += -## "$(nl) " ; -## for local prop in [ $(action-props).raw ] -## { -## local prop-name = [ MATCH ^<(.*)>$ : $(prop:G) ] ; -## .contents on $(xml-file) += -## "$(nl) " ; -## } -## .contents on $(xml-file) += -## "$(nl) " ; -## } - -## local locate = [ on $(target) return $(LOCATE) ] ; -## locate ?= "" ; -## .contents on $(xml-file) += -## "$(nl) " -## "$(nl) " -## "$(nl) " -## "$(nl) " ; -## .contents on $(xml-file) += -## "$(nl) " ; -## } - -## # When no __ACTION_RULE__ is set "on" a target, the search falls back to -## # the global module. -## module -## { -## __ACTION_RULE__ = build-system.out-xml.collect -## [ modules.peek build-system : .out-xml ] ; -## } - -## IMPORT -## build-system : -## out-xml.collect -## out-xml.generate-action -## : : -## build-system.out-xml.collect -## build-system.out-xml.generate-action -## ; -## } - j = option.get("jobs") if j: bjam.call("set-variable", 'PARALLELISM', j) From 0e164d20d28aff876fb0b0a9a071160469d7f9ed Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:01:44 -0500 Subject: [PATCH 082/158] Fix inconsistency with in builtin.py. --- src/tools/builtin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/builtin.py b/src/tools/builtin.py index f49d41e40..85595d93c 100644 --- a/src/tools/builtin.py +++ b/src/tools/builtin.py @@ -147,7 +147,7 @@ def register_globals (): feature.feature ('exception-handling', ['on', 'off'], ['propagated']) # Whether there is support for asynchronous EH (e.g. catching SEGVs). - feature.feature ('asynch-exceptions', ['on', 'off'], ['propagated']) + feature.feature ('asynch-exceptions', ['off', 'on'], ['propagated']) # Whether all extern "C" functions are considered nothrow by default. feature.feature ('extern-c-nothrow', ['off', 'on'], ['propagated']) From a216a9a2c87586457c1565a06eef0b0a4c615488 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:02:17 -0500 Subject: [PATCH 083/158] Set CScanner as scanner for H and HPP types. --- src/tools/builtin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/builtin.py b/src/tools/builtin.py index 85595d93c..03f3fb34d 100644 --- a/src/tools/builtin.py +++ b/src/tools/builtin.py @@ -403,6 +403,8 @@ class CScanner (scanner.Scanner): scanner.register (CScanner, 'include') type.set_scanner ('CPP', CScanner) type.set_scanner ('C', CScanner) +type.set_scanner('H', CScanner) +type.set_scanner('HPP', CScanner) # Ported to trunk@47077 class LibGenerator (generators.Generator): From 593f615a1aee9876678d3c504d1b867d11f9e4d1 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:03:48 -0500 Subject: [PATCH 084/158] Prevent LinkingGenerator from direclty modifying its source list. --- src/tools/builtin.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/builtin.py b/src/tools/builtin.py index 03f3fb34d..ff4c50ccb 100644 --- a/src/tools/builtin.py +++ b/src/tools/builtin.py @@ -600,6 +600,8 @@ class LinkingGenerator (generators.Generator): assert isinstance(prop_set, property_set.PropertySet) assert is_iterable_typed(sources, virtual_target.VirtualTarget) + # create a copy since sources is being modified + sources = list(sources) sources.extend(prop_set.get('')) # Add properties for all searched libraries From aa42913e08720c2654e14ad62fd512a581a9224d Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:05:26 -0500 Subject: [PATCH 085/158] Finish porting the ArchivingGenerator. --- src/tools/builtin.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/tools/builtin.py b/src/tools/builtin.py index ff4c50ccb..d748589d0 100644 --- a/src/tools/builtin.py +++ b/src/tools/builtin.py @@ -733,11 +733,27 @@ class ArchiveGenerator (generators.Generator): generators.Generator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) def run (self, project, name, prop_set, sources): - sources += prop_set.get ('') + assert isinstance(project, targets.ProjectTarget) + assert isinstance(name, basestring) or name is None + assert isinstance(prop_set, property_set.PropertySet) + assert is_iterable_typed(sources, virtual_target.VirtualTarget) + + # create a copy since this modifies the sources list + sources = list(sources) + sources.extend(prop_set.get('')) result = generators.Generator.run (self, project, name, prop_set, sources) - return result + usage_requirements = [] + link = prop_set.get('') + if 'static' in link: + for t in sources: + if type.is_derived(t.type(), 'LIB'): + usage_requirements.append(property.Property('', t)) + + usage_requirements = property_set.create(usage_requirements) + + return usage_requirements, result def register_archiver(id, source_types, target_types, requirements): From 8f0b57e54e03479348fe5a681d528d90c29495b0 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:06:46 -0500 Subject: [PATCH 086/158] Fix cast() rule. Previously, only the TYPE was allowed and not the type's rule. This brings the Python port up to date with Jam. --- src/tools/cast.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/cast.py b/src/tools/cast.py index 0d21edb0b..cf1a87627 100644 --- a/src/tools/cast.py +++ b/src/tools/cast.py @@ -25,7 +25,7 @@ # > cast, as defining a new target type + generator for that type is somewhat # > simpler than defining a main target rule. -from b2.build import targets, virtual_target, property_set +from b2.build import targets, virtual_target, property_set, type as type_ from b2.manager import get_manager from b2.util import bjam_signature, is_iterable_typed @@ -52,6 +52,7 @@ class CastTargetClass(targets.TypedTarget): return property_set.empty(), result + @bjam_signature((["name", "type"], ["sources", "*"], ["requirements", "*"], ["default_build", "*"], ["usage_requirements", "*"])) def cast(name, type, sources, requirements, default_build, usage_requirements): @@ -61,8 +62,11 @@ def cast(name, type, sources, requirements, default_build, usage_requirements): project = get_manager().projects().current() + real_type = type_.type_from_rule_name(type) + if not real_type: + real_type = type return t.main_target_alternative( - CastTargetClass(name, project, type, + CastTargetClass(name, project, real_type, t.main_target_sources(sources, name), t.main_target_requirements(requirements, project), t.main_target_default_build(default_build, project), From d5a07dcdb30c302813eaae55faa93569410710d6 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:09:33 -0500 Subject: [PATCH 087/158] Fix get_invocation_command_nodefault(). It was possible for command to be None. Thus, calling ' '.join(None) directly would error out. --- src/tools/common.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/tools/common.py b/src/tools/common.py index 18ea0542b..8bf33a063 100644 --- a/src/tools/common.py +++ b/src/tools/common.py @@ -314,9 +314,8 @@ def get_invocation_command_nodefault( #FIXME #ECHO "warning: initialized from" [ errors.nearest-user-location ] command = [] - command = ' '.join(command) - - assert(isinstance(command, str)) + if command: + command = ' '.join(command) return command From 2371e387a0abc775fb0104b4ebb93a57ecd946d6 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:10:43 -0500 Subject: [PATCH 088/158] Make the command line outputs like that of Jam. --- src/tools/common.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tools/common.py b/src/tools/common.py index 8bf33a063..4c8a9dabd 100644 --- a/src/tools/common.py +++ b/src/tools/common.py @@ -541,9 +541,16 @@ def prepend_path_variable_command(variable, paths): """ assert isinstance(variable, basestring) assert is_iterable_typed(paths, basestring) + return path_variable_setting_command( + variable, paths + [expand_variable(variable)]) + + +def expand_variable(variable): + """Produce a string that expands the shell variable.""" + if os.name == 'nt': + return '%{}%'.format(variable) + return '${%s}' % variable - return path_variable_setting_command(variable, - paths + os.environ.get(variable, "").split(os.pathsep)) def file_creation_command(): """ From b4b5e3179e906f79943b09831515b91de2cb9606 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:19:31 -0500 Subject: [PATCH 089/158] Clean up common.MkDir in common.py. --- src/tools/common.py | 54 +++++++++++---------------------------------- 1 file changed, 13 insertions(+), 41 deletions(-) diff --git a/src/tools/common.py b/src/tools/common.py index 4c8a9dabd..aad123a9b 100644 --- a/src/tools/common.py +++ b/src/tools/common.py @@ -581,10 +581,7 @@ def mkdir(engine, target): __mkdir_set.add(target) # Schedule the mkdir build action. - if os_name() == 'NT': - engine.set_update_action("common.MkDir1-quick-fix-for-windows", target, []) - else: - engine.set_update_action("common.MkDir1-quick-fix-for-unix", target, []) + engine.set_update_action("common.MkDir", target, []) # Prepare a Jam 'dirs' target that can be used to make the build only # construct all the target directories. @@ -822,62 +819,37 @@ def runtime_tag(name, target_type, prop_set ): return tag -## TODO: -##rule __test__ ( ) -##{ -## import assert ; -## -## local nl = " -##" ; -## -## local save-os = [ modules.peek os : .name ] ; -## -## modules.poke os : .name : LINUX ; -## -## assert.result "PATH=foo:bar:baz$(nl)export PATH$(nl)" -## : path-variable-setting-command PATH : foo bar baz ; -## -## assert.result "PATH=foo:bar:$PATH$(nl)export PATH$(nl)" -## : prepend-path-variable-command PATH : foo bar ; -## -## modules.poke os : .name : NT ; -## -## assert.result "set PATH=foo;bar;baz$(nl)" -## : path-variable-setting-command PATH : foo bar baz ; -## -## assert.result "set PATH=foo;bar;%PATH%$(nl)" -## : prepend-path-variable-command PATH : foo bar ; -## -## modules.poke os : .name : $(save-os) ; -##} - def init(manager): + global __RM, __CP, __IGNORE, __LN engine = manager.engine() - engine.register_action("common.MkDir1-quick-fix-for-unix", 'mkdir -p "$(<)"') - engine.register_action("common.MkDir1-quick-fix-for-windows", 'if not exist "$(<)\\" mkdir "$(<)"') - + # register the make() and alias() rules globally import b2.tools.make import b2.build.alias - global __RM, __CP, __IGNORE, __LN + windows_hack = '' # ported from trunk@47281 if os_name() == 'NT': __RM = 'del /f /q' - __CP = 'copy' + __CP = 'copy /b' + windows_hack = '+ this-file-does-not-exist-A698EE7806899E69' __IGNORE = '2>nul >nul & setlocal' __LN = __CP #if not __LN: # __LN = CP + MKDIR = 'if not exist "$(<)\\" mkdir "$(<)"' else: __RM = 'rm -f' __CP = 'cp' __IGNORE = '' __LN = 'ln' + MKDIR = 'mkdir -p "$(<)"' - engine.register_action("common.Clean", __RM + ' "$(>)"', - flags=['piecemeal', 'together', 'existing']) - engine.register_action("common.copy", __CP + ' "$(>)" "$(<)"') + engine.register_action("common.MkDir", MKDIR + __IGNORE) + + engine.register_action( + "common.Clean", __RM + ' "$(>)"', flags=['piecemeal', 'together', 'existing']) + engine.register_action("common.copy", '{} "$(>)" {} "$(<)"'.format(__CP, windows_hack)) engine.register_action("common.RmTemps", __RM + ' "$(>)" ' + __IGNORE, flags=['quietly', 'updated', 'piecemeal', 'together']) From eb097ad804eefe9bb91d1bf00d70bcde9c2731b6 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:23:33 -0500 Subject: [PATCH 090/158] Fix options bug in gcc.py --- src/tools/gcc.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/tools/gcc.py b/src/tools/gcc.py index bc810e489..498008dc0 100644 --- a/src/tools/gcc.py +++ b/src/tools/gcc.py @@ -103,11 +103,13 @@ def init(version = None, command = None, options = None): # The command. command = to_seq(common.get_invocation_command('gcc', 'g++', command)) # The root directory of the tool install. - root = feature.get_values('', options) ; + root = feature.get_values('', options) + root = root[0] if root else '' # The bin directory where to find the command to execute. bin = None # The flavor of compiler. flavor = feature.get_values('', options) + flavor = flavor[0] if flavor else '' # Autodetect the root and bin dir if not given. if command: if not bin: From 1fee45565676643b9b9695ccdcbcc6bab6f00c08 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:24:10 -0500 Subject: [PATCH 091/158] Fix function called with wrong type in gcc.py. --- src/tools/gcc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/gcc.py b/src/tools/gcc.py index 498008dc0..b343a6d4f 100644 --- a/src/tools/gcc.py +++ b/src/tools/gcc.py @@ -200,7 +200,7 @@ def init(version = None, command = None, options = None): # objects, so configure that. rc_command = common.get_invocation_command('gcc', 'as', [], [bin], path_last=True) rc_type = 'null' - rc.configure(rc_command, condition, '' + rc_type) + rc.configure([rc_command], condition, ['' + rc_type]) ###if [ os.name ] = NT ###{ From e50815353e81d3b12ad9cca0578ffe88637f38a1 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:24:36 -0500 Subject: [PATCH 092/158] Add preprocessor support in gcc.py/ --- src/tools/gcc.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/tools/gcc.py b/src/tools/gcc.py index b343a6d4f..270ca97b6 100644 --- a/src/tools/gcc.py +++ b/src/tools/gcc.py @@ -211,6 +211,8 @@ def init(version = None, command = None, options = None): #FIXME: when register_c_compiler is moved to # generators, these should be updated +builtin.register_c_compiler('gcc.compile.c++.preprocess', ['CPP'], ['PREPROCESSED_CPP'], ['gcc']) +builtin.register_c_compiler('gcc.compile.c.preprocess', ['C'], ['PREPROCESSED_C'], ['gcc']) builtin.register_c_compiler('gcc.compile.c++', ['CPP'], ['OBJ'], ['gcc']) builtin.register_c_compiler('gcc.compile.c', ['C'], ['OBJ'], ['gcc']) builtin.register_c_compiler('gcc.compile.asm', ['ASM'], ['OBJ'], ['gcc']) @@ -378,6 +380,24 @@ engine.register_action( function=gcc_compile_c, bound_list=['PCH_FILE']) +engine.register_action( + 'gcc.compile.c++.preprocess', + function=gcc_compile_cpp, + bound_list=['PCH_FILE'], + command=""" + $(CONFIG_COMMAND) $(LANG) -ftemplate-depth-$(TEMPLATE_DEPTH) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" "$(>:W)" -E >"$(<:W)" + """ +) + +engine.register_action( + 'gcc.compile.c.preprocess', + function=gcc_compile_c, + bound_list=['PCH_FILE'], + command=""" + $(CONFIG_COMMAND) $(LANG) $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(PCH_FILE:D)" -I"$(INCLUDES)" "$(>)" -E >$(<) + """ +) + def gcc_compile_asm(targets, sources, properties): get_manager().engine().set_target_variable(targets, 'LANG', '-x assembler-with-cpp') From 643bc6f410567ecc8259ecac00760da9b204edf2 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:25:59 -0500 Subject: [PATCH 093/158] Fix toolset.flags() call for 'mc.compile' in mc.py. --- src/tools/mc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/mc.py b/src/tools/mc.py index 9992c36c1..d8b970194 100644 --- a/src/tools/mc.py +++ b/src/tools/mc.py @@ -34,7 +34,7 @@ feature('mc-set-customer-bit', ['no', 'yes'], ['free']) flags('mc.compile', 'MCFLAGS', ['ansi'], ['-a']) flags('mc.compile', 'MCFLAGS', ['unicode'], ['-u']) -flags('mc.compile', 'MCFLAGS', ['ansi'], '-A') +flags('mc.compile', 'MCFLAGS', ['ansi'], ['-A']) flags('mc.compile', 'MCFLAGS', ['unicode'], ['-U']) flags('mc.compile', 'MCFLAGS', ['no'], []) flags('mc.compile', 'MCFLAGS', ['yes'], ['-c']) From aa49e0a1416bc045d86ea9679cb9c014d250fa54 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:26:56 -0500 Subject: [PATCH 094/158] Fix msvc.preprocess action name in msvc.py. --- src/tools/msvc.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/msvc.py b/src/tools/msvc.py index c3ac2034b..fd7ac8a82 100644 --- a/src/tools/msvc.py +++ b/src/tools/msvc.py @@ -380,12 +380,12 @@ def setup_preprocess_c_cpp_action(targets, sources, properties): return 'preprocess-c-c++' register_setup_action( - 'msvc.preprocess.c', + 'msvc.compile.c.preprocess', setup_preprocess_c_cpp_action, function=compile_c_preprocess) register_setup_action( - 'msvc.preprocess.c++', + 'msvc.compile.c++.preprocess', setup_preprocess_c_cpp_action, function=compile_cpp_preprocess) From aaf918788359bb77a5d90f1c784dbe1638fd8d31 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:27:24 -0500 Subject: [PATCH 095/158] Add support for faster MSVC Startup script. --- src/tools/msvc.py | 130 +++++++++++++++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 29 deletions(-) diff --git a/src/tools/msvc.py b/src/tools/msvc.py index fd7ac8a82..de184dbd3 100644 --- a/src/tools/msvc.py +++ b/src/tools/msvc.py @@ -623,6 +623,102 @@ def auto_detect_toolset_versions(): register_configuration(i,default_path(i)) +def maybe_rewrite_setup(toolset, setup_script, setup_options, version, rewrite_setup='off'): + """ + 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. + """ + result = '"{}" {}'.format(setup_script, setup_options) + + # At the moment we only know how to rewrite scripts with cmd shell. + if os.name == 'nt' and rewrite_setup != 'off': + basename = os.path.basename(setup_script) + filename, _ = os.path.splitext(basename) + setup_script_id = 'b2_{}_{}_{}'.format(toolset, version, filename) + if setup_options: + setup_script_id = '{}_{}'.format(setup_script_id, setup_options) + + tempdir = os.environ.get('TEMP') + replacement = os.path.join(tempdir, setup_script_id + '.cmd') + if rewrite_setup == 'always' or not os.path.exists(replacement): + import subprocess + # call the setup script and print the environment after doing so + p = subprocess.Popen([ + setup_script, setup_options, '>', 'nul', '&&', 'set', + ], stdout=subprocess.PIPE, shell=True + ) + stdout, _ = p.communicate() + + diff_vars = [] + for var in stdout.splitlines(): + # returns a tuple of ('var-name', '=', 'value'). + # partition is being used here (over something like .split()) + # for two reasons: + # 1) an environment variable may have a value that contains an '='; + # .partition() will still return the correct key and value pair. + # 2) if the line doesn't contain an '=' at all, then the returned + # tuple will contain only empty strings rather than raising + # an exception. + key, _, value = var.partition('=') + # os.environ handles casing differences here. Usually the + # call to "set" above will produce pascal-cased environment + # variable names, so a normal python dict can't be used here. + # check for the existence of key in case the partitioning() above + # returned an empty key value pair. + if key and os.environ.get(key) != value: + diff_vars.append('SET {}={}'.format(key, value)) + + if diff_vars: + with open(replacement, 'wb') as f: + f.write(os.linesep.join(diff_vars)) + + result = '"{}"'.format(replacement) + else: + result = '"{}"'.format(replacement) + + return result + + +def generate_setup_cmd(version, command, parent, options, cpu, global_setup, + default_global_setup_options, default_setup): + setup_prefix = "call " + setup_suffix = """ >nul\n""" + if on_cygwin(): + setup_prefix = "cmd.exe /S /C call " + setup_suffix = " \">nul\" \"&&\" " + + setup_options = '' + setup_cpu = feature.get_values(''.format(cpu), options) + + if not setup_cpu: + if global_setup: + setup_cpu = 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(''.format(cpu),options) + if not setup_options: + setup_options = default_global_setup_options[cpu] + else: + setup_cpu = locate_default_setup(command, parent, default_setup[cpu]) + else: + setup_cpu = setup_cpu[0] + + # Cygwin to Windows path translation. + # setup-$(c) = "\""$(setup-$(c):W)"\"" ; + + # Append setup options to the setup name and add the final setup + # prefix & suffix. + rewrite = feature.get_values('', options) + rewrite = rewrite[0] if rewrite else '' + setup = maybe_rewrite_setup( + 'msvc', setup_cpu, setup_options, version, rewrite) + return '{}{}{}'.format(setup_prefix, setup, setup_suffix) + + # Worker rule for toolset version configuration. Takes an explicit version id or # nothing in case it should configure the default toolset version (the first # registered one or a new 'default' one in case no toolset versions have been @@ -787,39 +883,15 @@ def configure_really(version=None, options=[]): elif somehow_detect_the_itanium_platform: default_global_setup_options[ 'ia64' ] = 'ia64' - setup_prefix = "call " - setup_suffix = """ >nul\n""" - if on_cygwin(): - setup_prefix = "cmd.exe /S /C call " - setup_suffix = " \">nul\" \"&&\" " - for c in cpu: - setup_options = None - setup_cpu = feature.get_values(''.format(c),options) - - if not setup_cpu: - if global_setup: - setup_cpu = 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(''.format(c),options) - if not setup_options: - setup_options = default_global_setup_options[ c ] - else: - setup_cpu = locate_default_setup(command, parent, default_setup[ 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_scripts[ c ] = '{}"{}" {}{}'.format(setup_prefix, setup_cpu, setup_options, setup_suffix) + setup_scripts[c] = generate_setup_cmd( + version, command, parent, options, c, global_setup, + default_global_setup_options, default_setup + ) # Get tool names (if any) and finish setup. compiler = feature.get_values("", options) - if not compiler: - compiler = "cl" + compiler = compiler[0] if compiler else 'cl' linker = feature.get_values("", options) if not linker: From 359f21c237a1b80e7f44dc7b5b3530bbb8317498 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:27:44 -0500 Subject: [PATCH 096/158] Fix incorrect type passed in msvc.py --- src/tools/msvc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/msvc.py b/src/tools/msvc.py index de184dbd3..baa57e831 100644 --- a/src/tools/msvc.py +++ b/src/tools/msvc.py @@ -1039,7 +1039,7 @@ def register_toolset_really(): feature.extend('toolset', ['msvc']) # Intel and msvc supposedly have link-compatible objects. - feature.subfeature( 'toolset', 'msvc', 'vendor', 'intel', ['propagated', 'optional']) + feature.subfeature( 'toolset', 'msvc', 'vendor', ['intel'], ['propagated', 'optional']) # Inherit MIDL flags. toolset.inherit_flags('msvc', 'midl') From 404ae8a89d8c35a1e64f1742c46d3235ec4bbba8 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:28:48 -0500 Subject: [PATCH 097/158] Incorrect type passed in rc.py --- src/tools/rc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rc.py b/src/tools/rc.py index 79a373e8b..d9d840ffe 100644 --- a/src/tools/rc.py +++ b/src/tools/rc.py @@ -68,7 +68,7 @@ def configure (command = None, condition = None, options = None): if command and condition and rc_type: flags('rc.compile.resource', '.RC', condition, command) - flags('rc.compile.resource', '.RC_TYPE', condition, rc_type.lower()) + flags('rc.compile.resource', '.RC_TYPE', condition, [rc_type.lower()]) flags('rc.compile.resource', 'DEFINES', [], ['']) flags('rc.compile.resource', 'INCLUDES', [], ['']) if debug(): From 83de3c5827f138ea1ae752c9ff22ee00480e2d33 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:29:36 -0500 Subject: [PATCH 098/158] Fix call to alias() in testing.py. --- src/tools/testing.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/testing.py b/src/tools/testing.py index 868905a05..b634bea28 100644 --- a/src/tools/testing.py +++ b/src/tools/testing.py @@ -113,7 +113,7 @@ def make_test(target_type, sources, requirements, target_name=None): # The alias to the real target, per period replacement above. if real_name != target_name: - get_manager().projects().project_rules().all_names_["alias"]( + get_manager().projects().project_rules().rules["alias"]( target_name, [t]) # Remember the test (for --dump-tests). A good way would be to collect all From 8ee37e2afe64477548ccad7e8bd9afc6688f756d Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:30:33 -0500 Subject: [PATCH 099/158] Fix asm.set_asm_type() return value. --- src/tools/types/asm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/types/asm.py b/src/tools/types/asm.py index a4b4aee61..d9a30152e 100644 --- a/src/tools/types/asm.py +++ b/src/tools/types/asm.py @@ -27,7 +27,7 @@ def set_asm_type(type_, sources, name=''): name = name if name else _project_types[project.name() + type_] type_ += '.asm' - cast(name, type_.upper(), sources, [], [], []) + return cast(name, type_.upper(), sources, [], [], []) PROJECT_REGISTRY.add_rule("set-asm-type", set_asm_type) From 1080608e1187565c58d6a77387e69c7ee6b61abf Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:31:23 -0500 Subject: [PATCH 100/158] Remove CScanner from cpp.py as it was already declared in builtin.py --- src/tools/types/cpp.py | 76 +----------------------------------------- 1 file changed, 1 insertion(+), 75 deletions(-) diff --git a/src/tools/types/cpp.py b/src/tools/types/cpp.py index 22f4dece4..50797bae4 100644 --- a/src/tools/types/cpp.py +++ b/src/tools/types/cpp.py @@ -1,84 +1,10 @@ # 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 as type_ -import bjam - -from b2.build import type as type_, scanner -from b2.manager import get_manager -from b2.util.utility import replace_grist - - -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) From 1c315cf87be832211a9cbbbd284503be48678ac6 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:32:54 -0500 Subject: [PATCH 101/158] Update unix.ArchiveGenerator.run(). --- src/tools/unix.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/tools/unix.py b/src/tools/unix.py index 681a87202..f66ed16f7 100644 --- a/src/tools/unix.py +++ b/src/tools/unix.py @@ -46,8 +46,13 @@ class UnixArchiveGenerator (builtin.ArchiveGenerator): builtin.ArchiveGenerator.__init__ (self, id, composing, source_types, target_types_and_names, requirements) def run (self, project, name, prop_set, sources): + from b2.build.property_set import PropertySet result = builtin.ArchiveGenerator.run(self, project, name, prop_set, sources) - set_library_order(project.manager(), sources, prop_set, result) + if result and isinstance(result[0], PropertySet): + _, targets = result + else: + targets = result + set_library_order(project.manager(), sources, prop_set, targets) return result class UnixSearchedLibGenerator (builtin.SearchedLibGenerator): From a56aca921290ad49e25d17764d5e5dfebf73208f Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:33:43 -0500 Subject: [PATCH 102/158] Fix path.glob(). --- src/util/path.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util/path.py b/src/util/path.py index 7b9032073..e451c2cbe 100644 --- a/src/util/path.py +++ b/src/util/path.py @@ -881,7 +881,7 @@ def glob_tree(roots, patterns, exclude_patterns=None): exclude_patterns = [] result = glob(roots, patterns, exclude_patterns) - subdirs = [s for s in glob(roots, ["*"]) if s != "." and s != ".." and os.path.isdir(s)] + subdirs = [s for s in glob(roots, ["*"], exclude_patterns) if s != "." and s != ".." and os.path.isdir(s)] if subdirs: result.extend(glob_tree(subdirs, patterns, exclude_patterns)) From 88f567f2ff31f64bcc5e9ca0a4016e3ef3e72abc Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:34:51 -0500 Subject: [PATCH 103/158] Prevent backreferences from breaking regex.transform(). --- src/util/regex.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/util/regex.py b/src/util/regex.py index 6348c6fb1..37eeb6d88 100644 --- a/src/util/regex.py +++ b/src/util/regex.py @@ -38,7 +38,16 @@ def replace(s, pattern, replacement): pattern (str): the search expression replacement (str): the string to replace each match with """ - return re.sub(pattern, replacement, s) + # the replacement string may contain invalid backreferences (like \1 or \g) + # which will cause python's regex to blow up. Since this should emulate + # the jam version exactly and the jam version didn't support + # backreferences, this version shouldn't either. re.sub + # allows replacement to be a callable; this is being used + # to simply return the replacement string and avoid the hassle + # of worrying about backreferences within the string. + def _replacement(matchobj): + return replacement + return re.sub(pattern, _replacement, s) @bjam_signature((['items', '*'], ['match'], ['replacement'])) From 0055072ad67aca00279c6700bf237beace8e76f1 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:37:12 -0500 Subject: [PATCH 104/158] Support passing --stacktrace to tests. --- test/BoostBuild.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/BoostBuild.py b/test/BoostBuild.py index 8c51cf05f..20a174568 100644 --- a/test/BoostBuild.py +++ b/test/BoostBuild.py @@ -453,6 +453,8 @@ class Tester(TestCmd.TestCmd): kw["program"].append("--ignore-toolset-requirements") if "--python" in sys.argv: kw["program"].append("--python") + if "--stacktrace" in sys.argv: + kw["program"].append("--stacktrace") kw["chdir"] = subdir self.last_program_invocation = kw["program"] build_time_start = time.time() From d7b2e0974c3db9cf11f293236c6e14e2ed9d7e00 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 22:52:38 -0500 Subject: [PATCH 105/158] Update gitignore to ignore *.pyo and b2/bjam.exe --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 77cbb38df..500fe4bcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ -*.pyc +*.py[co] /doc/bin /doc/html /b2 /bjam +/b2.exe +/bjam.exe /bin /bootstrap.log /test/test_results.txt From 67bafcd133976a858a5b781a045a0ca78545c427 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 23:37:43 -0500 Subject: [PATCH 106/158] Add LazyProperty class for delayed Property evaluation. --- src/build/property.py | 110 +++++++++++++++++++++++++++++--------- src/build/property_set.py | 42 ++++++++++++--- 2 files changed, 119 insertions(+), 33 deletions(-) diff --git a/src/build/property.py b/src/build/property.py index 72de89825..0c3ac44cf 100644 --- a/src/build/property.py +++ b/src/build/property.py @@ -9,12 +9,14 @@ import re import sys + from b2.util.utility import * from b2.build import feature from b2.util import sequence, qualify_jam_action, is_iterable_typed import b2.util.set from b2.manager import get_manager + __re_two_ampersands = re.compile ('&&') __re_comma = re.compile (',') __re_split_condition = re.compile ('(.*):(<.*)') @@ -23,14 +25,38 @@ __re_colon = re.compile (':') __re_has_condition = re.compile (r':<') __re_separate_condition_and_property = re.compile (r'(.*):(<.*)') -__not_applicable_feature='not-applicable-in-this-context' -feature.feature(__not_applicable_feature, [], ['free']) +_not_applicable_feature='not-applicable-in-this-context' +feature.feature(_not_applicable_feature, [], ['free']) __abbreviated_paths = False + +class PropertyMeta(type): + """ + This class exists to implement the isinstance() and issubclass() + hooks for the Property class. Since we've introduce the concept of + a LazyProperty, isinstance(p, Property) will fail when p is a LazyProperty. + Implementing both __instancecheck__ and __subclasscheck__ will allow + LazyProperty instances to pass the isinstance() and issubclass check for + the Property class. + """ + @staticmethod + def check(obj): + return (hasattr(obj, 'feature') and + hasattr(obj, 'value') and + hasattr(obj, 'condition')) + + def __instancecheck__(self, instance): + return self.check(instance) + + def __subclasscheck__(self, subclass): + return self.check(subclass) + + class Property(object): - __slots__ = ('_feature', '_value', '_condition') + __slots__ = ('_feature', '_value', '_condition', '_to_raw', '_hash') + __metaclass__ = PropertyMeta def __init__(self, f, value, condition = []): if type(f) == type(""): @@ -69,6 +95,38 @@ class Property(object): (other._feature.name(), other._value, other._condition)) +class LazyProperty(object): + def __init__(self, feature_name, value, condition=None): + if condition is None: + condition = [] + + self.__property = Property( + feature.get(_not_applicable_feature), feature_name + value, condition=condition) + self.__name = feature_name + self.__value = value + self.__condition = condition + self.__feature = None + + def __getattr__(self, item): + if self.__feature is None: + try: + self.__feature = feature.get(self.__name) + self.__property = Property(self.__feature, self.__value, self.__condition) + except KeyError: + pass + return getattr(self.__property, item) + + def __hash__(self): + return hash(self.__property) + + def __str__(self): + return self.__property._to_raw + + def __cmp__(self, other): + return cmp((self._feature.name(), self._value, self._condition), + (other._feature.name(), other._value, other._condition)) + + def create_from_string(s, allow_condition=False,allow_missing_value=False): assert isinstance(s, basestring) assert isinstance(allow_condition, bool) @@ -89,17 +147,24 @@ def create_from_string(s, allow_condition=False,allow_missing_value=False): # FIXME: break dependency cycle from b2.manager import get_manager + if condition: + condition = [create_from_string(x) for x in condition.split(',')] + feature_name = get_grist(s) if not feature_name: if feature.is_implicit_value(s): f = feature.implied_feature(s) value = s + p = Property(f, value, condition=condition) else: raise get_manager().errors()("Invalid property '%s' -- unknown feature" % s) else: + value = get_value(s) + if not value and not allow_missing_value: + get_manager().errors()("Invalid property '%s' -- no value specified" % s) + if feature.valid(feature_name): - f = feature.get(feature_name) - value = get_value(s) + p = Property(feature.get(feature_name), value, condition=condition) else: # In case feature name is not known, it is wrong to do a hard error. # Feature sets change depending on the toolset. So e.g. @@ -112,17 +177,9 @@ def create_from_string(s, allow_condition=False,allow_missing_value=False): # The underlying cause for this problem is that python port Property # is more strict than its Jam counterpart and must always reference # a valid feature. - f = feature.get(__not_applicable_feature) - value = s + p = LazyProperty(feature_name, value, condition=condition) - if not value and not allow_missing_value: - get_manager().errors()("Invalid property '%s' -- no value specified" % s) - - - if condition: - condition = [create_from_string(x) for x in condition.split(',')] - - return Property(f, value, condition) + return p def create_from_strings(string_list, allow_condition=False): assert is_iterable_typed(string_list, basestring) @@ -279,17 +336,20 @@ def expand_subfeatures_in_conditions (properties): else: expanded = [] for c in p.condition(): + # It common that condition includes a toolset which + # was never defined, or mentiones subfeatures which + # were never defined. In that case, validation will + # only produce an spirious error, so don't validate. + expanded.extend(feature.expand_subfeatures ([c], True)) - if c.feature().name().startswith("toolset") or c.feature().name() == "os": - # It common that condition includes a toolset which - # was never defined, or mentiones subfeatures which - # were never defined. In that case, validation will - # only produce an spirious error, so don't validate. - expanded.extend(feature.expand_subfeatures ([c], True)) - else: - expanded.extend(feature.expand_subfeatures([c])) - - result.append(Property(p.feature(), p.value(), expanded)) + # we need to keep LazyProperties lazy + if isinstance(p, LazyProperty): + value = p.value() + feature_name = get_grist(value) + value = value.replace(feature_name, '') + result.append(LazyProperty(feature_name, value, condition=expanded)) + else: + result.append(Property(p.feature(), p.value(), expanded)) return result diff --git a/src/build/property_set.py b/src/build/property_set.py index d9a1bd97a..b5686bc85 100644 --- a/src/build/property_set.py +++ b/src/build/property_set.py @@ -207,6 +207,14 @@ class PropertySet: # A cache for already evaluated sets. self.evaluated_ = {} + # stores the list of LazyProperty instances. + # these are being kept separate from the normal + # Property instances so that when this PropertySet + # tries to return one of its attributes, it + # will then try to evaluate the LazyProperty instances + # first before returning. + self.lazy_properties = [] + for p in raw_properties: if not get_grist (p): raise BaseException ("Invalid property: '%s'" % p) @@ -220,7 +228,8 @@ class PropertySet: self.link_incompatible.append (p) for p in properties: - + if isinstance(p, property.LazyProperty): + self.lazy_properties.append(p) # A feature can be both incidental and free, # in which case we add it to incidental. if p.feature().incidental(): @@ -237,7 +246,7 @@ class PropertySet: if p.feature().dependency(): self.dependency_.append (p) - else: + elif not isinstance(p, property.LazyProperty): self.non_dependency_.append (p) @@ -247,7 +256,12 @@ class PropertySet: def raw (self): """ Returns the list of stored properties. """ - return self.all_raw_ + # create a new list due to the LazyProperties. + # this gives them a chance to evaluate to their + # true Property(). This approach is being + # taken since calculations should not be using + # PropertySet.raw() + return [p.to_raw() for p in self.all_] def __str__(self): return ' '.join(str(p) for p in self.all_) @@ -255,25 +269,35 @@ class PropertySet: def base (self): """ Returns properties that are neither incidental nor free. """ - return self.base_ + result = [p for p in self.lazy_properties + if not(p.feature().incidental() or p.feature().free())] + result.extend(self.base_) + return result def free (self): """ Returns free properties which are not dependency properties. """ - return self.free_ + result = [p for p in self.lazy_properties + if not p.feature().incidental() and p.feature().free()] + result.extend(self.free_) + return result def non_free(self): - return self.base_ + self.incidental_ + return self.base() + self.incidental() def dependency (self): """ Returns dependency properties. """ + result = [p for p in self.lazy_properties if p.feature().dependency()] + result.extend(self.dependency_) return self.dependency_ def non_dependency (self): """ Returns properties that are not dependencies. """ - return self.non_dependency_ + result = [p for p in self.lazy_properties if not p.feature().dependency()] + result.extend(self.non_dependency_) + return result def conditional (self): """ Returns conditional properties. @@ -288,7 +312,9 @@ class PropertySet: def incidental (self): """ Returns incidental properties. """ - return self.incidental_ + result = [p for p in self.lazy_properties if p.feature().incidental()] + result.extend(self.incidental_) + return result def refine (self, requirements): """ Refines this set's properties using the requirements passed as an argument. From 42e0899eedc0e6f408329ddc32505cbea71a42c0 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:04:24 -0500 Subject: [PATCH 107/158] Add bjam_signature() to feature.extend(). --- src/build/feature.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build/feature.py b/src/build/feature.py index a8abf6969..db487d69e 100644 --- a/src/build/feature.py +++ b/src/build/feature.py @@ -420,7 +420,7 @@ def expand_subfeatures(properties, dont_validate = False): # Now, the specific rule must be called, depending on the desired operation: # extend_feature # extend_subfeature - +@bjam_signature([['name'], ['values', '*']]) def extend (name, values): """ Adds the given values to the given feature. """ From f663fd8163c8ac75ccea4e2003615873ead13e7f Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:05:04 -0500 Subject: [PATCH 108/158] Update set_abbreviated_paths() to work from Jam. --- src/build/property.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/build/property.py b/src/build/property.py index 0c3ac44cf..4d1b192c5 100644 --- a/src/build/property.py +++ b/src/build/property.py @@ -198,6 +198,9 @@ reset () def set_abbreviated_paths(on=True): global __abbreviated_paths + if on == 'off': + on = False + on = bool(on) __abbreviated_paths = on From bb1fa52a2f8ece8a36b9c88cfea982e54db3b3e7 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:05:35 -0500 Subject: [PATCH 109/158] Set target location on metatargets. --- src/build/targets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/build/targets.py b/src/build/targets.py index 7b3025476..367385376 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -82,6 +82,7 @@ from virtual_target import Subvariant from b2.exceptions import * from b2.util.sequence import unique from b2.util import path, bjam_signature, safe_isinstance, is_iterable_typed +from b2.build import errors from b2.build.errors import user_error_checkpoint import b2.build.build_request as build_request @@ -308,6 +309,7 @@ class AbstractTarget: self.name_ = name self.project_ = project + self.location_ = errors.nearest_user_location() def manager (self): return self.manager_ From 51e665fc45db0653c08398173bb539cadb5c8a2e Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:07:01 -0500 Subject: [PATCH 110/158] Various fixes in targets.py --- src/build/targets.py | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/build/targets.py b/src/build/targets.py index 367385376..78a464ad1 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -156,6 +156,8 @@ class TargetRegistry: 'project' is the project where the main taret is to be declared.""" assert is_iterable_typed(specification, basestring) assert isinstance(project, ProjectTarget) + # create a copy since the list is being modified + specification = list(specification) specification.extend(toolset.requirements()) requirements = property_set.refine_from_user_input( @@ -529,8 +531,16 @@ class ProjectTarget (AbstractTarget): target_part = None if split: - project_part = split.group (1) - target_part = split.group (2) + project_part = split.group(1) + target_part = split.group(2) + if not target_part: + get_manager().errors()( + 'Project ID, "{}", is not a valid target reference. There should ' + 'be either a target name after the "//" or the "//" should be removed ' + 'from the target reference.' + .format(id) + ) + project_registry = self.project_.manager ().projects () @@ -615,7 +625,7 @@ class ProjectTarget (AbstractTarget): to the location of project. """ assert isinstance(name, basestring) - assert isinstance(value, basestring) + assert is_iterable_typed(value, basestring) assert isinstance(path, int) # will also match bools if path: l = self.location_ @@ -627,10 +637,10 @@ class ProjectTarget (AbstractTarget): # targets in config files, but that's for later. l = self.get('source-location') - value = os.path.join(l, value) + value = os.path.join(l, value[0]) # Now make the value absolute path. Constants should be in # platform-native form. - value = os.path.normpath(os.path.join(os.getcwd(), value)) + value = [os.path.normpath(os.path.join(os.getcwd(), value))] self.constants_[name] = value bjam.call("set-variable", self.project_module(), name, value) From 8c406a88cf70da63a1e566f500cde65732f375c4 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:07:54 -0500 Subject: [PATCH 111/158] Save best alternative on metatargets. This is useful for virtual target reporting to report which alternative was chosen. --- src/build/targets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/build/targets.py b/src/build/targets.py index 78a464ad1..4e8f8557f 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -670,6 +670,7 @@ class MainTarget (AbstractTarget): def __init__ (self, name, project): AbstractTarget.__init__ (self, name, project) self.alternatives_ = [] + self.best_alternative = None self.default_build_ = property_set.empty () def add_alternative (self, target): @@ -781,6 +782,7 @@ class MainTarget (AbstractTarget): """ assert isinstance(prop_set, property_set.PropertySet) best_alternative = self.__select_alternatives (prop_set, debug=0) + self.best_alternative = best_alternative if not best_alternative: # FIXME: revive. From 0228b8ed7dcc1a4152016dc7dac3af474eb2005a Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:09:02 -0500 Subject: [PATCH 112/158] Various fixes in toolset.py --- src/build/toolset.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/build/toolset.py b/src/build/toolset.py index 59ddd7378..25c3a5fe6 100644 --- a/src/build/toolset.py +++ b/src/build/toolset.py @@ -17,7 +17,7 @@ import bjam from b2.util import cached, qualify_jam_action, is_iterable_typed, is_iterable from b2.util.utility import * -from b2.util import bjam_signature +from b2.util import bjam_signature, sequence from b2.manager import get_manager __re_split_last_segment = re.compile (r'^(.+)\.([^\.])*') @@ -356,11 +356,11 @@ def __handle_flag_value (manager, value, ps): else: result.extend(value.split ('&&')) else: - result.append (ungristed) + result.append (value) else: result.append (value) - return result + return sequence.unique(result, stable=True) def __add_flag (rule_or_module, variable_name, condition, values): """ Adds a new flag setting with the specified values. From 4bbde8e2b803318154854eb9864545593fd82bf3 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:09:38 -0500 Subject: [PATCH 113/158] Fix duplicate virtual target error message. --- src/build/virtual_target.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/build/virtual_target.py b/src/build/virtual_target.py index 0ae214a25..be3d51ef3 100644 --- a/src/build/virtual_target.py +++ b/src/build/virtual_target.py @@ -218,10 +218,12 @@ class VirtualTargetRegistry: p2 = p2.raw () properties_removed = set.difference (p1, p2) - if not properties_removed: properties_removed = "none" + if not properties_removed: + properties_removed = ["none"] properties_added = set.difference (p2, p1) - if not properties_added: properties_added = "none" + if not properties_added: + properties_added = ["none"] # FIXME: Revive printing of real location. get_manager().errors()( @@ -230,13 +232,14 @@ class VirtualTargetRegistry: "created from '%s'\n" "another virtual target '%s'\n" "created from '%s'\n" - "added properties: '%s'\n" - "removed properties: '%s'\n" + "added properties:\n%s\n" + "removed properties:\n%s\n" % (actual_name, - self.actual_ [actual_name], "loc", #cmt1.location (), + self.actual_ [actual_name], cmt1.project().location(), virtual_target, - "loc", #cmt2.location (), - properties_added, properties_removed)) + cmt2.project().location(), + '\n'.join('\t' + p for p in properties_added), + '\n'.join('\t' + p for p in properties_removed))) else: self.actual_ [actual_name] = virtual_target From 0999a4f1ef81c3fa12b7c84a4bea3edbb816f689 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:59:24 -0500 Subject: [PATCH 114/158] Optimize CScanner in builtin.py --- src/tools/builtin.py | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/tools/builtin.py b/src/tools/builtin.py index d748589d0..ee6474b73 100644 --- a/src/tools/builtin.py +++ b/src/tools/builtin.py @@ -367,11 +367,21 @@ class CScanner (scanner.Scanner): return r'#[ \t]*include[ ]*(<(.*)>|"(.*)")' def process (self, target, matches, binding): + # since it's possible for this function to be called + # thousands to millions of times (depending on how many + # header files there are), as such, there are some + # optimizations that have been used here. Anything that + # is slightly out of the ordinary for Python code + # has been commented. + angle = [] + quoted = [] + for match in matches: + if '<' in match: + angle.append(match.strip('<>')) + elif '"' in match: + quoted.append(match.strip('"')) - angle = regex.transform (matches, "<(.*)>") - quoted = regex.transform (matches, '"(.*)"') - - g = str(id(self)) + g = id(self) b = os.path.normpath(os.path.dirname(binding[0])) # Attach binding of including file to included targets. @@ -382,23 +392,32 @@ class CScanner (scanner.Scanner): # We don't need this extra information for angle includes, # since they should not depend on including file (we can't # get literal "." in include path). - g2 = g + "#" + b + # Note: string interpolation is slightly faster + # than .format() + g2 = '<%s#%s>' % (g, b) + g = "<%s>" % g - g = "<" + g + ">" - g2 = "<" + g2 + ">" angle = [g + x for x in angle] quoted = [g2 + x for x in quoted] all = angle + quoted bjam.call("mark-included", target, all) + # each include in self.includes_ looks something like this: + # path/to/somewhere + # calling get_value(include) is super slow, + # calling .replace('', '') is much faster + # however, i[9:] is the fastest way of stripping off the "" + # substring. + include_paths = [i[9:] for i in self.includes_] + engine = get_manager().engine() - engine.set_target_variable(angle, "SEARCH", get_value(self.includes_)) - engine.set_target_variable(quoted, "SEARCH", [b] + get_value(self.includes_)) + engine.set_target_variable(angle, "SEARCH", include_paths) + engine.set_target_variable(quoted, "SEARCH", [b] + include_paths) # Just propagate current scanner to includes, in a hope # that includes do not change scanners. - get_manager().scanners().propagate(self, angle + quoted) + get_manager().scanners().propagate(self, all) scanner.register (CScanner, 'include') type.set_scanner ('CPP', CScanner) From e3b93cffcbddcd06f7a5aa03a7614261a963c32f Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:35:35 -0500 Subject: [PATCH 115/158] Optimize set.difference(). --- src/util/set.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/util/set.py b/src/util/set.py index f2239a021..98b1d17f5 100644 --- a/src/util/set.py +++ b/src/util/set.py @@ -10,13 +10,11 @@ from .utility import to_seq def difference (b, a): """ Returns the elements of B that are not in A. """ - assert is_iterable(b) - assert is_iterable(a) + a = set(a) result = [] - for element in b: - if not element in a: - result.append (element) - + for item in b: + if item not in a: + result.append(item) return result def intersection (set1, set2): From 42ffca9c1c0c21664e7eb0f02e9b44022e112ec7 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 17:36:30 -0500 Subject: [PATCH 116/158] Optimize replace_grist() and forward_slashes(). --- src/util/utility.py | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/util/utility.py b/src/util/utility.py index 162a57be4..ded3e5bcd 100644 --- a/src/util/utility.py +++ b/src/util/utility.py @@ -59,17 +59,28 @@ def replace_grist (features, new_grist): """ assert is_iterable_typed(features, basestring) or isinstance(features, basestring) assert isinstance(new_grist, basestring) - def replace_grist_one (name, new_grist): - split = __re_grist_and_value.match (name) - if not split: - return new_grist + name - else: - return new_grist + split.group (2) + # this function is used a lot in the build phase and the original implementation + # was extremely slow; thus some of the weird-looking optimizations for this function. + single_item = False + if isinstance(features, str): + features = [features] + single_item = True - if isinstance (features, str): - return replace_grist_one (features, new_grist) - else: - return [ replace_grist_one (feature, new_grist) for feature in features ] + result = [] + for feature in features: + # 'value' -> ('', 'value') + # 'something' -> ('something', '', '') + # 'msvc/value' -> ('', 'msvc/value') + grist, split, value = feature.partition('>') + # if a partition didn't occur, then grist is just 'something' + # set the value to be the grist + if not value and not split: + value = grist + result.append(new_grist + value) + + if single_item: + return result[0] + return result def get_value (property): """ Gets the value of a property, that is, the part following the grist, if any. @@ -124,7 +135,7 @@ def forward_slashes (s): """ Converts all backslashes to forward slashes. """ assert isinstance(s, basestring) - return __re_backslash.sub ('/', s) + return s.replace('\\', '/') def split_action_id (id): From 6f04175044c419e8a62c90b48576366f02904be7 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 23:46:33 -0500 Subject: [PATCH 117/158] Convert all Property and Feature gettters to attribute access. --- src/build/build_request.py | 2 +- src/build/feature.py | 252 +++++++++++++++--------------------- src/build/property.py | 88 ++++++------- src/build/property_set.py | 44 ++++--- src/build/targets.py | 23 ++-- src/build/toolset.py | 12 +- src/build/virtual_target.py | 2 +- src/tools/stage.py | 10 +- src/tools/unix.py | 2 +- 9 files changed, 197 insertions(+), 238 deletions(-) diff --git a/src/build/build_request.py b/src/build/build_request.py index 194251688..4fa54072f 100644 --- a/src/build/build_request.py +++ b/src/build/build_request.py @@ -56,7 +56,7 @@ def __x_product_aux (property_sets, seen_features): these_features = set() for p in property_sets[0].non_free(): - these_features.add(p.feature()) + these_features.add(p.feature) # Note: the algorithm as implemented here, as in original Jam code, appears to # detect conflicts based on features, not properties. For example, if command diff --git a/src/build/feature.py b/src/build/feature.py index db487d69e..85f6579ca 100644 --- a/src/build/feature.py +++ b/src/build/feature.py @@ -9,6 +9,7 @@ import re +from b2.manager import get_manager from b2.util import utility, bjam_signature, is_iterable_typed import b2.util.set from b2.util.utility import add_grist, get_grist, ungrist, replace_grist, to_seq @@ -18,108 +19,79 @@ __re_split_subfeatures = re.compile ('<(.*):(.*)>') __re_no_hyphen = re.compile ('^([^:]+)$') __re_slash_or_backslash = re.compile (r'[\\/]') +VALID_ATTRIBUTES = { + 'implicit', + 'composite', + 'optional', + 'symmetric', + 'free', + 'incidental', + 'path', + 'dependency', + 'propagated', + 'link-incompatible', + 'subfeature', + 'order-sensitive' +} + + class Feature(object): - - # Map from string attribute names to integers bit flags. - # This will be initialized after declaration of the class. - _attribute_name_to_integer = {} - def __init__(self, name, values, attributes): assert isinstance(name, basestring) assert is_iterable_typed(values, basestring) assert is_iterable_typed(attributes, basestring) - self._name = name - self._values = values - self._default = None - self._attributes = 0 - for a in attributes: - self._attributes = self._attributes | Feature._attribute_name_to_integer[a] - self._attributes_string_list = attributes - self._subfeatures = [] - self._parent = None + self.name = name + self.values = values + self.default = None + self.subfeatures = [] + self.parent = None + self.attributes_string_list = [] + self._hash = hash(self.name) - def name(self): - return self._name - - def values(self): - return self._values + for attr in attributes: + self.attributes_string_list.append(attr) + attr = attr.replace("-", "_") + setattr(self, attr, True) def add_values(self, values): assert is_iterable_typed(values, basestring) - self._values.extend(values) - - def attributes(self): - return self._attributes + self.values.extend(values) def set_default(self, value): assert isinstance(value, basestring) for attr in ('free', 'optional'): - if getattr(self, attr)(): + if getattr(self, attr): get_manager().errors()('"{}" feature "<{}>" cannot have a default value.' - .format(attr, self._name)) + .format(attr, self.name)) - self._default = value - - def default(self): - return self._default - - # FIXME: remove when we fully move to using classes for features/properties - def attributes_string_list(self): - return self._attributes_string_list - - def subfeatures(self): - return self._subfeatures + self.default = value def add_subfeature(self, name): assert isinstance(name, Feature) - self._subfeatures.append(name) - - def parent(self): - """For subfeatures, return pair of (parent_feature, value). - - Value may be None if this subfeature is not specific to any - value of the parent feature. - """ - return self._parent + self.subfeatures.append(name) def set_parent(self, feature, value): assert isinstance(feature, Feature) assert isinstance(value, basestring) - self._parent = (feature, value) + self.parent = (feature, value) + + def __hash__(self): + return self._hash def __str__(self): - return self._name + return self.name def reset (): """ Clear the module state. This is mainly for testing purposes. """ global __all_attributes, __all_features, __implicit_features, __composite_properties - global __features_with_attributes, __subfeature_from_value, __all_top_features, __free_features + global __subfeature_from_value, __all_top_features, __free_features global __all_subfeatures - # The list with all attribute names. - __all_attributes = [ 'implicit', - 'composite', - 'optional', - 'symmetric', - 'free', - 'incidental', - 'path', - 'dependency', - 'propagated', - 'link-incompatible', - 'subfeature', - 'order-sensitive' - ] - i = 1 - for a in __all_attributes: - setattr(Feature, a.upper(), i) - Feature._attribute_name_to_integer[a] = i - def probe(self, flag=i): - return getattr(self, "_attributes") & flag - setattr(Feature, a.replace("-", "_"), probe) - i = i << 1 + # sets the default value of False for each valid attribute + for attr in VALID_ATTRIBUTES: + setattr(Feature, attr.replace("-", "_"), False) # A map containing all features. The key is the feature name. # The value is an instance of Feature class. @@ -135,10 +107,6 @@ def reset (): # and the value is a list of Property instances __composite_properties = {} - __features_with_attributes = {} - for attribute in __all_attributes: - __features_with_attributes [attribute] = [] - # Maps a value to the corresponding subfeature name. __subfeature_from_value = {} @@ -178,9 +146,6 @@ def feature (name, values, attributes = []): # Temporary measure while we have not fully moved from 'gristed strings' __all_features["<" + name + ">"] = feature - for attribute in attributes: - __features_with_attributes [attribute].append (name) - name = add_grist(name) if 'subfeature' in attributes: @@ -203,19 +168,18 @@ def set_default (feature, value): value: the default value to assign """ f = __all_features[feature] - attributes = f.attributes() bad_attribute = None - if attributes & Feature.FREE: + if f.free: bad_attribute = "free" - elif attributes & Feature.OPTIONAL: + elif f.optional: bad_attribute = "optional" if bad_attribute: - raise InvalidValue ("%s property %s cannot have a default" % (bad_attribute, feature.name())) + raise InvalidValue ("%s property %s cannot have a default" % (bad_attribute, f.name)) - if not value in f.values(): - raise InvalidValue ("The specified default value, '%s' is invalid.\n" % value + "allowed values are: %s" % f.values()) + if value not in f.values: + raise InvalidValue ("The specified default value, '%s' is invalid.\n" % value + "allowed values are: %s" % f.values) f.set_default(value) @@ -228,8 +192,8 @@ def defaults(features): result = [] for f in features: - if not f.free() and not f.optional() and f.default(): - result.append(property.Property(f, f.default())) + if not f.free and not f.optional and f.default: + result.append(property.Property(f, f.default)) return result @@ -246,14 +210,14 @@ def attributes (feature): """ Returns the attributes of the given feature. """ assert isinstance(feature, basestring) - return __all_features[feature].attributes_string_list() + return __all_features[feature].attributes_string_list def values (feature): """ Return the values of the given feature. """ assert isinstance(feature, basestring) validate_feature (feature) - return __all_features[feature].values() + return __all_features[feature].values def is_implicit_value (value_string): """ Returns true iff 'value_string' is a value_string @@ -323,6 +287,7 @@ def validate_feature (name): else: return __all_features[name] + # Uses Property def __expand_subfeatures_aux (property_, dont_validate = False): """ Helper for expand_subfeatures. @@ -343,8 +308,8 @@ def __expand_subfeatures_aux (property_, dont_validate = False): assert isinstance(property_, property.Property) assert isinstance(dont_validate, int) # matches bools - f = property_.feature() - v = property_.value() + f = property_.feature + v = property_.value if not dont_validate: validate_value_string(f, v) @@ -394,7 +359,7 @@ def expand_subfeatures(properties, dont_validate = False): result = [] for p in properties: # Don't expand subfeatures in subfeatures - if p.feature().subfeature(): + if p.feature.subfeature: result.append (p) else: result.extend(__expand_subfeatures_aux (p, dont_validate)) @@ -430,14 +395,14 @@ def extend (name, values): __validate_feature (name) feature = __all_features [name] - if feature.implicit(): + if feature.implicit: for v in values: if v in __implicit_features: raise BaseException ("'%s' is already associated with the feature '%s'" % (v, __implicit_features [v])) __implicit_features[v] = feature - if values and not feature.values() and not(feature.free() or feature.optional()): + if values and not feature.values and not(feature.free or feature.optional): # This is the first value specified for this feature, # take it as default value feature.set_default(values[0]) @@ -449,20 +414,20 @@ def validate_value_string (f, value_string): """ assert isinstance(f, Feature) assert isinstance(value_string, basestring) - if f.free() or value_string in f.values(): + if f.free or value_string in f.values: return values = [value_string] - if f.subfeatures(): - if not value_string in f.values() and \ - not value_string in f.subfeatures(): + if f.subfeatures: + if not value_string in f.values and \ + not value_string in f.subfeatures: values = value_string.split('-') # 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], f.name(), f.values())) + 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], f.name, f.values)) for v in values [1:]: # this will validate any subfeature values in value-string @@ -529,7 +494,7 @@ def subfeature (feature_name, value_string, subfeature, subvalues, attributes = # Add grist to the subfeature name if a value-string was supplied subfeature_name = __get_subfeature_name (subfeature, value_string) - if subfeature_name in __all_features[feature_name].subfeatures(): + if subfeature_name in __all_features[feature_name].subfeatures: message = "'%s' already declared as a subfeature of '%s'" % (subfeature, feature_name) message += " specific to '%s'" % value_string raise BaseException (message) @@ -554,14 +519,14 @@ def compose (composite_property_s, component_properties_s): component_properties_s = to_seq (component_properties_s) composite_property = property.create_from_string(composite_property_s) - f = composite_property.feature() + f = composite_property.feature if len(component_properties_s) > 0 and isinstance(component_properties_s[0], property.Property): component_properties = component_properties_s else: component_properties = [property.create_from_string(p) for p in component_properties_s] - if not f.composite(): + if not f.composite: raise BaseException ("'%s' is not a composite feature" % f) if property in __composite_properties: @@ -608,7 +573,7 @@ def expand_composites (properties): if __debug__: from .property import Property assert is_iterable_typed(properties, Property) - explicit_features = set(p.feature() for p in properties) + explicit_features = set(p.feature for p in properties) result = [] @@ -618,23 +583,23 @@ def expand_composites (properties): for x in expanded: if not x in result: - f = x.feature() + f = x.feature - if f.free(): + if f.free: result.append (x) elif not x in properties: # x is the result of expansion if not f in explicit_features: # not explicitly-specified - if any(r.feature() == f for r in result): + if any(r.feature == f for r in result): raise FeatureConflict( "expansions of composite features result in " "conflicting values for '%s'\nvalues: '%s'\none contributing composite property was '%s'" % - (f.name(), [r.value() for r in result if r.feature() == f] + [x.value()], p)) + (f.name, [r.value for r in result if r.feature == f] + [x.value], p)) else: result.append (x) - elif any(r.feature() == f for r in result): + elif any(r.feature == f for r in result): raise FeatureConflict ("explicitly-specified values of non-free feature '%s' conflict\n" "existing values: '%s'\nvalue from expanding '%s': '%s'" % (f, - [r.value() for r in result if r.feature() == f], p, x.value())) + [r.value for r in result if r.feature == f], p, x.value)) else: result.append (x) @@ -651,20 +616,20 @@ def is_subfeature_of (parent_property, f): assert isinstance(parent_property, Property) assert isinstance(f, Feature) - if not f.subfeature(): + if not f.subfeature: return False - p = f.parent() + p = f.parent if not p: return False parent_feature = p[0] parent_value = p[1] - if parent_feature != parent_property.feature(): + if parent_feature != parent_property.feature: return False - if parent_value and parent_value != parent_property.value(): + if parent_value and parent_value != parent_property.value: return False return True @@ -676,7 +641,7 @@ def __is_subproperty_of (parent_property, p): from .property import Property assert isinstance(parent_property, Property) assert isinstance(p, Property) - return is_subfeature_of (parent_property, p.feature()) + return is_subfeature_of (parent_property, p.feature) # Returns true iff the subvalue is valid for the feature. When the @@ -735,28 +700,23 @@ def add_defaults (properties): if __debug__: from .property import Property assert is_iterable_typed(properties, Property) + # create a copy since properties will be modified + result = list(properties) - result = [x for x in properties] - - handled_features = set() - for p in properties: - # We don't add default for conditional properties. We don't want - # debug:DEBUG to be takes as specified value for - if not p.condition(): - handled_features.add(p.feature()) + # We don't add default for conditional properties. We don't want + # debug:DEBUG to be takes as specified value for + handled_features = set(p.feature for p in properties if not p.condition) missing_top = [f for f in __all_top_features if not f in handled_features] more = defaults(missing_top) result.extend(more) - for p in more: - handled_features.add(p.feature()) + handled_features.update(p.feature for p in more) # Add defaults for subfeatures of features which are present for p in result[:]: - s = p.feature().subfeatures() - more = defaults([s for s in p.feature().subfeatures() if not s in handled_features]) - for p in more: - handled_features.add(p.feature()) + subfeatures = [s for s in p.feature.subfeatures if not s in handled_features] + more = defaults(__select_subfeatures(p, subfeatures)) + handled_features.update(h.feature for h in more) result.extend(more) return result @@ -775,29 +735,33 @@ def minimize (properties): assert is_iterable_typed(properties, Property) # remove properties implied by composite features components = [] + component_features = set() for property in properties: if property in __composite_properties: - components.extend(__composite_properties[property]) + cs = __composite_properties[property] + components.extend(cs) + component_features.update(c.feature for c in cs) + properties = b2.util.set.difference (properties, components) # handle subfeatures and implicit features # move subfeatures to the end of the list - properties = [p for p in properties if not p.feature().subfeature()] +\ - [p for p in properties if p.feature().subfeature()] + properties = [p for p in properties if not p.feature.subfeature] +\ + [p for p in properties if p.feature.subfeature] result = [] while properties: p = properties[0] - f = p.feature() + f = p.feature # locate all subproperties of $(x[1]) in the property set - subproperties = __select_subproperties (p, properties) + subproperties = [x for x in properties if is_subfeature_of(p, x.feature)] if subproperties: # reconstitute the joined property name subproperties.sort () - joined = b2.build.property.Property(p.feature(), p.value() + '-' + '-'.join ([sp.value() for sp in subproperties])) + joined = b2.build.property.Property(p.feature, p.value + '-' + '-'.join ([sp.value for sp in subproperties])) result.append(joined) properties = b2.util.set.difference(properties[1:], subproperties) @@ -811,12 +775,8 @@ def minimize (properties): # have been eliminated, any remaining property whose # feature is the same as a component of a composite in the # set must have a non-redundant value. - if p.value() != f.default() or f.symmetric(): + if p.value != f.default or f.symmetric or f in component_features: result.append (p) - #\ - #or get_grist (fullp) in get_grist (components): - # FIXME: restore above - properties = properties[1:] @@ -872,18 +832,18 @@ def compress_subproperties (properties): matched_subs = set() all_subs = set() for p in properties: - f = p.feature() + f = p.feature - if not f.subfeature(): - subs = __select_subproperties (p, properties) + if not f.subfeature: + subs = [x for x in properties if is_subfeature_of(p, x.feature)] if subs: matched_subs.update(subs) - subvalues = '-'.join (sub.value() for sub in subs) + subvalues = '-'.join (sub.value for sub in subs) result.append(Property( - p.feature(), p.value() + '-' + subvalues, - p.condition())) + p.feature, p.value + '-' + subvalues, + p.condition)) else: result.append(p) @@ -920,7 +880,7 @@ def __validate_feature_attributes (name, attributes): assert isinstance(name, basestring) assert is_iterable_typed(attributes, basestring) for attribute in attributes: - if not attribute in __all_attributes: + if attribute not in VALID_ATTRIBUTES: raise InvalidAttribute ("unknown attributes: '%s' in feature declaration: '%s'" % (str (b2.util.set.difference (attributes, __all_attributes)), name)) if name in __all_features: diff --git a/src/build/property.py b/src/build/property.py index 4d1b192c5..e691609dd 100644 --- a/src/build/property.py +++ b/src/build/property.py @@ -55,7 +55,7 @@ class PropertyMeta(type): class Property(object): - __slots__ = ('_feature', '_value', '_condition', '_to_raw', '_hash') + __slots__ = ('feature', 'value', 'condition', '_to_raw', '_hash') __metaclass__ = PropertyMeta def __init__(self, f, value, condition = []): @@ -64,23 +64,14 @@ class Property(object): # At present, single property has a single value. assert type(value) != type([]) assert(f.free() or value.find(':') == -1) - self._feature = f - self._value = value - self._condition = condition - - def feature(self): - return self._feature - - def value(self): - return self._value - - def condition(self): - return self._condition + self.feature = f + self.value = value + self.condition = condition def to_raw(self): - result = "<" + self._feature.name() + ">" + str(self._value) - if self._condition: - result = ",".join(str(p) for p in self._condition) + ':' + result + result = "<" + self.feature.name + ">" + str(self.value) + if self.condition: + result = ",".join(str(p) for p in self.condition) + ':' + result return result def __str__(self): @@ -88,11 +79,11 @@ class Property(object): def __hash__(self): # FIXME: consider if this class should be value-is-identity one - return hash((self._feature, self._value, tuple(self._condition))) + return hash((self.feature, self.value, tuple(self.condition))) def __cmp__(self, other): - return cmp((self._feature.name(), self._value, self._condition), - (other._feature.name(), other._value, other._condition)) + return cmp((self.feature.name, self.value, self.condition), + (other.feature.name, other.value, other.condition)) class LazyProperty(object): @@ -123,8 +114,8 @@ class LazyProperty(object): return self.__property._to_raw def __cmp__(self, other): - return cmp((self._feature.name(), self._value, self._condition), - (other._feature.name(), other._value, other._condition)) + return cmp((self.feature.name, self.value, self.condition), + (other.feature.name, other.value, other.condition)) def create_from_string(s, allow_condition=False,allow_missing_value=False): @@ -259,19 +250,19 @@ def refine (properties, requirements): # Record them so that we can handle 'properties'. for r in requirements: # Don't consider conditional requirements. - if not r.condition(): - required[r.feature()] = r + if not r.condition: + required[r.feature] = r for p in properties: # Skip conditional properties - if p.condition(): + if p.condition: result.add(p) # No processing for free properties - elif p.feature().free(): + elif p.feature.free: result.add(p) else: - if p.feature() in required: - result.add(required[p.feature()]) + if p.feature in required: + result.add(required[p.feature]) else: result.add(p) @@ -282,17 +273,18 @@ def translate_paths (properties, path): The property values are assumed to be in system-specific form, and will be translated into normalized form. """ + assert is_iterable_typed(properties, Property) result = [] for p in properties: - if p.feature().path(): - values = __re_two_ampersands.split(p.value()) + if p.feature.path: + values = __re_two_ampersands.split(p.value) - new_value = "&&".join(os.path.join(path, v) for v in values) + new_value = "&&".join(os.path.normpath(os.path.join(path, v)) for v in values) - if new_value != p.value(): - result.append(Property(p.feature(), new_value, p.condition())) + if new_value != p.value: + result.append(Property(p.feature, new_value, p.condition)) else: result.append(p) @@ -310,10 +302,10 @@ def translate_indirect(properties, context_module): assert isinstance(context_module, basestring) result = [] for p in properties: - if p.value()[0] == '@': - q = qualify_jam_action(p.value()[1:], context_module) + if p.value[0] == '@': + q = qualify_jam_action(p.value[1:], context_module) get_manager().engine().register_bjam_action(q) - result.append(Property(p.feature(), '@' + q, p.condition())) + result.append(Property(p.feature, '@' + q, p.condition)) else: result.append(p) @@ -334,11 +326,11 @@ def expand_subfeatures_in_conditions (properties): result = [] for p in properties: - if not p.condition(): + if not p.condition: result.append(p) else: expanded = [] - for c in p.condition(): + for c in p.condition: # It common that condition includes a toolset which # was never defined, or mentiones subfeatures which # were never defined. In that case, validation will @@ -347,12 +339,12 @@ def expand_subfeatures_in_conditions (properties): # we need to keep LazyProperties lazy if isinstance(p, LazyProperty): - value = p.value() + value = p.value feature_name = get_grist(value) value = value.replace(feature_name, '') result.append(LazyProperty(feature_name, value, condition=expanded)) else: - result.append(Property(p.feature(), p.value(), expanded)) + result.append(Property(p.feature, p.value, expanded)) return result @@ -404,7 +396,7 @@ def evaluate_conditionals_in_context (properties, context): conditional = [] for p in properties: - if p.condition(): + if p.condition: conditional.append (p) else: base.append (p) @@ -414,8 +406,8 @@ def evaluate_conditionals_in_context (properties, context): # Evaluate condition # FIXME: probably inefficient - if all(x in context for x in p.condition()): - result.append(Property(p.feature(), p.value())) + if all(x in context for x in p.condition): + result.append(Property(p.feature, p.value)) return result @@ -452,8 +444,8 @@ def __validate1 (property): assert isinstance(property, Property) msg = None - if not property.feature().free(): - feature.validate_value_string (property.feature(), property.value()) + if not property.feature.free: + feature.validate_value_string (property.feature, property.value) ################################################################### @@ -523,10 +515,10 @@ def translate_dependencies(properties, project_id, location): result = [] for p in properties: - if not p.feature().dependency(): + if not p.feature.dependency: result.append(p) else: - v = p.value() + v = p.value m = re.match("(.*)//(.*)", v) if m: rooted = m.group(1) @@ -536,12 +528,12 @@ def translate_dependencies(properties, project_id, location): else: rooted = os.path.join(os.getcwd(), location, rooted) - result.append(Property(p.feature(), rooted + "//" + m.group(2), p.condition())) + result.append(Property(p.feature, rooted + "//" + m.group(2), p.condition)) elif os.path.isabs(v): result.append(p) else: - result.append(Property(p.feature(), project_id + "//" + v, p.condition())) + result.append(Property(p.feature, project_id + "//" + v, p.condition)) return result diff --git a/src/build/property_set.py b/src/build/property_set.py index b5686bc85..f9147515d 100644 --- a/src/build/property_set.py +++ b/src/build/property_set.py @@ -228,23 +228,24 @@ class PropertySet: self.link_incompatible.append (p) for p in properties: + f = p.feature if isinstance(p, property.LazyProperty): self.lazy_properties.append(p) # A feature can be both incidental and free, # in which case we add it to incidental. - if p.feature().incidental(): + elif f.incidental: self.incidental_.append(p) - elif p.feature().free(): + elif f.free: self.free_.append(p) else: self.base_.append(p) - if p.condition(): + if p.condition: self.conditional_.append(p) else: self.non_conditional_.append(p) - if p.feature().dependency(): + if f.dependency: self.dependency_.append (p) elif not isinstance(p, property.LazyProperty): self.non_dependency_.append (p) @@ -270,7 +271,7 @@ class PropertySet: """ Returns properties that are neither incidental nor free. """ result = [p for p in self.lazy_properties - if not(p.feature().incidental() or p.feature().free())] + if not(p.feature.incidental or p.feature.free)] result.extend(self.base_) return result @@ -278,7 +279,7 @@ class PropertySet: """ Returns free properties which are not dependency properties. """ result = [p for p in self.lazy_properties - if not p.feature().incidental() and p.feature().free()] + if not p.feature.incidental and p.feature.free] result.extend(self.free_) return result @@ -288,14 +289,14 @@ class PropertySet: def dependency (self): """ Returns dependency properties. """ - result = [p for p in self.lazy_properties if p.feature().dependency()] + result = [p for p in self.lazy_properties if p.feature.dependency] result.extend(self.dependency_) return self.dependency_ def non_dependency (self): """ Returns properties that are not dependencies. """ - result = [p for p in self.lazy_properties if not p.feature().dependency()] + result = [p for p in self.lazy_properties if not p.feature.dependency] result.extend(self.non_dependency_) return result @@ -312,7 +313,7 @@ class PropertySet: def incidental (self): """ Returns incidental properties. """ - result = [p for p in self.lazy_properties if p.feature().incidental()] + result = [p for p in self.lazy_properties if p.feature.incidental] result.extend(self.incidental_) return result @@ -368,13 +369,13 @@ class PropertySet: def path_order (p1, p2): - i1 = p1.feature().implicit() - i2 = p2.feature().implicit() + i1 = p1.feature.implicit + i2 = p2.feature.implicit if i1 != i2: return i2 - i1 else: - return cmp(p1.feature().name(), p2.feature().name()) + return cmp(p1.feature.name, p2.feature.name) # trim redundancy properties = feature.minimize(self.base_) @@ -384,15 +385,16 @@ class PropertySet: components = [] for p in properties: - if p.feature().implicit(): - components.append(p.value()) + f = p.feature + if f.implicit: + components.append(p.value) else: - value = p.feature().name() + "-" + p.value() + value = f.name.replace(':', '-') + "-" + p.value if property.get_abbreviated_paths(): value = abbreviate_dashed(value) components.append(value) - self.as_path_ = '/'.join (components) + self.as_path_ = '/'.join(components) return self.as_path_ @@ -467,13 +469,13 @@ class PropertySet: feature = b2.build.feature.get(feature) assert isinstance(feature, b2.build.feature.Feature) - if not self.feature_map_: + if self.feature_map_ is None: self.feature_map_ = {} for v in self.all_: - if v.feature() not in self.feature_map_: - self.feature_map_[v.feature()] = [] - self.feature_map_[v.feature()].append(v.value()) + if v.feature not in self.feature_map_: + self.feature_map_[v.feature] = [] + self.feature_map_[v.feature].append(v.value) return self.feature_map_.get(feature, []) @@ -486,7 +488,7 @@ class PropertySet: result = [] for p in self.all_: - if p.feature() == feature: + if p.feature == feature: result.append(p) return result diff --git a/src/build/targets.py b/src/build/targets.py index 4e8f8557f..d3d78d1f7 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -969,7 +969,7 @@ class BasicTarget (AbstractTarget): free_unconditional = [] other = [] for p in requirements.all(): - if p.feature().free() and not p.condition() and p.feature().name() != 'conditional': + if p.feature.free and not p.condition and p.feature.name != 'conditional': free_unconditional.append(p) else: other.append(p) @@ -1157,10 +1157,10 @@ class BasicTarget (AbstractTarget): usage_requirements = [] for p in properties: - result = generate_from_reference(p.value(), self.project_, ps) + result = generate_from_reference(p.value, self.project_, ps) for t in result.targets(): - result_properties.append(property.Property(p.feature(), t)) + result_properties.append(property.Property(p.feature, t)) usage_requirements += result.usage_requirements().all() @@ -1327,9 +1327,18 @@ class BasicTarget (AbstractTarget): # they are propagated only to direct dependents. We might need # a more general mechanism, but for now, only those two # features are special. - removed_pch = filter(lambda prop: prop.feature().name() not in ['', ''], subvariant.sources_usage_requirements().all()) - result = result.add(property_set.PropertySet(removed_pch)) + properties = [] + for p in subvariant.sources_usage_requirements().all(): + if p.feature.name not in ('pch-header', 'pch-file'): + properties.append(p) + if 'shared' in rproperties.get('link'): + new_properties = [] + for p in properties: + if p.feature.name != 'library': + new_properties.append(p) + properties = new_properties + result = result.add_raw(properties) return result def create_subvariant (self, root_targets, all_targets, @@ -1412,11 +1421,9 @@ def apply_default_build(property_set_, default_build): assert isinstance(property_set_, property_set.PropertySet) assert isinstance(default_build, property_set.PropertySet) - specified_features = set(p.feature() for p in property_set_.all()) - defaults_to_apply = [] for d in default_build.all(): - if not d.feature() in specified_features: + if not property_set_.get(d.feature): defaults_to_apply.append(d) # 2. If there's any defaults to be applied, form the new diff --git a/src/build/toolset.py b/src/build/toolset.py index 25c3a5fe6..6d2704cea 100644 --- a/src/build/toolset.py +++ b/src/build/toolset.py @@ -184,16 +184,14 @@ def find_satisfied_condition(conditions, ps): 'properties', or an empty list if no such element exists.""" assert is_iterable_typed(conditions, property_set.PropertySet) assert isinstance(ps, property_set.PropertySet) - features = set(p.feature() for p in ps.all()) for condition in conditions: found_all = True for i in condition.all(): - found = False - if i.value(): - found = i.value() in ps.get(i.feature()) + if i.value: + found = i.value in ps.get(i.feature) else: # Handle value-less properties like '' (compare with # 'x86'). @@ -206,7 +204,7 @@ def find_satisfied_condition(conditions, ps): # foo foo foo no match # foo foo foo no match # foo foo foo foo match - found = not i.feature() in features + found = not ps.get(i.feature) found_all = found_all and found @@ -339,12 +337,12 @@ def __handle_flag_value (manager, value, ps): for value in values: - if f.dependency(): + if f.dependency: # the value of a dependency feature is a target # and must be actualized result.append(value.actualize()) - elif f.path() or f.free(): + elif f.path or f.free: # Treat features with && in the value # specially -- each &&-separated element is considered diff --git a/src/build/virtual_target.py b/src/build/virtual_target.py index be3d51ef3..e3bd6c352 100644 --- a/src/build/virtual_target.py +++ b/src/build/virtual_target.py @@ -1114,7 +1114,7 @@ class Subvariant: if not e in result: result.add(e) if isinstance(e, property.Property): - t = e.value() + t = e.value else: t = e diff --git a/src/tools/stage.py b/src/tools/stage.py index 76b10f65a..2a15dd18a 100644 --- a/src/tools/stage.py +++ b/src/tools/stage.py @@ -60,7 +60,7 @@ class InstallTargetClass(targets.BasicTarget): # properties. if build_ps.get('hardcode-dll-paths') != ['true']: - properties = [p for p in properties if p.feature().name() != 'dll-path'] + properties = [p for p in properties if p.feature.name != 'dll-path'] # If any properties were specified for installing, add # them. @@ -75,7 +75,7 @@ class InstallTargetClass(targets.BasicTarget): # sources, then we shall get virtual targets with the # property set. properties = [p for p in properties - if not p.feature().name() in ['tag', 'location']] + if not p.feature.name in ['tag', 'location']] properties.extend(build_ps.get_properties('dependency')) @@ -90,7 +90,7 @@ class InstallTargetClass(targets.BasicTarget): # making the path absolute will help. if d: p = d[0] - properties.append(property.Property(p.feature(), os.path.abspath(p.value()))) + properties.append(property.Property(p.feature, os.path.abspath(p.value))) return property_set.create(properties) @@ -180,8 +180,8 @@ class InstallTargetClass(targets.BasicTarget): for r in result: if isinstance(r, property.Property): - if r.feature().name() != 'use': - result2.append(r.value()) + if r.feature.name != 'use': + result2.append(r.value) else: result2.append(r) result2 = unique(result2) diff --git a/src/tools/unix.py b/src/tools/unix.py index f66ed16f7..298fc1dc5 100644 --- a/src/tools/unix.py +++ b/src/tools/unix.py @@ -135,7 +135,7 @@ def set_library_order (manager, sources, prop_set, result): used_libraries = [] deps = prop_set.dependency () - sources.extend(d.value() for d in deps) + sources.extend(d.value for d in deps) sources = sequence.unique(sources) for l in sources: From 7f7995879b840ea91aee3168c0615a1c0c4b6e4b Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 23:52:27 -0500 Subject: [PATCH 118/158] Optimize Property comparisons. --- src/build/property.py | 55 ++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 19 deletions(-) diff --git a/src/build/property.py b/src/build/property.py index e691609dd..1da99c4cb 100644 --- a/src/build/property.py +++ b/src/build/property.py @@ -9,6 +9,7 @@ import re import sys +from functools import total_ordering from b2.util.utility import * from b2.build import feature @@ -53,39 +54,53 @@ class PropertyMeta(type): return self.check(subclass) +@total_ordering class Property(object): - __slots__ = ('feature', 'value', 'condition', '_to_raw', '_hash') + __slots__ = ('feature', 'value', 'condition', '_to_raw', '_hash', 'id') __metaclass__ = PropertyMeta - def __init__(self, f, value, condition = []): - if type(f) == type(""): - f = feature.get(f) - # At present, single property has a single value. - assert type(value) != type([]) - assert(f.free() or value.find(':') == -1) + def __init__(self, f, value, condition=None): + assert(f.free or ':' not in value) + if condition is None: + condition = [] + self.feature = f self.value = value self.condition = condition + self._hash = hash((self.feature, self.value) + tuple(sorted(self.condition))) + self.id = PropertyMeta.current_id + # increment the id counter by bit shifting. + # this allows us to take a list of Property + # instances and add their IDs together to create + # a unique key for that "PropertySet". + PropertyMeta.current_id += 1 + + condition_str = '' + if condition: + condition_str = ",".join(str(p) for p in self.condition) + ':' + + self._to_raw = '{}<{}>{}'.format(condition_str, f.name, value) def to_raw(self): - result = "<" + self.feature.name + ">" + str(self.value) - if self.condition: - result = ",".join(str(p) for p in self.condition) + ':' + result - return result + return self._to_raw def __str__(self): - return self.to_raw() + + return self._to_raw def __hash__(self): # FIXME: consider if this class should be value-is-identity one - return hash((self.feature, self.value, tuple(self.condition))) + return self._hash - def __cmp__(self, other): - return cmp((self.feature.name, self.value, self.condition), - (other.feature.name, other.value, other.condition)) + def __eq__(self, other): + return self._hash == other._hash + + def __lt__(self, other): + return (self.feature.name, self.value) < (other.feature.name, other.value) +@total_ordering class LazyProperty(object): def __init__(self, feature_name, value, condition=None): if condition is None: @@ -113,9 +128,11 @@ class LazyProperty(object): def __str__(self): return self.__property._to_raw - def __cmp__(self, other): - return cmp((self.feature.name, self.value, self.condition), - (other.feature.name, other.value, other.condition)) + def __eq__(self, other): + return self.__property == other + + def __lt__(self, other): + return (self.feature.name, self.value) < (other.feature.name, other.value) def create_from_string(s, allow_condition=False,allow_missing_value=False): From 5292c95e29d2a4af6f6e182e212fa492e7a15a4d Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 23:57:09 -0500 Subject: [PATCH 119/158] Optimize PropertySet creation. The Property class has been updated so that passing in the same parameters will always return the same Property instance. Since no duplicate Property instances will be created, we can assign a unique ID to each instance. This allows us to create a faster lookup key when determining whether to create a new PropertySet or use an existing one as integer comparison is much faster than (string, string) comparison. --- src/build/property.py | 33 +++++++++++++++++++++++++++++---- src/build/property_set.py | 11 ++++++----- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/build/property.py b/src/build/property.py index 1da99c4cb..dff82865c 100644 --- a/src/build/property.py +++ b/src/build/property.py @@ -40,7 +40,32 @@ class PropertyMeta(type): Implementing both __instancecheck__ and __subclasscheck__ will allow LazyProperty instances to pass the isinstance() and issubclass check for the Property class. + + Additionally, the __call__ method intercepts the call to the Property + constructor to ensure that calling Property with the same arguments + will always return the same Property instance. """ + _registry = {} + current_id = 1 + + def __call__(mcs, f, value, condition=None): + """ + This intercepts the call to the Property() constructor. + + This exists so that the same arguments will always return the same Property + instance. This allows us to give each instance a unique ID. + """ + from b2.build.feature import Feature + if not isinstance(f, Feature): + f = feature.get(f) + if condition is None: + condition = [] + key = (f, value) + tuple(sorted(condition)) + if key not in mcs._registry: + instance = super(PropertyMeta, mcs).__call__(f, value, condition) + mcs._registry[key] = instance + return mcs._registry[key] + @staticmethod def check(obj): return (hasattr(obj, 'feature') and @@ -70,10 +95,11 @@ class Property(object): self.condition = condition self._hash = hash((self.feature, self.value) + tuple(sorted(self.condition))) self.id = PropertyMeta.current_id - # increment the id counter by bit shifting. + # increment the id counter. # this allows us to take a list of Property - # instances and add their IDs together to create - # a unique key for that "PropertySet". + # instances and use their unique integer ID + # to create a key for PropertySet caching. This is + # much faster than string comparison. PropertyMeta.current_id += 1 condition_str = '' @@ -90,7 +116,6 @@ class Property(object): return self._to_raw def __hash__(self): - # FIXME: consider if this class should be value-is-identity one return self._hash def __eq__(self, other): diff --git a/src/build/property_set.py b/src/build/property_set.py index f9147515d..cf935ce98 100644 --- a/src/build/property_set.py +++ b/src/build/property_set.py @@ -44,12 +44,13 @@ def create (raw_properties = []): x = raw_properties else: x = [property.create_from_string(ps) for ps in raw_properties] - x.sort() - x = unique(x, stable=True) - # FIXME: can we do better, e.g. by directly computing - # hash value of the list? - key = tuple(x) + # these two lines of code are optimized to the current state + # of the Property class. since this function acts as the caching + # frontend to the PropertySet class modifying these two lines + # could have a severe performance penalty. be careful + x = sorted(set(x), key=lambda p: p.id) + key = tuple(p.id for p in x) if key not in __cache: __cache [key] = PropertySet(x) From ca9b6035bae4cca3b07459dfbb86ebd36bf1df48 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:04:00 -0500 Subject: [PATCH 120/158] Optimize PropertySet class. --- src/build/property_set.py | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/src/build/property_set.py b/src/build/property_set.py index cf935ce98..e39a5aa56 100644 --- a/src/build/property_set.py +++ b/src/build/property_set.py @@ -155,16 +155,13 @@ class PropertySet: - several operations, like and refine and as_path are provided. They all use caching whenever possible. """ - def __init__ (self, properties = []): + def __init__ (self, properties=None): + if properties is None: + properties = [] assert is_iterable_typed(properties, property.Property) - raw_properties = [] - for p in properties: - raw_properties.append(p.to_raw()) - self.all_ = properties - self.all_raw_ = raw_properties - self.all_set_ = set(properties) + self._all_set = {p.id for p in properties} self.incidental_ = [] self.free_ = [] @@ -216,18 +213,6 @@ class PropertySet: # first before returning. self.lazy_properties = [] - for p in raw_properties: - if not get_grist (p): - raise BaseException ("Invalid property: '%s'" % p) - - att = feature.attributes (get_grist (p)) - - if 'propagated' in att: - self.propagated_.append (p) - - if 'link_incompatible' in att: - self.link_incompatible.append (p) - for p in properties: f = p.feature if isinstance(p, property.LazyProperty): @@ -251,6 +236,11 @@ class PropertySet: elif not isinstance(p, property.LazyProperty): self.non_dependency_.append (p) + if f.propagated: + self.propagated_.append(p) + if f.link_incompatible: + self.link_incompatible.append(p) + def all(self): return self.all_ @@ -263,10 +253,10 @@ class PropertySet: # true Property(). This approach is being # taken since calculations should not be using # PropertySet.raw() - return [p.to_raw() for p in self.all_] + return [p._to_raw for p in self.all_] def __str__(self): - return ' '.join(str(p) for p in self.all_) + return ' '.join(p._to_raw for p in self.all_) def base (self): """ Returns properties that are neither incidental nor free. @@ -494,7 +484,7 @@ class PropertySet: return result def __contains__(self, item): - return item in self.all_set_ + return item.id in self._all_set def hash(p): m = hashlib.md5() From 18e423e4058fb86c5bb6ed23e2e2b3289f9cadfb Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 00:07:27 -0500 Subject: [PATCH 121/158] Optmize apply_default_build(). --- src/build/targets.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/build/targets.py b/src/build/targets.py index d3d78d1f7..cb4148658 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -1447,10 +1447,12 @@ def apply_default_build(property_set_, default_build): # be an indication that # build_request.expand-no-defaults is the wrong rule # to use here. - compressed = feature.compress_subproperties(property_set_.all()) + properties = build_request.expand_no_defaults([property_set.create( + feature.compress_subproperties(property_set_.all() + defaults_to_apply))]) - result = build_request.expand_no_defaults( - b2.build.property_set.create(feature.expand([p])) for p in (compressed + defaults_to_apply)) + if properties: + for p in properties: + result.append(property_set.create(feature.expand(p.all()))) else: result.append (property_set_) From 601a721ad5fc92c9250242d9b9ccd421b5c68ca0 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 8 Oct 2016 16:04:32 -0500 Subject: [PATCH 122/158] Optimize Engine.set_target_variable(). This removes the extra call to do_set_target_variable() because it's possible for target variables to be set during the build phase. The extra call added a decent amount of overhead. Addtionally, rather than setting the target variables for each target (via the for loop), the bjam interface "set-target-variable" rule allows for taking in a list of targets. Thus, even more function calls are avoided. --- src/build/engine.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/build/engine.py b/src/build/engine.py index c409276b6..6e49a8b5e 100644 --- a/src/build/engine.py +++ b/src/build/engine.py @@ -136,8 +136,11 @@ class Engine: assert isinstance(variable, basestring) assert is_iterable(value) - for target in targets: - self.do_set_target_variable (target, variable, value, append) + if targets: + if append: + bjam_interface.call("set-target-variable", targets, variable, value, "true") + else: + bjam_interface.call("set-target-variable", targets, variable, value) def set_update_action (self, action_name, targets, sources, properties=None): """ Binds a target to the corresponding update action. From f993e75a7f8da4448d7bf7145449e028e5be150c Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 16:28:04 -0500 Subject: [PATCH 123/158] Fix conditionals_multiple test. --- src/build/toolset.py | 6 ++++-- test/conditionals_multiple.py | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/build/toolset.py b/src/build/toolset.py index 6d2704cea..29c7db464 100644 --- a/src/build/toolset.py +++ b/src/build/toolset.py @@ -78,8 +78,10 @@ reset () # FIXME: --ignore-toolset-requirements def using(toolset_module, *args): - loaded_toolset_module= get_manager().projects().load_module(toolset_module, [os.getcwd()]); - loaded_toolset_module.init(*args) + if isinstance(toolset_module, (list, tuple)): + toolset_module = toolset_module[0] + loaded_toolset_module= get_manager().projects().load_module(toolset_module, [os.getcwd()]); + loaded_toolset_module.init(*args) # FIXME push-checking-for-flags-module .... # FIXME: investigate existing uses of 'hack-hack' parameter diff --git a/test/conditionals_multiple.py b/test/conditionals_multiple.py index 91b8f30d7..dd1169081 100755 --- a/test/conditionals_multiple.py +++ b/test/conditionals_multiple.py @@ -147,7 +147,7 @@ rule init ( version ? ) { } from b2.build import feature feature.extend('toolset', ["%(toolset)s"]) feature.subfeature('toolset', "%(toolset)s", "version", ['0','1']) -def init ( version ): pass +def init (version=''): pass """ % {"toolset": toolset}) t.write("jamroot.jam", """\ From 0b02b4823528b73b1ec835715922c62b4d260ff6 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 16:34:38 -0500 Subject: [PATCH 124/158] Make the src directory a Python package. --- src/__init__.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/__init__.py diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 000000000..e69de29bb From 6cac5a21e503633c7e0fee1bc18596d19decb9f1 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 18:11:33 -0500 Subject: [PATCH 125/158] Fix default_build test. --- src/build/targets.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/build/targets.py b/src/build/targets.py index cb4148658..8ac2d33fa 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -1447,12 +1447,16 @@ def apply_default_build(property_set_, default_build): # be an indication that # build_request.expand-no-defaults is the wrong rule # to use here. - properties = build_request.expand_no_defaults([property_set.create( - feature.compress_subproperties(property_set_.all() + defaults_to_apply))]) + properties = build_request.expand_no_defaults( + [property_set.create([p]) for p in + feature.compress_subproperties(property_set_.all()) + defaults_to_apply] + ) if properties: for p in properties: result.append(property_set.create(feature.expand(p.all()))) + else: + result = [property_set.empty()] else: result.append (property_set_) From 1bd0eab6000027611c5db1b0001bcf1ba12dfdb3 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 18:33:37 -0500 Subject: [PATCH 126/158] Enable type checking for Python tests. --- src/build/virtual_target.py | 4 ++-- src/tools/common.py | 2 +- test/BoostBuild.py | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/build/virtual_target.py b/src/build/virtual_target.py index e3bd6c352..2a0a1e5cb 100644 --- a/src/build/virtual_target.py +++ b/src/build/virtual_target.py @@ -952,9 +952,9 @@ class NonScanningAction(Action): #be removed? -- Steven Watanabe Action.__init__(self, b2.manager.get_manager(), sources, action_name, property_set) - def actualize_source_type(self, sources, property_set): + def actualize_source_type(self, sources, ps=None): assert is_iterable_typed(sources, VirtualTarget) - assert isinstance(property_set, property_set.PropertySet) + assert isinstance(ps, property_set.PropertySet) or ps is None result = [] for s in sources: result.append(s.actualize()) diff --git a/src/tools/common.py b/src/tools/common.py index aad123a9b..87b942c6d 100644 --- a/src/tools/common.py +++ b/src/tools/common.py @@ -182,7 +182,7 @@ def check_init_parameters(toolset, requirement, *args): The return value from this rule is a condition to be used for flags settings. """ assert isinstance(toolset, basestring) - assert is_iterable_typed(requirement, basestring) + assert is_iterable_typed(requirement, basestring) or requirement is None from b2.build import toolset as b2_toolset if requirement is None: requirement = [] diff --git a/test/BoostBuild.py b/test/BoostBuild.py index 20a174568..55f3bc221 100644 --- a/test/BoostBuild.py +++ b/test/BoostBuild.py @@ -452,7 +452,10 @@ class Tester(TestCmd.TestCmd): if ignore_toolset_requirements: kw["program"].append("--ignore-toolset-requirements") if "--python" in sys.argv: - kw["program"].append("--python") + # -z disables Python optimization mode. + # this enables type checking (all assert + # and if __debug__ statements). + kw["program"].extend(["--python", "-z"]) if "--stacktrace" in sys.argv: kw["program"].append("--stacktrace") kw["chdir"] = subdir From b90915009e6d6678aad00b37f334e05964be7842 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 18:33:57 -0500 Subject: [PATCH 127/158] Fix generator_selection test. Allow generators.register_standard() to be called from Jam. --- src/build/generators.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/build/generators.py b/src/build/generators.py index d12be7e33..a4a39d94d 100644 --- a/src/build/generators.py +++ b/src/build/generators.py @@ -56,7 +56,7 @@ from . import virtual_target, type, property_set, property from b2.exceptions import BaseBoostBuildException from b2.util.logger import * from b2.util.utility import * -from b2.util import set as set_, is_iterable_typed, is_iterable +from b2.util import set as set_, is_iterable_typed, is_iterable, bjam_signature from b2.util.sequence import unique import b2.util.sequence as sequence from b2.manager import get_manager @@ -718,6 +718,7 @@ def check_register_types(fn): return wrapper +@bjam_signature([['id'], ['source_types', '*'], ['target_types', '*'], ['requirements', '*']]) @check_register_types def register_standard (id, source_types, target_types, requirements = []): """ Creates new instance of the 'generator' class and registers it. From a77502735e6122938f60d1a7ff78c0f2ca8e648c Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 18:41:40 -0500 Subject: [PATCH 128/158] Fix configuration test. --- src/util/os_j.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/util/os_j.py b/src/util/os_j.py index f44cca620..f5dff1f90 100644 --- a/src/util/os_j.py +++ b/src/util/os_j.py @@ -8,6 +8,7 @@ # Copyright 2003, 2005 Vladimir Prus # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt) +import os import bjam @@ -17,3 +18,7 @@ __OS = bjam.call("peek", [], "OS")[0] # when faced with Python naming def name(): return __OS + + +def environ(keys): + return [os.environ[key] for key in keys if key in os.environ] From daa173da70c87ce3abf22f8bc21032039d31f044 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 18:47:36 -0500 Subject: [PATCH 129/158] Fix error message in project.py --- src/build/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build/project.py b/src/build/project.py index 46888cb2a..357de848b 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -593,7 +593,7 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" try: return self.module2attributes[project].get(attribute) except: - raise BaseException("No attribute '%s' for project" % (attribute, project)) + raise BaseException("No attribute '%s' for project %s" % (attribute, project)) def attributeDefault(self, project, attribute, default): """Returns the value of the specified attribute in the From 0ef26673c5c430973a852ff9256d058c1b3d4247 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 19:06:50 -0500 Subject: [PATCH 130/158] Fix inherit_toolset test. --- src/build/toolset.py | 2 +- test/inherit_toolset.py | 49 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/src/build/toolset.py b/src/build/toolset.py index 29c7db464..cf2b24b2e 100644 --- a/src/build/toolset.py +++ b/src/build/toolset.py @@ -410,7 +410,7 @@ def add_requirements(requirements): def inherit(toolset, base): assert isinstance(toolset, basestring) assert isinstance(base, basestring) - get_manager().projects().load_module(base, []); + get_manager().projects().load_module(base, ['.']); inherit_generators(toolset, [], base) inherit_flags(toolset, base) diff --git a/test/inherit_toolset.py b/test/inherit_toolset.py index af1878003..95884647e 100644 --- a/test/inherit_toolset.py +++ b/test/inherit_toolset.py @@ -25,6 +25,36 @@ actions compile { yfc1-compile } actions link { yfc1-link } """) +t.write( + 'yfc1.py', +""" +from b2.build import feature, generators +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +feature.extend('toolset', ['yfc1']) + +generators.register_standard('yfc1.compile', ['CPP'], ['OBJ'], ['yfc1']) +generators.register_standard('yfc1.link', ['OBJ'], ['EXE'], ['yfc1']) + +ENGINE.register_action( + 'yfc1.compile', + 'yfc1-compile' +) + +ENGINE.register_action( + 'yfc1.link', + 'yfc1-link' +) + +def init(*args): + pass + +""" +) + t.write("yfc2.jam", """\ import feature ; import toolset ; @@ -36,6 +66,25 @@ rule init ( ) { } actions link { yfc2-link } """) +t.write( + 'yfc2.py', +""" +from b2.build import feature, toolset +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +feature.extend('toolset', ['yfc2']) +toolset.inherit('yfc2', 'yfc1') + +ENGINE.register_action('yfc2.link', 'yfc2-link') + +def init(*args): + pass +""" +) + t.write("jamfile.jam", "exe a : a.cpp ;") t.write("jamroot.jam", "using yfc1 ;") From 1731a892f03c2bc67c46e95d03e9980d56cb118e Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 19:40:41 -0500 Subject: [PATCH 131/158] Fix BasicTarget type assertions --- src/build/targets.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/build/targets.py b/src/build/targets.py index 8ac2d33fa..6f71177c3 100644 --- a/src/build/targets.py +++ b/src/build/targets.py @@ -676,7 +676,7 @@ class MainTarget (AbstractTarget): def add_alternative (self, target): """ Add a new alternative for this target. """ - assert isinstance(target, AbstractTarget) + assert isinstance(target, BasicTarget) d = target.default_build () if self.alternatives_ and self.default_build_ != d: @@ -895,9 +895,9 @@ class BasicTarget (AbstractTarget): """ def __init__ (self, name, project, sources, requirements = None, default_build = None, usage_requirements = None): assert is_iterable_typed(sources, basestring) - assert isinstance(requirements, property_set.PropertySet) - assert isinstance(default_build, property_set.PropertySet) - assert isinstance(usage_requirements, property_set.PropertySet) + assert isinstance(requirements, property_set.PropertySet) or requirements is None + assert isinstance(default_build, property_set.PropertySet) or default_build is None + assert isinstance(usage_requirements, property_set.PropertySet) or usage_requirements is None AbstractTarget.__init__ (self, name, project) for s in sources: From b55a11515ac9f3ec0fc6264679b75c0f18256786 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 19:53:26 -0500 Subject: [PATCH 132/158] Fix message test. --- src/kernel/bootstrap.jam | 1 - src/tools/message.py | 18 +++++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/kernel/bootstrap.jam b/src/kernel/bootstrap.jam index c4320dc29..74ee5d34f 100644 --- a/src/kernel/bootstrap.jam +++ b/src/kernel/bootstrap.jam @@ -140,7 +140,6 @@ if ! $(dont-build) } else { - ECHO "Boost.Build V2 Python port (experimental)" ; # Define additional interface exposed to Python code. Python code will # also have access to select bjam builtins in the 'bjam' module, but diff --git a/src/tools/message.py b/src/tools/message.py index 5ec3efc76..3f276f93e 100644 --- a/src/tools/message.py +++ b/src/tools/message.py @@ -15,9 +15,10 @@ from b2.manager import get_manager class MessageTargetClass(targets.BasicTarget): - def __init__(self, name, project, *args): - - targets.BasicTarget.__init__(self, name, project, []) + def __init__(self, name, project, sources, requirements, default_build, + usage_requirements, *args): + targets.BasicTarget.__init__( + self, name, project, sources, requirements, default_build, usage_requirements) self.args = args self.built = False @@ -38,9 +39,16 @@ def message(name, *args): name = name[0] t = get_manager().targets() - project = get_manager().projects().current() - return t.main_target_alternative(MessageTargetClass(*((name, project) + args))) + return t.main_target_alternative( + MessageTargetClass( + name, project, + t.main_target_sources([], name), + t.main_target_requirements([], project), + t.main_target_default_build([], project), + t.main_target_usage_requirements([], project), + *args + )) get_manager().projects().add_rule("message", message) From 7c656245fbbae41342288dddef9f86878d332094 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 20:01:21 -0500 Subject: [PATCH 133/158] Partially fix project_test3 --- src/build/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build/project.py b/src/build/project.py index 357de848b..499d12cca 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -184,7 +184,7 @@ class ProjectRegistry: if not found: print "error: Could not find parent for project at '%s'" % location - print "error: Did not find Jamfile or project-root.jam in any parent directory." + print "error: Did not find Jamfile.jam or Jamroot.jam in any parent directory." sys.exit(1) return self.load(os.path.dirname(found[0])) From a08ec65a24229d1c80bbc07c461a0ceee0102c4b Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 20:03:51 -0500 Subject: [PATCH 134/158] Fix regression test --- src/tools/testing-aux.jam | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/testing-aux.jam b/src/tools/testing-aux.jam index a264e4c35..30309fbb8 100644 --- a/src/tools/testing-aux.jam +++ b/src/tools/testing-aux.jam @@ -1,3 +1,5 @@ +import feature ; + # This module is imported by testing.py. The definitions here are # too tricky to do in Python From db45f34192e6e362e3c1a20c2c419fb5570b199d Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 20:14:25 -0500 Subject: [PATCH 135/158] Fix scanner_causing_rebuilds test --- test/scanner_causing_rebuilds.py | 48 ++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/test/scanner_causing_rebuilds.py b/test/scanner_causing_rebuilds.py index 2b5fc501c..d1ff66bfd 100755 --- a/test/scanner_causing_rebuilds.py +++ b/test/scanner_causing_rebuilds.py @@ -68,6 +68,54 @@ actions foo $(.touch) "$(<[2])" } """) + +t.write( + 'foo.py', +""" +import os + +from b2.build import type as type_, generators +from b2.tools import common +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +type_.register('FOO', ['foo']) +type_.register('BAR', ['bar']) +generators.register_standard('foo.foo', ['FOO'], ['CPP', 'BAR']) + +def sleep_cmd(delay): + if os.name == 'nt': + return 'ping 127.0.0.1 -n {} -w 1000 >NUL'.format(delay) + return 'sleep {}'.format(delay) + +def foo(targets, sources, properties): + cpp, bar = targets + foo = sources[0] + # We add the INCLUDE relationship between our generated CPP & BAR targets + # explicitly instead of relying on Boost Jam's internal implementation + # detail - automatically adding such relationships between all files + # generated by the same action. This way our test will continue to function + # correctly even if the related Boost Jam implementation detail changes. + # Note that adding this relationship by adding an #include directive in our + # generated CPP file is not good enough as such a relationship would get + # added only after the scanner target's relationships have already been + # established and they (as affected by our initial INCLUDE relationship) are + # the original reason for this test failing. + bjam.call('INCLUDES', cpp, bar) + +ENGINE.register_action( + 'foo.foo', + ''' + {touch} "$(<[1])" + {sleep} + {touch} "$(<[2])" + '''.format(touch=common.file_creation_command(), sleep=sleep_cmd(2)) +) +""" +) + t.write("x.foo", "") t.write("jamroot.jam", """\ import foo ; From 0490f580716016c002bcd53ec1c8acade0b1f3a7 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 20:21:06 -0500 Subject: [PATCH 136/158] Fix source_order test --- test/source_order.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/test/source_order.py b/test/source_order.py index f42f4ccae..af8fd54bc 100755 --- a/test/source_order.py +++ b/test/source_order.py @@ -27,6 +27,37 @@ actions check-order generators.register-composing check-order.check-order : C : ORDER_TEST ; """) +t.write( + 'check-order.py', +""" +import bjam + +from b2.build import type as type_, generators +from b2.tools import common +from b2.manager import get_manager + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +type_.register('ORDER_TEST', ['order-test']) + +generators.register_composing('check-order.check-order', ['C'], ['ORDER_TEST']) + +def check_order(targets, sources, properties): + ENGINE.set_target_variable(targets, 'SPACE', ' ') + ENGINE.set_target_variable(targets, 'nl', '\\n') + +ENGINE.register_action( + 'check-order.check-order', + function=check_order, + command=''' + echo$(SPACE)$(>[1])>$(<[1]) + echo$(SPACE)$(>[2-])>>$(<[1])$(nl) + ''' +) +""" +) + # The aliases are necessary for this test, since # the targets were sorted by virtual target # id, not by file name. From fd29f0fc9927a84153079459261e2d60ffaf9432 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 20:31:13 -0500 Subject: [PATCH 137/158] Fix stage test --- src/build/virtual_target.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/build/virtual_target.py b/src/build/virtual_target.py index 2a0a1e5cb..e5a130476 100644 --- a/src/build/virtual_target.py +++ b/src/build/virtual_target.py @@ -1102,8 +1102,8 @@ class Subvariant: or as dependency properties. Targets referred with dependency property are returned a properties, not targets.""" if __debug__: - from .targets import GenerateResult - assert isinstance(result, GenerateResult) + from .property import Property + assert is_iterable_typed(result, (VirtualTarget, Property)) # Find directly referenced targets. deps = self.build_properties().dependency() all_targets = self.sources_ + deps From 5369b25498937f0180ab4b85cc9418c48e61a58a Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 21:08:25 -0500 Subject: [PATCH 138/158] Partially fix test_rc. --- src/tools/rc.py | 1 + test/test_rc.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/src/tools/rc.py b/src/tools/rc.py index d9d840ffe..c7a02dbb6 100644 --- a/src/tools/rc.py +++ b/src/tools/rc.py @@ -97,6 +97,7 @@ def rc_register_action(action_name, function = None): def rc_compile_resource(targets, sources, properties): rc_type = bjam.call('get-target-variable', targets, '.RC_TYPE') + rc_type = rc_type[0] if rc_type else '' global engine engine.set_update_action('rc.compile.resource.' + rc_type, targets, sources, properties) diff --git a/test/test_rc.py b/test/test_rc.py index 510b47275..6d6478eeb 100755 --- a/test/test_rc.py +++ b/test/test_rc.py @@ -73,6 +73,44 @@ set-generated-obj-suffix windows ; set-generated-obj-suffix cygwin ; """ % toolsetName) + t.write( + toolsetName + '.py', +""" +from b2.build import feature, type as type_ +from b2.manager import get_manager +from b2.tools import rc, common + +MANAGER = get_manager() +ENGINE = MANAGER.engine() + +toolset_name = "{}" + +feature.extend('toolset', [toolset_name]) + +def init(*args): + pass + +rc.configure(['dummy-rc-command'], ['' + toolset_name], ['dummy']) + +ENGINE.register_action( + 'rc.compile.resource.dummy', + ''' + %s "$(<)" + ''' % common.file_creation_command() +) + +def set_generated_obj_suffix(target_os=''): + requirements = ['' + toolset_name] + if target_os: + requirements.append('' + target_os) + type_.set_generated_target_suffix('OBJ', requirements, 'obj') + +set_generated_obj_suffix() +set_generated_obj_suffix('windows') +set_generated_obj_suffix('cygwin') +""".format(toolsetName) + ) + # Prepare project source files. t.write("jamroot.jam", """\ ECHO {{{ [ modules.peek : XXX ] [ modules.peek : NOEXEC ] }}} ; From 8c656bab6b5c344d17628157398f64a54585d242 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 22:39:59 -0500 Subject: [PATCH 139/158] Fix indirect_conditional test. --- src/build/project.py | 31 ++++++++++++++++++------------- src/build_system.py | 2 ++ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/src/build/project.py b/src/build/project.py index 499d12cca..fff4b137f 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -298,16 +298,17 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" # See if the Jamfile is where it should be. is_jamroot = False jamfile_to_load = b2.util.path.glob([dir], self.JAMROOT) - if not jamfile_to_load: - jamfile_to_load = self.find_jamfile(dir) - else: + if jamfile_to_load: if len(jamfile_to_load) > 1: - get_manager().errors()("Multiple Jamfiles found at '%s'\n" +\ - "Filenames are: %s" - % (dir, [os.path.basename(j) for j in jamfile_to_load])) - + get_manager().errors()( + "Multiple Jamfiles found at '{}'\n" + "Filenames are: {}" + .format(dir, ' '.join(os.path.basename(j) for j in jamfile_to_load)) + ) is_jamroot = True jamfile_to_load = jamfile_to_load[0] + else: + jamfile_to_load = self.find_jamfile(dir) dir = os.path.dirname(jamfile_to_load) if not dir: @@ -330,7 +331,6 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" self.jamfile_modules[jamfile_module] = True bjam.call("load", jamfile_module, jamfile_to_load) - basename = os.path.basename(jamfile_to_load) if is_jamroot: jamfile = self.find_jamfile(dir, no_errors=True) @@ -369,7 +369,7 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" print "warning: specified no project id" print "warning: the --build-dir option will be ignored" - def end_load(self, previous_project): + def end_load(self, previous_project=None): if not self.current_project: self.manager.errors()( 'Ending project loading requested when there was no project currently ' @@ -423,8 +423,6 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" assert isinstance(basename, basestring) or basename is None jamroot = False parent_module = None - - parent_module = None; if module_name == "test-config": # No parent pass @@ -558,6 +556,11 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" def current(self): """Returns the project which is currently being loaded.""" + if not self.current_project: + get_manager().errors()( + 'Reference to the project currently being loaded requested ' + 'when there was no project module being loaded.' + ) return self.current_project def set_current(self, c): @@ -576,8 +579,10 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" self.current_project = project def pop_current(self): - self.current_project = self.saved_current_project[-1] - del self.saved_current_project[-1] + if self.saved_current_project: + self.current_project = self.saved_current_project.pop() + else: + self.current_project = None def attributes(self, project): """Returns the project-attribute instance for the diff --git a/src/build_system.py b/src/build_system.py index 96dca751b..6e78ced50 100644 --- a/src/build_system.py +++ b/src/build_system.py @@ -327,6 +327,8 @@ def load_configuration_files(): initialize_config_module('project-config', os.path.dirname(file[0])) load_config('project-config', "project-config.jam", [os.path.dirname(file[0])], True) + get_manager().projects().end_load() + # Autoconfigure toolsets based on any instances of --toolset=xx,yy,...zz or # toolset=xx,yy,...zz in the command line. May return additional properties to From 1a51b6aa072c7aac5038cebc0ce2d78c32a15001 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sun, 9 Oct 2016 22:50:48 -0500 Subject: [PATCH 140/158] Fix dependency_property test. --- test/dependency_property.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/dependency_property.py b/test/dependency_property.py index cdd8055b0..bcced6ad9 100644 --- a/test/dependency_property.py +++ b/test/dependency_property.py @@ -10,7 +10,6 @@ # targets ended up being in the same location. import BoostBuild -import string t = BoostBuild.Tester() @@ -31,6 +30,10 @@ void foo() {} """) t.run_build_system(["--no-error-backtrace"], status=1) -t.fail_test(string.find(t.stdout(), "Tried to build the target twice") == -1) +output = t.stdout() +t.fail_test( + "Tried to build the target twice" not in output and + "Duplicate name of actual target" not in output +) t.cleanup() From cf0440104989fdc55085d00356445dd95c829cd1 Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Sat, 15 Oct 2016 10:44:01 -0500 Subject: [PATCH 141/158] Fix test_rc for Py26 tests. --- test/test_rc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_rc.py b/test/test_rc.py index 6d6478eeb..1ffac15b0 100755 --- a/test/test_rc.py +++ b/test/test_rc.py @@ -83,7 +83,7 @@ from b2.tools import rc, common MANAGER = get_manager() ENGINE = MANAGER.engine() -toolset_name = "{}" +toolset_name = "{0}" feature.extend('toolset', [toolset_name]) From be1cadf2f3c2b989e4d8f20ea8f68e02a3a2397e Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Tue, 25 Oct 2016 16:33:04 -0500 Subject: [PATCH 142/158] Make properties sorted, just like Jam. --- src/build/property_set.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/build/property_set.py b/src/build/property_set.py index e39a5aa56..3fc86de27 100644 --- a/src/build/property_set.py +++ b/src/build/property_set.py @@ -45,11 +45,14 @@ def create (raw_properties = []): else: x = [property.create_from_string(ps) for ps in raw_properties] - # these two lines of code are optimized to the current state - # of the Property class. since this function acts as the caching + # These two lines of code are optimized to the current state + # of the Property class. Since this function acts as the caching # frontend to the PropertySet class modifying these two lines - # could have a severe performance penalty. be careful - x = sorted(set(x), key=lambda p: p.id) + # could have a severe performance penalty. Be careful. + # It would be faster to sort by p.id, but some projects may rely + # on the fact that the properties are ordered alphabetically. So, + # we maintain alphabetical sorting so as to maintain backward compatibility. + x = sorted(set(x), key=lambda p: (p.feature.name, p.value, p.condition)) key = tuple(p.id for p in x) if key not in __cache: From 710428b6387940727a4a7ad72e28238a71a3840a Mon Sep 17 00:00:00 2001 From: Aaron Boman Date: Thu, 27 Oct 2016 20:00:27 -0500 Subject: [PATCH 143/158] Fix unintentional masking of ImportErrors. Closes #121 --- src/build/project.py | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/build/project.py b/src/build/project.py index fff4b137f..9ec2ccb79 100644 --- a/src/build/project.py +++ b/src/build/project.py @@ -759,15 +759,21 @@ Please consult the documentation at 'http://boost.org/boost-build2'.""" # 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) + except ImportError: + # if the module is not found in the b2 package, + # this error will be handled later + pass + else: + # we've found the module, now let's try loading it. + # it's possible that the module itself contains an ImportError + # which is why we're loading it in this else clause so that the + # proper error message is shown to the end user. + # TODO: does this module name really need to be mangled like this? mname = name + "__for_jamfile" self.loaded_tool_module_path_[mname] = location module = imp.load_module(mname, f, location, description) self.loaded_tool_modules_[name] = module return module - 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 From 1be1c5b42cbcd02666b760d990754805ed473c1e Mon Sep 17 00:00:00 2001 From: Stefan Seefeld Date: Fri, 28 Oct 2016 13:23:44 -0400 Subject: [PATCH 144/158] Fix NumPy detection bug in numpy-test. --- src/tools/python.jam | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/tools/python.jam b/src/tools/python.jam index 1d5c306f3..b8968848f 100644 --- a/src/tools/python.jam +++ b/src/tools/python.jam @@ -1276,10 +1276,7 @@ rule numpy-test ( name : sources * : requirements * ) { numpy-include = [ python.numpy-include ] ; # yuk ! - if $(.numpy) = false - { - requirements += no ; - } + if ! $(.numpy) { requirements += no ; } sources ?= $(name).py $(name).cpp ; name = [ regex.replace $(name) "[/]" "~" ] ; return [ testing.make-test run-pyd From 32113ca3ddbc637d08e85c44502f3149d37323e0 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 8 Nov 2016 10:18:27 -0600 Subject: [PATCH 145/158] Fix output-xml not getting correctly generated on parallel builds. --- src/build-system.jam | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/build-system.jam b/src/build-system.jam index 76db2d377..1a3ac7904 100644 --- a/src/build-system.jam +++ b/src/build-system.jam @@ -971,7 +971,12 @@ local rule should-clean-project ( project ) DEPENDS all : $(actual-targets) ; if UPDATE_NOW in [ RULENAMES ] { - local ok = [ UPDATE_NOW all $(.out-xml) ] ; + local ok = [ UPDATE_NOW all ] ; + # Force sequence updating of regular targets, then the xml + # log output target. To ensure the output records all built + # as otherwise if could execute out-of-sequence when + # doing parallel builds. + ok += [ UPDATE_NOW $(.out-xml) : : ignore-minus-n ] ; if $(.post-build-hook) { $(.post-build-hook) $(ok) ; From b1df9b928b0ae182385021b86a207597ddc0e383 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 8 Nov 2016 10:42:24 -0600 Subject: [PATCH 146/158] Fix extra arg value when post-build is called. --- src/build-system.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build-system.jam b/src/build-system.jam index 1a3ac7904..ae3984621 100644 --- a/src/build-system.jam +++ b/src/build-system.jam @@ -976,7 +976,7 @@ local rule should-clean-project ( project ) # log output target. To ensure the output records all built # as otherwise if could execute out-of-sequence when # doing parallel builds. - ok += [ UPDATE_NOW $(.out-xml) : : ignore-minus-n ] ; + UPDATE_NOW $(.out-xml) : : ignore-minus-n ; if $(.post-build-hook) { $(.post-build-hook) $(ok) ; From a5cb6203365e0901971366445c95068f2f84529f Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 8 Nov 2016 13:27:42 -0600 Subject: [PATCH 147/158] Fix BB test failures from double UPDATE_NOW calls. --- src/build-system.jam | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/build-system.jam b/src/build-system.jam index ae3984621..185526c70 100644 --- a/src/build-system.jam +++ b/src/build-system.jam @@ -976,7 +976,10 @@ local rule should-clean-project ( project ) # log output target. To ensure the output records all built # as otherwise if could execute out-of-sequence when # doing parallel builds. - UPDATE_NOW $(.out-xml) : : ignore-minus-n ; + if $(.out-xml) + { + UPDATE_NOW $(.out-xml) : : ignore-minus-n ; + } if $(.post-build-hook) { $(.post-build-hook) $(ok) ; From 4ee16d44c2da8a318b30caf7f5ae0ff00654e080 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Mon, 28 Nov 2016 13:26:22 -0600 Subject: [PATCH 148/158] Fix macro redef errors on some compilers. --- src/engine/function.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/engine/function.c b/src/engine/function.c index bd42237e0..5f244e286 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -32,7 +32,9 @@ /* */ #ifndef FUNCTION_DEBUG_PROFILE +#undef PROFILE_ENTER_LOCAL #define PROFILE_ENTER_LOCAL(x) +#undef PROFILE_EXIT_LOCAL #define PROFILE_EXIT_LOCAL(x) #endif From af046405c513a4ac276a8de8562cee9847681f15 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Tue, 29 Nov 2016 06:46:32 -0600 Subject: [PATCH 149/158] Fix var declare errors from empty declaration on some compilers. --- src/engine/function.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/function.c b/src/engine/function.c index 5f244e286..6d7b0feba 100644 --- a/src/engine/function.c +++ b/src/engine/function.c @@ -33,7 +33,7 @@ #ifndef FUNCTION_DEBUG_PROFILE #undef PROFILE_ENTER_LOCAL -#define PROFILE_ENTER_LOCAL(x) +#define PROFILE_ENTER_LOCAL(x) static int unused_LOCAL_##x = 0 #undef PROFILE_EXIT_LOCAL #define PROFILE_EXIT_LOCAL(x) #endif From 9396ede927da154b415c8ae550e01c7b1da06d7a Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Mon, 5 Dec 2016 13:13:25 -0500 Subject: [PATCH 150/158] Added doc for bzip2 toolset --- doc/src/reference.xml | 77 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/doc/src/reference.xml b/doc/src/reference.xml index 7e4c4ec86..b46cea063 100644 --- a/doc/src/reference.xml +++ b/doc/src/reference.xml @@ -1698,6 +1698,83 @@ using zlib : 1.2.7 : : <toolset>gcc ;

+
+ bzip2 + bzip2 + + Provides support for the + bzip2 library. bzip2 + can be configured either to use precompiled binaries or to + build the library from source. + + bzip2 can be initialized using the following syntax + +using bzip2 : version : options : condition : is-default ; + + Options for using a prebuilt library: + + + search + + The directory containing the bzip2 binaries. + + + + name + + Overrides the default library name. + + + + include + + The directory containing the bzip2 headers. + + + + If none of these options is specified, then the environmental + variables BZIP2_LIBRARY_PATH, BZIP2_NAME, and BZIP2_INCLUDE will be + used instead. + Options for building bzip2 from source: + + + source + + The bzip2 source directory. Defaults to the + environmental variable BZIP2_SOURCE. + + + + tag + + Sets the tag + property to adjust the file name of the library. Ignored + when using precompiled binaries. + + + + build-name + + The base name to use for the compiled library. + Ignored when using precompiled binaries. + + + + Examples: + +# Find bzip in the default system location +using bzip2 ; +# Build bzip from source +using bzip2 : 1.0.6 : <source>/home/sergey/src/bzip2-1.0.6 ; +# Find bzip in /usr/local +using bzip2 : 1.0.6 : <include>/usr/local/include <search>/usr/local/lib ; +# Build bzip from source for msvc and find +# prebuilt binaries for gcc. +using bzip2 : 1.0.6 : <source>C:/Devel/src/bzip2-1.0.6 : <toolset>msvc ; +using bzip2 : 1.0.6 : : <toolset>gcc ; + +
+
From 373fb6f76962caca9da109d4fe1e820af996326d Mon Sep 17 00:00:00 2001 From: Andrea Bocci Date: Sat, 14 Jan 2017 11:59:31 +0100 Subject: [PATCH 151/158] Do not reuse the same target for different library link checks --- src/build/ac.jam | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/build/ac.jam b/src/build/ac.jam index c6e36c6a5..c01dc5997 100644 --- a/src/build/ac.jam +++ b/src/build/ac.jam @@ -76,14 +76,6 @@ rule construct-library ( name : property-set : provided-path ? ) rule find-library ( properties : names + : provided-path ? ) { local result ; - if ! $(.main.cpp) - { - local a = [ class.new action : ac.generate-main : - [ property-set.empty ] ] ; - .main.cpp = [ virtual-target.register - [ class.new file-target main.cpp exact - : CPP : $(.project) : $(a) ] ] ; - } if [ $(properties).get ] = shared { link-opts = shared static ; @@ -100,8 +92,12 @@ rule find-library ( properties : names + : provided-path ? ) { local name = $(names-iter[1]) ; local lib = [ construct-library $(name) : $(properties) : $(provided-path) ] ; + local a = [ class.new action : ac.generate-main : + [ property-set.empty ] ] ; + local main.cpp = [ virtual-target.register + [ class.new file-target main-$(name).cpp exact : CPP : $(.project) : $(a) ] ] ; local test = [ generators.construct $(.project) $(name) : EXE - : [ $(properties).add $(lib[1]) ] : $(.main.cpp) $(lib[2-]) + : [ $(properties).add $(lib[1]) ] : $(main.cpp) $(lib[2-]) : true ] ; local jam-targets ; for t in $(test[2-]) From c413447f4c21447174e750478bcd9818412d3279 Mon Sep 17 00:00:00 2001 From: Deniz Bahadir Date: Thu, 19 Jan 2017 16:25:18 +0100 Subject: [PATCH 152/158] Fix generating pre-compiled headers (pch) with clang (on linux). --- src/tools/clang-linux.jam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clang-linux.jam b/src/tools/clang-linux.jam index f6dcda9f3..f977c8c72 100644 --- a/src/tools/clang-linux.jam +++ b/src/tools/clang-linux.jam @@ -153,7 +153,7 @@ rule compile.c++.pch ( targets * : sources * : properties * ) { } actions compile.c++.pch { - rm -f "$(<)" && "$(CONFIG_COMMAND)" -x c++-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -Xclang -emit-pth -o "$(<)" "$(>)" + rm -f "$(<)" && "$(CONFIG_COMMAND)" -c -x c++-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -Xclang -emit-pth -o "$(<)" "$(>)" } rule compile.c.pch ( targets * : sources * : properties * ) { @@ -164,7 +164,7 @@ rule compile.c.pch ( targets * : sources * : properties * ) { actions compile.c.pch { - rm -f "$(<)" && "$(CONFIG_COMMAND)" -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -Xclang -emit-pth -o "$(<)" "$(>)" + rm -f "$(<)" && "$(CONFIG_COMMAND)" -c -x c-header $(OPTIONS) $(USER_OPTIONS) -D$(DEFINES) -I"$(INCLUDES)" -Xclang -emit-pth -o "$(<)" "$(>)" } ############################################################################### From e0eea1133cf8a35b484056d65d859250f0475485 Mon Sep 17 00:00:00 2001 From: Rene Rivera Date: Fri, 20 Jan 2017 21:10:20 -0600 Subject: [PATCH 153/158] Fix errors with tool path with spaces when on Windows. Like the gcc toolset this now quotes the command to check the compiler version before SHELL'ing out to get the version info. --- src/tools/emscripten.jam | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/tools/emscripten.jam b/src/tools/emscripten.jam index 2ad1b804a..c9a0009db 100644 --- a/src/tools/emscripten.jam +++ b/src/tools/emscripten.jam @@ -21,9 +21,10 @@ rule init ( version ? : command * : options * ) : $(command) ] ; # Determine the version - local command-string = $(command:J=" ") ; if $(command) - { + { + local command-string = \"$(command)\" ; + command-string = $(command-string:J=" ") ; version ?= [ MATCH "([0-9.]+)" : [ SHELL "$(command-string) --version" ] ] ; } From cb70dbeb5cadfe94b48ad0d97452811cc4e5bbfc Mon Sep 17 00:00:00 2001 From: Arkadiy Shapkin Date: Wed, 1 Feb 2017 22:13:49 +0300 Subject: [PATCH 154/158] Some fixes for VS2017 #157 Path autodetection to VS works only if it installed to default path --- src/engine/build.bat | 16 +++++++++++++--- src/engine/build.jam | 1 + src/tools/msvc.py | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/engine/build.bat b/src/engine/build.bat index 2086f37a7..a63285c52 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -106,9 +106,19 @@ if NOT "_%VS150COMNTOOLS%_" == "__" ( set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" goto :eof) call :Clear_Error -if EXIST "%ProgramFiles%\Microsoft Visual Studio 15.0\VC\VCVARSALL.BAT" ( +if EXIST "%ProgramFiles%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio 15.0\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio\2017\Enterprise\VC\" + goto :eof) +call :Clear_Error +if EXIST "%ProgramFiles%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" ( + set "BOOST_JAM_TOOLSET=vc15" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio\2017\Professional\VC\" + goto :eof) +call :Clear_Error +if EXIST "%ProgramFiles%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" ( + set "BOOST_JAM_TOOLSET=vc15" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio\2017\Community\VC\" goto :eof) call :Clear_Error if NOT "_%VS140COMNTOOLS%_" == "__" ( @@ -460,7 +470,7 @@ if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc15_" goto Skip_VC15 if NOT "_%VS150COMNTOOLS%_" == "__" ( set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" ) -if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%VCVARSALL.BAT" %BOOST_JAM_ARGS% +if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%Auxiliary\Build\vcvarsall.bat" %BOOST_JAM_ARGS% if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" ( if "_%VCINSTALLDIR%_" == "__" ( set "PATH=%BOOST_JAM_TOOLSET_ROOT%bin;%PATH%" diff --git a/src/engine/build.jam b/src/engine/build.jam index e16b24085..59d0cb658 100644 --- a/src/engine/build.jam +++ b/src/engine/build.jam @@ -401,6 +401,7 @@ toolset vc14 cl : /Fe /Fe /Fd /Fo : -D [ opt --debug : /MTd /DEBUG /Z7 /Od /Ob0 /wd4996 ] -I$(--python-include) -I$(--extra-include) : kernel32.lib advapi32.lib user32.lib $(--python-lib[1]) ; +## Microsoft Visual C++ 2017 toolset vc15 cl : /Fe /Fe /Fd /Fo : -D : /nologo [ opt --release : /GL /MT /O2 /Ob2 /Gy /GF /GA /wd4996 ] diff --git a/src/tools/msvc.py b/src/tools/msvc.py index baa57e831..efd3a908a 100644 --- a/src/tools/msvc.py +++ b/src/tools/msvc.py @@ -772,7 +772,7 @@ def configure_really(version=None, options=[]): # version from the path. # FIXME: We currently detect both Microsoft Visual Studio 9.0 and # 9.0express as 9.0 here. - if re.search("Microsoft Visual Studio 15", command): + if re.search("Microsoft Visual Studio[\/\\]2017", command): version = '15.0' elif re.search("Microsoft Visual Studio 14", command): version = '14.0' From 6a76ad35f863173b5b34639e5815355e5a9faba8 Mon Sep 17 00:00:00 2001 From: Thomas Kent Date: Thu, 2 Feb 2017 16:21:00 -0600 Subject: [PATCH 155/158] Fixed paths for vc15 and arch variable --- src/engine/build.bat | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/engine/build.bat b/src/engine/build.bat index a63285c52..877e830dd 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -106,19 +106,19 @@ if NOT "_%VS150COMNTOOLS%_" == "__" ( set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" goto :eof) call :Clear_Error -if EXIST "%ProgramFiles%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( +if EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio\2017\Enterprise\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Enterprise\VC\" goto :eof) call :Clear_Error -if EXIST "%ProgramFiles%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" ( +if EXIST "%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio\2017\Professional\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Professional\VC\" goto :eof) call :Clear_Error -if EXIST "%ProgramFiles%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" ( +if EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles%\Microsoft Visual Studio\2017\Community\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Community\VC\" goto :eof) call :Clear_Error if NOT "_%VS140COMNTOOLS%_" == "__" ( @@ -470,6 +470,13 @@ if NOT "_%BOOST_JAM_TOOLSET%_" == "_vc15_" goto Skip_VC15 if NOT "_%VS150COMNTOOLS%_" == "__" ( set "BOOST_JAM_TOOLSET_ROOT=%VS150COMNTOOLS%..\..\VC\" ) + +REM vc15 vsvarsall requires the architecture as a parameter. +set BOOST_JAM_ARCH=x86 +if NOT "_%PROCESSOR_ARCHITECTURE%_" == "__" set BOOST_JAM_ARCH=%PROCESSOR_ARCHITECTURE% +if NOT "_%Platform%_" == "__" set BOOST_JAM_ARCH=%Platform% +set BOOST_JAM_ARGS=%BOOST_JAM_ARGS% %BOOST_JAM_ARCH% + if "_%VCINSTALLDIR%_" == "__" call :Call_If_Exists "%BOOST_JAM_TOOLSET_ROOT%Auxiliary\Build\vcvarsall.bat" %BOOST_JAM_ARGS% if NOT "_%BOOST_JAM_TOOLSET_ROOT%_" == "__" ( if "_%VCINSTALLDIR%_" == "__" ( From d99f08fe5bddda83f84f211f535d51cac4ffda88 Mon Sep 17 00:00:00 2001 From: Thomas Kent Date: Wed, 8 Feb 2017 16:35:52 -0600 Subject: [PATCH 156/158] Fixed a typo in the paths to VC15 installs. --- src/engine/build.bat | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/engine/build.bat b/src/engine/build.bat index 877e830dd..34caf37c9 100644 --- a/src/engine/build.bat +++ b/src/engine/build.bat @@ -108,17 +108,17 @@ if NOT "_%VS150COMNTOOLS%_" == "__" ( call :Clear_Error if EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Enterprise\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Enterprise\VC\" goto :eof) call :Clear_Error -if EXIST "%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" ( +if EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Professional\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Professional\VC\" goto :eof) call :Clear_Error if EXIST "%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat" ( set "BOOST_JAM_TOOLSET=vc15" - set "BOOST_JAM_TOOLSET_ROOT=%ProgramFilesi(x86)%\Microsoft Visual Studio\2017\Community\VC\" + set "BOOST_JAM_TOOLSET_ROOT=%ProgramFiles(x86)%\Microsoft Visual Studio\2017\Community\VC\" goto :eof) call :Clear_Error if NOT "_%VS140COMNTOOLS%_" == "__" ( From be31aad5ffe47e51c9780c8c3107cd419d0b48e7 Mon Sep 17 00:00:00 2001 From: Niklas Angare Date: Sat, 11 Feb 2017 22:39:28 +0100 Subject: [PATCH 157/158] Fixed setting of SONAME for toolset qcc The SONAME is now set unconditionally. The use if HAVE_SONAME was probably mistakenly copied from gcc.jam. --- src/tools/qcc.jam | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/qcc.jam b/src/tools/qcc.jam index 3b3557894..faa353064 100644 --- a/src/tools/qcc.jam +++ b/src/tools/qcc.jam @@ -234,5 +234,5 @@ rule link.dll ( targets * : sources * : properties * ) # actions link.dll bind LIBRARIES { - "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,-R$(SPACE)-Wl,"$(RPATH)" -o "$(<)" $(HAVE_SONAME)-Wl,-h$(SPACE)-Wl,$(<[1]:D=) -shared "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-ST) -l$(FINDLIBS-SA) $(OPTIONS) + "$(CONFIG_COMMAND)" -L"$(LINKPATH)" -Wl,-R$(SPACE)-Wl,"$(RPATH)" -o "$(<)" -Wl,-h$(SPACE)-Wl,$(<[1]:D=) -shared "$(>)" "$(LIBRARIES)" -l$(FINDLIBS-ST) -l$(FINDLIBS-SA) $(OPTIONS) } From abdf4805c484e3222dd440a95cb79dc00be67256 Mon Sep 17 00:00:00 2001 From: Steven Watanabe Date: Wed, 1 Mar 2017 08:43:15 -0700 Subject: [PATCH 158/158] Include options/ and contrib/ when installing Boost.Build. --- Jamroot.jam | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Jamroot.jam b/Jamroot.jam index 2f50eed09..d7f76b7c9 100644 --- a/Jamroot.jam +++ b/Jamroot.jam @@ -35,7 +35,9 @@ package.install-data boost-build-core $(SELF)/boost-build.jam $(SELF)/src/build-system.jam [ path.glob-tree $(SELF)/src/build : *.jam *.py ] + [ path.glob-tree $(SELF)/src/contrib : *.jam *.py ] [ path.glob-tree $(SELF)/src/kernel : *.jam *.py ] + [ path.glob-tree $(SELF)/src/options : *.jam *.py ] [ path.glob-tree $(SELF)/src/util : *.jam *.py ] [ path.glob-tree $(SELF)/src/tools : *.jam *.py *.xml *.xsl *.doxyfile *.hpp ] $(e2)