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 ; } } 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 += static 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 = shared ; } argv = $(argv[2-]) ; } #Determine if a library can be compiled statically. rule auto-shared ( name : additional * ) { additional ?= "" ; if $(shared-command-line) = "shared" { return "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 "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 = $(with-macports)/lib ; I-boost-include = -I$(with-macports)/include ; boost-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 = $(with-boost)/lib $(with-boost)/lib64 ; I-boost-include = -I$(with-boost)/include ; boost-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 * ) { flags = $(L-boost-search)" -lboost_"$(name)"$(boost-lib-version)" ; local main ; if $(name) = "unit_test_framework" { main = "BOOST_AUTO_TEST_CASE(foo) {}" ; flags += " -DBOOST_TEST_MODULE=CompileTest $(I-boost-include) -include boost/test/unit_test.hpp" ; } if $(boost-auto-shared) = "shared" { flags += " -DBOOST_$(macro)" ; } else { flags = " -Wl,-Bstatic $(flags) -Wl,-Bdynamic " ; } if [ test_flags $(flags) : $(main) ] { lib inner_boost_$(name) : : single $(boost-search) boost_$(name)$(boost-lib-version) : static : $(deps) ; lib inner_boost_$(name) : : multi $(boost-search) boost_$(name)$(boost-lib-version) : static : $(deps) ; } else { lib inner_boost_$(name) : : $(boost-search) boost_$(name)$(boost-lib-version) : : $(deps) ; } if $(boost-auto-shared) = "shared" { alias boost_$(name) : inner_boost_$(name) : shared ; requirements += BOOST_$(macro) ; } else { alias boost_$(name) : inner_boost_$(name) : static ; } } #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 = "" ; } #Are we linking static binaries against shared boost? boost-auto-shared = [ auto-shared "boost_program_options"$(boost-lib-version) : $(L-boost-search) ] ; #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 unit_test_framework TEST_DYN_LINK ; boost-lib iostreams IOSTREAMS_DYN_LINK ; boost-lib filesystem FILE_SYSTEM_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-path) $(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) $(cflags) $(ldflags) LINUX,clang: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 += 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) : $(BINDIR) on EXE shared:$(LIBDIR) ; install prefix-lib : $(deps) : $(LIBDIR) on LIB shared:$(LIBDIR) ; } rule install-headers ( name : list * : source-root ? ) { local includedir = [ option.get "includedir" : $(prefix)/include ] ; source-root ?= "." ; install $(name) : $(list) : $(includedir) $(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 "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 ; 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 $(file) to force #recompilation. rule update-if-changed ( file current ) { if ( ! [ path.exists $(file) ] ) || ( [ _shell "cat $(file)" ] != $(current) ) { make $(file) : : $(__name__).write-options : $(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 : . ;