| | 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 |
| | 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 |
| | 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 "You MUST do 3 things before sending to the mailing list:" ; |
| | echo " 1. Subscribe to the mailing list at http://mailman.mit.edu/mailman/listinfo/moses-support" ; |
| | echo " 2. Attach build.log.gz to your e-mail" ; |
| | echo " 3. Say what is the EXACT command you executed when you got the error" ; |
| | } |
| | 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 : . ; |
| |
|