if ! $(gPYTHON_INCLUDED) { gPYTHON_INCLUDED = true ; # Do some OS-specific setup if $(NT) { CATENATE = type ; PYTHON_VERSION ?= 2.1 ; } else if $(UNIX) { CATENATE = cat ; PYTHON_VERSION ?= 1.5 ; } # Strip the dot from the Python version in order to be able to name # libraries PYTHON_VERSION_NODOT = [ SUBST $(PYTHON_VERSION) ([0-9]*)\.([0-9]*) $1$2 ] ; local RUN_PATH = $(RUN_PATH) ; # Decide which toolsets should be treated like an ordinary (unix) GCC installation gcc-compilers = [ MATCH ^(gcc.*)$ : $(TOOLS) ] ; gcc-compilers = [ difference $(gcc-compilers) : gcc-nocygwin ] ; if $(NT) { PYTHON_ROOT ?= c:/tools/python ; # Reconstitute any paths split due to embedded spaces. PYTHON_ROOT = $(PYTHON_ROOT:J=" ") ; PYTHON_LIB_PATH ?= $(PYTHON_ROOT)/libs $(PYTHON_ROOT)/PCBuild ; PYTHON_STDLIB_PATH ?= $(PYTHON_ROOT)/Lib ; # Locate Python libraries. In the case of MSVC the libraries are # found implicitly, and GCC/MINGW will use -lpython to # find it, but other compilers may need an explicit pointer on the # command line. PYTHON_LIB ?= python$(PYTHON_VERSION_NODOT).lib ; SEARCH on $(PYTHON_LIB) = $(PYTHON_LIB_PATH) ; PYTHON_D_LIB ?= python$(PYTHON_VERSION_NODOT)_d.lib ; SEARCH on $(PYTHON_D_LIB) = $(PYTHON_LIB_PATH) ; # common properties required for compiling any Python module. PYTHON_PROPERTIES ?= select-python-includes dynamic $(BOOST_ROOT) <$(gcc-compilers)><*>USE_DL_IMPORT <$(gcc-compilers)><*>python$(PYTHON_VERSION).dll ; GCC_PYTHON_ROOT ?= $(CYGWIN_ROOT)/usr/local ; GCC_PYTHON_ROOT ?= /usr/local ; GCC_PYTHON_DEBUG_ROOT ?= $(CYGWIN_ROOT)/usr/local/pydebug ; GCC_PYTHON_DEBUG_ROOT ?= /usr/local/pydebug ; } else if $(UNIX) { PYTHON_VERSION ?= 1.5 ; PYTHON_ROOT ?= /usr/local ; PYTHON_ROOT = $(PYTHON_ROOT:J=" ") ; PYTHON_INCLUDES ?= $(PYTHON_ROOT)/include/python$(PYTHON_VERSION) ; PYTHON_LIB_PATH ?= $(PYTHON_ROOT)/lib/python$(PYTHON_VERSION)/config ; PYTHON_STDLIB_PATH ?= $(PYTHON_ROOT)/lib/python$(PYTHON_VERSION) ; PYTHON_PROPERTIES ?= $(PYTHON_INCLUDES) $(PYTHON_LIB_PATH) ; if $(OS) = OSF { PYTHON_PROPERTIES += <*><*>"-expect_unresolved 'Py*' -expect_unresolved '_Py*'" ; } else if $(OS) = AIX { PYTHON_PROPERTIES += <*><*>"-bI:$(PYTHON_LIB_PATH)/python.exp" <*><*>pthreads ; } } # Locate the python executable PYTHON ?= python$(SUFEXE) ; SEARCH on $(PYTHON) = $(PYTHON_ROOT) $(PYTHON_ROOT)/bin $(PYTHON_ROOT)/PCBuild $(RUN_PATH) ; # And the debugging version PYTHON_D ?= $(PYTHON:S=)_d$(PYTHON:S) ; SEARCH on $(PYTHON_D) = $(PYTHON_ROOT) $(PYTHON_ROOT)/bin $(PYTHON_ROOT)/PCBuild $(RUN_PATH) ; # select-python-library # # Ungristed elements of a requirements list are treated as the rule # names to be called to transform the property set. This is used when # the requirements are too complicated to express otherwise. This # rule selects the right python library when building on Windows. rule select-python-library ( toolset variant : properties * ) { if $(NT) { if $(toolset) = mingw { local lib = python$(PYTHON_VERSION_NODOT) ; if BOOST_DEBUG_PYTHON in $(properties) { lib = python$(PYTHON_VERSION_NODOT)_d ; } properties += $(lib) ; } else if $(toolset) in $(gcc-compilers) { local python-root = $(GCC_PYTHON_ROOT) ; if BOOST_DEBUG_PYTHON in $(properties) { python-root = $(GCC_PYTHON_DEBUG_ROOT) ; } properties += $(python-root)/lib/python$(PYTHON_VERSION)/config ; } else if ! ( $(toolset) = msvc ) { local lib = $(PYTHON_LIB) ; if BOOST_DEBUG_PYTHON in $(properties) { lib = $(PYTHON_D_LIB) ; } properties += $(lib) ; } } return $(properties) ; } rule select-python-includes ( toolset variant : properties * ) { if $(toolset) in $(gcc-compilers) { local python-root = $(GCC_PYTHON_ROOT) ; if BOOST_DEBUG_PYTHON in $(properties) { python-root = $(GCC_PYTHON_DEBUG_ROOT) ; } properties += $(python-root)/include/python$(PYTHON_VERSION) ; } else { properties += $(PYTHON_ROOT)/include $(PYTHON_ROOT)/PC # in case the user is using a source installation _DEBUG ; } return $(properties) ; } PYTHON_PROPERTIES += <$(gcc-compilers)><*>util $(BOOST_ROOT) on select-python-library ; if $(NT) { # Most Windows compilers pick up implicit directions from #pragmas # to look for those libraries. PYTHON_PROPERTIES += $(PYTHON_LIB_PATH) ; } # Set gcc-specific release build properties { local gcc-release-properties = speed -fomit-frame-pointer on # GCC 2.95.4, which ships with Debian, chokes on this. # -foptimize-sibling-calls ; PYTHON_PROPERTIES += <$(gcc-compilers)>$(gcc-release-properties) ; } BOOST_PYTHON_V2_PROPERTIES = $(PYTHON_PROPERTIES) <*>"-inline deferred" <*>"-inline deferred" # added for internal testing purposes <*>$(BOOST_ROOT)/boost/compatibility/cpp_c_headers BOOST_PYTHON_DYNAMIC_LIB BOOST_PYTHON_V2 ; # Extends the RUN_PATH assignment for targets built under Cygwin so # that the Python DLL can be found. rule add-cygwin-python-run-path ( module ) { local d = $(GCC_ROOT_DIRECTORY) ; while $(d:D) != $(d) { local python-root = $(GCC_PYTHON_ROOT) ; if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) { python-root = $(GCC_PYTHON_DEBUG_ROOT) ; } gRUN_PATH($(module)) += $(python-root)/lib/python$(PYTHON_VERSION)/config ; d = $(d:D) ; } } # This is the generator function for Python modules. It deals with the # need to change the name of modules compiled with debugging on. This # is just a wrapper around the generator for shared libraries, # dll-files. rule python-files ( module implib ? : sources * ) { dll-files $(module) $(implib) : $(sources) : PYD ; if $(gCURRENT_TOOLSET) in $(gcc-compilers) { if $(NT) { add-cygwin-python-run-path $(<[-1]) ; } else { gRUN_PATH($(module)) += $(GCC_ROOT_DIRECTORY)/lib ; } } } if $(NT) { # Adjust the name of Python modules so that they have the _d # suffix when compiled with python debugging enabled. gNAME_ADJUST(PYD) = name-adjust-PYD ; rule name-adjust-PYD ( pyd implib ? : properties * : toolset variant ) { # Cygwin python is only happy if compiled modules have a .dll # extension if $(toolset) in $(gcc-compilers) { pyd = $(pyd:S=.dll) ; } else if BOOST_DEBUG_PYTHON in $(properties) { pyd = $(pyd:S=)_d$(pyd:S) ; } return $(pyd) $(implib) ; } } rule Link-PYD { gRUN_PATH($(<)) += $(gLOCATE($(<[1]))) ; if $(UNIX) { RUN_LD_LIBRARY_PATH on $(<) = [ join $(gRUN_LD_LIBRARY_PATH($(<))) : $(SPLITPATH) ] ; gRUN_LD_LIBRARY_PATH($(<)) += $(gLOCATE($(<[1]))) ; if $(OS) = AIX { # explicitly designate the exported init function LINKFLAGS on $(<) += "-e init$(<[1]:B)" ; Aix-Implib-Action $(<) : $(>) ; } } Link-action $(<) : $(>) : PYD ; } declare-target-type PYD : true ; gGENERATOR_FUNCTION(PYD) = python-files ; if $(NT) { SUFPYD = .pyd $(SUFDLL[2-]) ; } else { SUFPYD = $(SUFDLL) ; } PYDMODE = $(DLLMODE) ; SHARED_TYPES += PYD ; gTARGET_TYPE_ID(pyd) = PYD ; gIS_DEPENDENCY(PYD) = TRUE ; # Declare a python extension. rule extension ( name : sources + : requirements * : default-BUILD * ) { requirements += $(PYTHON_PROPERTIES) ; declare-local-target $(name) : $(sources) : $(requirements) : $(default-BUILD) : PYD ; } # boost-python-runtest target : python-script sources : requirements : local-build : args # # declare two python module tests: $(<).test which builds when out-of-date, and # $(<).run which builds unconditionally. rule boost-python-runtest ( target : python-script sources + : requirements * : local-build * : args * ) { # tell Jam that the python script is relative to this directory SEARCH on $(python-script) = $(SEARCH_SOURCE) ; # The user can add additional arguments in PYTHON_TEST_ARGS. local gPYTHON_TEST_ARGS = $(args) $(PYTHON_TEST_ARGS) ; # declare the two subsidiary tests. declare-local-target $(<) : $(>) : $(PYTHON_PROPERTIES) : $(4) : PYTHON_TEST ; declare-local-target $(<) : $(>) : $(PYTHON_PROPERTIES) : $(4) true : PYTHON_RUNTEST ; } rule boost-python-test ( name : sources + : requirements * : default-BUILD * ) { extension $(name) : $(sources) : $(requirements) true : $(4) ; } # special rules for two new target types: PYTHON_TEST and PYTHON_RUNTEST. # These are identical except that PYTHON_TEST runs the test when out-of-date, and # PYTHON_RUNTEST runs the test unconditionally. These are used by boost-python-runtest. SUFPYTHON_TEST = .test ; gGENERATOR_FUNCTION(PYTHON_TEST) = python-test-target ; rule python-test-target ( test-target : sources + ) { python-runtest-aux $(test-target) : $(sources) ; Clean clean : $(test-target) ; # remove the test-target as part of any clean operation type-DEPENDS test : $(test-target) ; MakeLocate $(test-target) : $(LOCATE_TARGET) ; MakeLocate $(test-target) : $(LOCATE_TARGET) ; } if $(UNIX) { gAPPEND_LD_LIBRARY_PATH = ":$"$(gSHELL_LIBPATH) ; gAPPEND_PATH = ":$"PATH ; } else if $(NT) { gAPPEND_PATH = ";%PATH%" ; } actions python-test-target bind PYTHON { $(SHELL_SET)PATH=$(run.path)$(gAPPEND_PATH) $(SHELL_EXPORT)PATH $(SHELL_SET)$(gSHELL_LIBPATH)=$(run.library_path)$(gAPPEND_LD_LIBRARY_PATH) $(SHELL_EXPORT)$(gSHELL_LIBPATH) $(SHELL_SET)PYTHONPATH=$(PYTHONPATH) $(SHELL_EXPORT)PYTHONPATH $(PYTHON_LAUNCH) $(PYTHON) $(PYTHON_ARGS) "$(>)" $(ARGS) 2>&1 "$(<)" || $(CATENATE) "$(<)" } SUFPYTHON_RUNTEST = .run ; gGENERATOR_FUNCTION(PYTHON_RUNTEST) = python-runtest-target ; rule python-runtest-target ( test-target : sources + ) { type-DEPENDS runtest : $(test-target) ; python-runtest-aux $(test-target) : $(sources) ; NOTFILE $(test-target) ; ALWAYS $(test-target) ; } actions python-runtest-target bind PYTHON { $(SHELL_SET)PATH=$(run.path)$(gAPPEND_PATH) $(SHELL_EXPORT)PATH $(SHELL_SET)$(gSHELL_LIBPATH)=$(run.library_path)$(gAPPEND_LD_LIBRARY_PATH) $(SHELL_EXPORT)$(gSHELL_LIBPATH) $(SHELL_SET)PYTHONPATH=$(PYTHONPATH) $(SHELL_EXPORT)PYTHONPATH $(PYTHON_LAUNCH) $(PYTHON) $(PYTHON_ARGS) "$(>)" $(ARGS) } # This is the rule that actually causes the test to run. It is used by # bothe python-test-target and python-runtest-target. rule python-runtest-aux ( target : sources + ) { DEPENDS $(target) : $(>) ; ARGS on $(target) += $(gPYTHON_TEST_ARGS) ; # Some tests need an extra command-line arg if built with # msvc. Checking the target grist is a cheap way to # find out. switch $(target) { case <*\\\\msvc\\\\*>* : ARGS on $(target) += --broken-auto-ptr ; case <*\\\\intel-win32\\\\*>* : ARGS on $(target) += --broken-auto-ptr ; } # choose the right python executable local python = $(PYTHON) ; local splitpath = $(SPLITPATH) ; # compute the PYTHONPATH environment variable that will allow the test to # find all of the modules on which it depends. local pythonpath = $(gLOCATE($(>[1]))) # location of python test file $(gRUN_PATH($(target))) # location of module dependencies [ join-path $(TOP) libs python test ] # location of doctest $(>:D) # directory of python driver file(s) $(PYTHONPATH) # base PYTHONPATH from environment ; if $(NT) && ( $(gCURRENT_TOOLSET) in $(gcc-compilers) ) { python = python$(PYTHON_VERSION)$(SUFEXE) ; local python-root = $(GCC_PYTHON_ROOT) ; if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) { python-root = $(GCC_PYTHON_DEBUG_ROOT) ; } SEARCH on $(python) = [ join-path [ split-path $(python-root)/bin ] ] $(RUN_PATH) ; splitpath = ":" ; local pp ; for local p in $(pythonpath) { # if already rooted... if $(p:R=xx) = $(p) { p = [ split-path $(p) ] ; p = [ join-path /cygdrive [ SUBST $(p[1]) ^(.).* $1 ] $(p[2-]) ] ; } pp += $(p) ; } pythonpath = $(pp:T) ; } else if BOOST_DEBUG_PYTHON in $(gBUILD_PROPERTIES) && $(NT) { python = $(PYTHON_D) ; } # adding the dummy at the end fixes a problem which causes a # trailing space to be added to the last path. PYTHONPATH on $(target) = [ join $(pythonpath) "" : $(splitpath) ] ; # set the path so that DLLs linked into extension modules will be # found run.path on $(target) = [ join $(gRUN_PATH($(target))) # location of module dependencies $(>:D) # directory of python driver file(s) : $(SPLITPATH) ] ; # platform path separator run.library_path on $(target) = $(gRUN_LD_LIBRARY_PATH($(target)):J=$(SPLITPATH)) ; PYTHON on $(target) = $(python) ; DEPENDS $(target) : $(python) ; } }