| import modules ; |
| import option ; |
| import os ; |
| import path ; |
| import project ; |
| import build-system ; |
| import version ; |
| |
| #Shell with trailing line removed http://lists.boost.org/boost-build/2007/08/17051.php |
| rule trim-nl ( str extras * ) { |
| return [ MATCH "([^ |
| ]*)" : $(str) ] $(extras) ; |
| } |
| rule _shell ( cmd : extras * ) { |
| return [ trim-nl [ SHELL $(cmd) : $(extras) ] ] ; |
| } |
| |
| rule shell_or_fail ( cmd ) { |
| local ret = [ SHELL $(cmd) : exit-status ] ; |
| if $(ret[2]) != 0 { |
| exit $(cmd) failed : 1 ; |
| } |
| } |
| |
| rule shell_or_die ( cmd ) { |
| local ret = [ SHELL $(cmd) : exit-status ] ; |
| if $(ret[2]) != 0 { |
| exit $(cmd) failed : 1 ; |
| } |
| return [ trim-nl $(ret[1]) ] ; |
| } |
| |
| cxxflags = [ os.environ "CXXFLAGS" ] ; |
| cflags = [ os.environ "CFLAGS" ] ; |
| ldflags = [ os.environ "LDFLAGS" ] ; |
| |
| #Run g++ with empty main and these arguments to see if it passes. |
| rule test_flags ( flags * : main ? ) { |
| flags = $(cxxflags) $(ldflags) $(flags) ; |
| if ! $(main) { |
| main = "int main() {}" ; |
| } |
| local cmd = "bash -c \"g++ "$(flags:J=" ")" -x c++ - <<<'$(main)' -o $(TOP)/dummy >/dev/null 2>/dev/null && rm $(TOP)/dummy 2>/dev/null\"" ; |
| local ret = [ SHELL $(cmd) : exit-status ] ; |
| if --debug-configuration in [ modules.peek : ARGV ] { |
| echo $(cmd) ; |
| echo $(ret) ; |
| } |
| if $(ret[2]) = 0 { |
| return true ; |
| } else { |
| return ; |
| } |
| } |
| |
| rule test_header ( name ) { |
| return [ test_flags "-include $(name)" ] ; |
| } |
| |
| requirements = ; |
| |
| FORCE-STATIC = [ option.get "static" : : "yes" ] ; |
| if $(FORCE-STATIC) { |
| requirements += <link>static <runtime-link>static ; |
| } |
| |
| rule test_library ( name ) { |
| if $(FORCE-STATIC) { |
| return [ test_flags "-Wl,-Bstatic -l$(name) -Wl,-Bdynamic" ] ; |
| } else { |
| return [ test_flags "-l$(name)" ] ; |
| } |
| } |
| |
| { |
| local cleaning = [ option.get "clean" : : yes ] ; |
| cleaning ?= [ option.get "clean-all" : no : yes ] ; |
| if "clean" in [ modules.peek : ARGV ] { |
| cleaning = yes ; |
| } |
| constant CLEANING : $(cleaning) ; |
| } |
| |
| shared-command-line = ; |
| local argv = [ modules.peek : ARGV ] ; |
| while $(argv) { |
| if $(argv[1]) = "link=shared" { |
| shared-command-line = <link>shared ; |
| } |
| argv = $(argv[2-]) ; |
| } |
| |
| #Determine if a library can be compiled statically. |
| rule auto-shared ( name : additional * ) { |
| |
| additional ?= "" ; |
| if $(shared-command-line) = "<link>shared" { |
| return "<link>shared" ; |
| } else { |
| if [ test_flags $(additional)" -Wl,-Bstatic -l"$(name)" -Wl,-Bdynamic" ] { |
| return ; |
| } else { |
| if $(FORCE-STATIC) { |
| echo "Could not statically link against lib $(name). Your build will probably fail." ; |
| return ; |
| } else { |
| return "<link>shared" ; |
| } |
| } |
| } |
| } |
| |
| # MacPorts' default location is /opt/local -- use this if no path is given. |
| with-macports = [ option.get "with-macports" : : "/opt/local" ] ; |
| if $(with-macports) { |
| using darwin ; |
| ECHO "Using --with-macports=$(with-macports), implying use of darwin GCC" ; |
| |
| L-boost-search = -L$(with-macports)/lib ; |
| boost-search = <search>$(with-macports)/lib ; |
| I-boost-include = -I$(with-macports)/include ; |
| boost-include = <include>$(with-macports)/include ; |
| requirements += $(boost-include) ; |
| } else { |
| with-boost = [ option.get "with-boost" ] ; |
| with-boost ?= [ os.environ "BOOST_ROOT" ] ; |
| if $(with-boost) { |
| L-boost-search = -L$(with-boost)/lib" "-L$(with-boost)/lib64 ; |
| boost-search = <search>$(with-boost)/lib <search>$(with-boost)/lib64 ; |
| I-boost-include = -I$(with-boost)/include ; |
| boost-include = <include>$(with-boost)/include ; |
| requirements += $(boost-include) ; |
| } else { |
| L-boost-search = "" ; |
| boost-search = ; |
| I-boost-include = "" ; |
| boost-include = ; |
| } |
| } |
| |
| #Convenience rule for boost libraries. Defines library boost_$(name). |
| rule boost-lib ( name macro : deps * ) { |
| lib boost_$(name)_static : $(deps) : $(boost-search) <name>boost_$(name)$(boost-lib-version) <link>static ; |
| lib boost_$(name)_shared : $(deps) : $(boost-search) <name>boost_$(name)$(boost-lib-version) <link>shared : : <define>BOOST_$(macro) ; |
| |
| alias boost_$(name)_default : $(deps) : <link>static:<source>boost_$(name)_static <link>shared:<source>boost_$(name)_shared ; |
| |
| alias boost_$(name)_static_works : $(deps) : [ check-target-builds empty_test_shared "Shared Boost" : <source>boost_$(name)_default : <source>boost_$(name)_static ] ; |
| alias boost_$(name) : $(deps) : [ check-target-builds empty_test_static "Static Boost" : <source>boost_$(name)_static_works : <source>boost_$(name)_shared ] ; |
| } |
| |
| #Argument is e.g. 103600 |
| rule boost ( min-version ) { |
| local cmd = "bash -c \"g++ "$(I-boost-include)" -dM -x c++ -E /dev/null -include boost/version.hpp 2>/dev/null |grep '#define BOOST_'\"" ; |
| local boost-shell = [ SHELL "$(cmd)" : exit-status ] ; |
| if $(boost-shell[2]) != 0 && $(CLEANING) = no { |
| echo Failed to run "$(cmd)" ; |
| exit Boost does not seem to be installed or g++ is confused. : 1 ; |
| } |
| constant BOOST-VERSION : [ MATCH "#define BOOST_VERSION ([0-9]*)" : $(boost-shell[1]) ] ; |
| if $(BOOST-VERSION) < $(min-version) && $(CLEANING) = no { |
| exit You have Boost $(BOOST-VERSION). This package requires Boost at least $(min-version) (and preferably newer). : 1 ; |
| } |
| # If matching version tags exist, use them. |
| boost-lib-version = [ MATCH "#define BOOST_LIB_VERSION \"([^\"]*)\"" : $(boost-shell[1]) ] ; |
| if [ test_flags $(L-boost-search)" -lboost_program_options-"$(boost-lib-version) ] { |
| boost-lib-version = "-"$(boost-lib-version) ; |
| } else { |
| boost-lib-version = "" ; |
| } |
| |
| #Crazy amount of testing to make sure that BOOST_TEST_DYN_LINK is defined properly. |
| lib boost_unit_test_framework_static_test : : $(boost-search) <name>boost_unit_test_framework$(boost-lib-version) <link>static ; |
| obj empty_test_static.o : jam-files/empty_test_main.cc boost_unit_test_framework_static_test : $(boost-include) ; |
| exe empty_test_static : empty_test_static.o boost_unit_test_framework_static_test ; |
| |
| lib boost_unit_test_framework_shared_test : : $(boost-search) <name>boost_unit_test_framework$(boost-lib-version) <link>shared : : <define>BOOST_TEST_DYN_LINK ; |
| obj empty_test_shared.o : jam-files/empty_test_main.cc boost_unit_test_framework_shared_test : $(boost-include) ; |
| exe empty_test_shared : empty_test_shared.o boost_unit_test_framework_shared_test ; |
| |
| explicit empty_test_static.o empty_test_static empty_test_shared.o empty_test_shared ; |
| |
| |
| #See tools/build/v2/contrib/boost.jam in a boost distribution for a table of macros to define. |
| boost-lib system SYSTEM_DYN_LINK ; |
| boost-lib thread THREAD_DYN_DLL : boost_system ; |
| boost-lib program_options PROGRAM_OPTIONS_DYN_LINK ; |
| boost-lib iostreams IOSTREAMS_DYN_LINK ; |
| boost-lib filesystem FILE_SYSTEM_DYN_LINK ; |
| boost-lib unit_test_framework TEST_DYN_LINK ; |
| # if $(BOOST-VERSION) >= 104800 { |
| # boost-lib chrono CHRONO_DYN_LINK ; |
| # boost-lib timer TIMER_DYN_LINK : boost_chrono ; |
| # } |
| } |
| |
| #Link normally to a library, but sometimes static isn't installed so fall back to dynamic. |
| rule external-lib ( name : search-path * : deps * ) { |
| lib $(name) : : [ auto-shared $(name) : "-L"$(search-path) ] <search>$(search-path) <use>$(deps) ; |
| } |
| |
| #Write the current command line to previous.sh. This does not do shell escaping. |
| { |
| local build-log = $(TOP)/previous.sh ; |
| if ! [ path.exists $(build-log) ] { |
| SHELL "touch \"$(build-log)\" && chmod +x \"$(build-log)\"" ; |
| } |
| local script = [ modules.peek : ARGV ] ; |
| if $(script[1]) = "./jam-files/bjam" { |
| #The ./bjam shell script calls ./jam-files/bjam so that appears in argv but |
| #we want ./bjam to appear so the environment variables are set correctly. |
| script = "./bjam "$(script[2-]:J=" ") ; |
| } else { |
| script = $(script:J=" ") ; |
| } |
| script = "#!/bin/sh\n$(script)\n" ; |
| local ignored = @($(build-log):E=$(script)) ; |
| } |
| |
| #Boost jam's static clang for Linux is buggy. |
| requirements += <cxxflags>$(cxxflags) <cflags>$(cflags) <linkflags>$(ldflags) <os>LINUX,<toolset>clang:<link>shared ; |
| |
| if ! [ option.get "without-libsegfault" : : "yes" ] && ! $(FORCE-STATIC) { |
| #libSegFault prints a stack trace on segfault. Link against it if available. |
| if [ test_flags "-lSegFault" ] { |
| external-lib SegFault ; |
| requirements += <library>SegFault ; |
| } |
| } |
| |
| if [ option.get "git" : : "yes" ] { |
| local revision = [ _shell "git rev-parse --verify HEAD |head -c 7" ] ; |
| constant GITTAG : "/"$(revision) ; |
| } else { |
| constant GITTAG : "" ; |
| } |
| |
| local prefix = [ option.get "prefix" ] ; |
| if $(prefix) { |
| prefix = [ path.root $(prefix) [ path.pwd ] ] ; |
| prefix = $(prefix)$(GITTAG) ; |
| } else { |
| prefix = $(TOP)$(GITTAG) ; |
| } |
| |
| path-constant PREFIX : $(prefix) ; |
| |
| path-constant BINDIR : [ option.get "bindir" : $(PREFIX)/bin ] ; |
| path-constant LIBDIR : [ option.get "libdir" : $(PREFIX)/lib ] ; |
| rule install-bin-libs ( deps * ) { |
| install prefix-bin : $(deps) : <location>$(BINDIR) <install-dependencies>on <install-type>EXE <link>shared:<dll-path>$(LIBDIR) ; |
| install prefix-lib : $(deps) : <location>$(LIBDIR) <install-dependencies>on <install-type>LIB <link>shared:<dll-path>$(LIBDIR) ; |
| } |
| rule install-headers ( name : list * : source-root ? ) { |
| local includedir = [ option.get "includedir" : $(prefix)/include ] ; |
| source-root ?= "." ; |
| install $(name) : $(list) : <location>$(includedir) <install-source-root>$(source-root) ; |
| } |
| |
| rule build-projects ( projects * ) { |
| for local p in $(projects) { |
| build-project $(p) ; |
| } |
| } |
| |
| #Only one post build hook is allowed. Allow multiple. |
| post-hooks = ; |
| rule post-build ( ok ? ) { |
| for local r in $(post-hooks) { |
| $(r) $(ok) ; |
| } |
| } |
| IMPORT $(__name__) : post-build : : $(__name__).post-build ; |
| build-system.set-post-build-hook $(__name__).post-build ; |
| rule add-post-hook ( names * ) { |
| post-hooks += $(names) ; |
| } |
| |
| rule failure-message ( ok ? ) { |
| if $(ok) != "ok" { |
| local args = [ modules.peek : ARGV ] ; |
| local args = $(args:J=" ") ; |
| if --debug-configuration in [ modules.peek : ARGV ] { |
| echo "The build failed with command line: " ; |
| echo " $(args)" ; |
| echo "If you need support, attach the full output to your e-mail." ; |
| } else { |
| echo "The build failed. If you need support, run:" ; |
| echo " $(args) --debug-configuration -d2 |gzip >build.log.gz" ; |
| echo "then attach build.log.gz to your e-mail." ; |
| } |
| echo "ERROR" ; |
| } else { |
| echo "SUCCESS" ; |
| } |
| } |
| add-post-hook failure-message ; |
| |
| import feature : feature ; |
| feature options-to-write : : free ; |
| import toolset : flags ; |
| flags write-options OPTIONS-TO-WRITE <options-to-write> ; |
| actions write-options { |
| echo "$(OPTIONS-TO-WRITE)" > $(<) ; |
| } |
| |
| #Compare contents of file with current. If they're different, write to the |
| #file. This file can then be used with <dependency>$(file) to force |
| #recompilation. |
| rule update-if-changed ( file current ) { |
| if ( ! [ path.exists $(file) ] ) || ( [ _shell "cat $(file)" ] != $(current) ) { |
| make $(file) : : $(__name__).write-options : <options-to-write>$(current) ; |
| always $(file) ; |
| } |
| } |
| |
| if [ option.get "sanity-test" : : "yes" ] { |
| local current_version = [ modules.peek : JAM_VERSION ] ; |
| if ( $(current_version[0]) < 2000 && [ version.check-jam-version 3 1 16 ] ) || [ version.check-jam-version 2011 0 0 ] { |
| EXIT "Sane" : 0 ; |
| } else { |
| EXIT "Bad" : 1 ; |
| } |
| } |
| |
| #Hack to act like alias in the sense that no lib is built, but only build cpp files once. |
| import type ; |
| rule fakelib ( name : deps * : requirements * : default-build * : usage-requirements * ) { |
| local c-files = ; |
| local real-deps = ; |
| for local c in $(deps) { |
| if [ type.type $(c) ] = CPP { |
| c-files += $(c) ; |
| } else { |
| real-deps += $(c) ; |
| } |
| } |
| for local c in $(c-files) { |
| obj $(c:B).o : $(c) $(real-deps) : $(requirements) : $(default-build) : $(usage_requirements) ; |
| } |
| alias $(name) : $(c-files:B).o $(real-deps) : $(requirements) : $(default-build) : $(usage-requirements) ; |
| } |
| |
| use-project /top : . ; |