Boost logo

Boost-Commit :

From: roland.schwarz_at_[hidden]
Date: 2007-08-20 15:14:14


Author: speedsnail
Date: 2007-08-20 15:14:14 EDT (Mon, 20 Aug 2007)
New Revision: 38803
URL: http://svn.boost.org/trac/boost/changeset/38803

Log:
Merge from RC_1_34_0 (CVS 1.12.2.53) to trunk. CVS RC_1_34_0 - 1.12.2.23 and CVS HEAD - 1.51 are the last versions that were equal. Between these and trunk was only a small diff for HPUX that removed pthread lib. This fix seems to be already present in the merged in version.
Text files modified:
   trunk/tools/build/v2/tools/python.jam | 1283 +++++++++++++++++++++++++++------------
   1 files changed, 897 insertions(+), 386 deletions(-)

Modified: trunk/tools/build/v2/tools/python.jam
==============================================================================
--- trunk/tools/build/v2/tools/python.jam (original)
+++ trunk/tools/build/v2/tools/python.jam 2007-08-20 15:14:14 EDT (Mon, 20 Aug 2007)
@@ -15,12 +15,6 @@
 #
 # Extensions that use Boost.Python must explicitly link to it.
 
-# Known problems:
-# - the directory where extension is generated is different from V2
-# - the ext + py -> pyd_run_output generator is declared to take
-# SHARED_LIB, not PYTHON_EXTENSION. That's because we reuse
-# 'lib-target-class', which creates SHARED_LIB explicitly.
-
 import type ;
 import testing ;
 import generators ;
@@ -32,6 +26,14 @@
 import common ;
 import toolset : flags ;
 import regex ;
+import numbers ;
+import string ;
+import property ;
+import sequence ;
+import path ;
+import feature ;
+import set ;
+import builtin ;
 
 # Make this module a project
 project.initialize $(__name__) ;
@@ -42,11 +44,9 @@
 # not in whatever project we were called by.
 .project = [ project.current ] ;
 
-.alias-defined = ;
-
-# Dynamic linker lib. Necessary to specify it explicitly
+# Dynamic linker lib. Necessary to specify it explicitly
 # on some platforms.
-lib dl ;
+lib dl ;
 # This contains 'openpty' function need by python. Again, on
 # some system need to pass this to linker explicitly.
 lib util ;
@@ -56,476 +56,951 @@
 lib rt ;
 
 
-# Initializes the Python toolset.
-# - version -- the version of Python to use. Should be in Major.Minor format,
-# for example 2.3
-# - 'root' -- the install root for Python
-# - 'includes' -- the include path to Python headers. If empty, will be
-# guessed from 'root'
-# - 'libraries' -- the path to Python libraries. If empty, will be guessed
-# from 'root'
-# - 'cygwin-condition' -- if specified, should be a set of properties which
-# are present when we're building with cygwin gcc.
-# This argument is not used yet.
+# Initializes the Python toolset. Note that all parameters are
+# optional.
+#
+# - version -- the version of Python to use. Should be in Major.Minor
+# format, for example 2.3. Do not include the subminor version.
+#
+# - cmd-or-prefix: Preferably, a command that invokes a Python
+# interpreter. Alternatively, the installation prefix for Python
+# libraries and includes. If empty, will be guessed from the
+# version, the platform's installation patterns, and the python
+# executables that can be found in PATH.
+#
+# - includes: the include path to Python headers. If empty, will be
+# guessed.
+#
+# - libraries: the path to Python library binaries. If empty, will be
+# guessed. On MacOS/Darwin, you can also pass the path of the
+# Python framework.
+#
+# - condition: if specified, should be a set of properties that are
+# matched against the build configuration when Boost.Build selects a
+# Python configuration to use.
+#
+# - extension-suffix: A string to append to the name of extension
+# modules before the true filename extension. Ordinarily we would
+# just compute this based on the value of the <python-debugging>
+# feature. However ubuntu's python-dbg package uses the windows
+# convention of appending _d to debug-build extension modules. We
+# have no way of detecting ubuntu, or of probing python for the "_d"
+# requirement, and if you configure and build python using
+# --with-pydebug, you'll be using the standard *nix convention.
+# Defaults to "" (or "_d" when targeting windows and
+# <python-debugging> is set).
 #
 # Example usage:
 #
-# using python 2.3 ; # Use default root
-# using python 2.3 : /usr/local ; # Root specified, include and lib paths
-# # will be guessed
+# using python 2.3 ;
+# using python 2.3 : /usr/local/bin/python ;
 #
-rule init ( version ? : root ? : includes ? : libraries ?
- : cygwin-condition * )
+rule init ( version ? : cmd-or-prefix ? : includes * : libraries ?
+ : condition * : extension-suffix ? )
 {
- .configured = true ;
-
     project.push-current $(.project) ;
-
- if [ os.name ] = NT
+
+ debug-message Configuring python... ;
+ for local v in version cmd-or-prefix includes libraries condition
     {
- init-nt $(version) : $(root) : $(includes) : $(libraries) : $(cygwin-condition) ;
+ if $($(v))
+ {
+ debug-message " user-specified "$(v): \"$($(v))\" ;
+ }
     }
- else if [ os.name ] = MACOSX
+
+ configure $(version) : $(cmd-or-prefix) : $(includes) : $(libraries) : $(condition) : $(extension-suffix) ;
+
+ project.pop-current ;
+}
+
+# A simpler version of SHELL that grabs stderr as well as stdout, but
+# returns nothing if there's an error.
+local rule shell-cmd ( cmd )
+{
+ debug-message running command '$(cmd)" 2>&1"' ;
+ x = [ SHELL $(cmd)" 2>&1" : exit-status ] ;
+ if $(x[2]) = 0
     {
- init-mac $(version) : $(root) : $(includes) : $(libraries) ;
- }
- else if [ modules.peek : UNIX ]
+ return $(x[1]) ;
+ }
+ else
     {
- init-unix $(version) : $(root) : $(includes) : $(libraries) : $(cygwin-condition) ;
+ return ;
     }
-
- if [ os.on-windows ] && ! $(.alias-defined)
+}
+
+# Try to identify Cygwin symlinks. Invoking such a file directly as
+# an NT executable from a native Windows build of bjam would be fatal
+# to the bjam process. One /can/ invoke them through sh.exe or
+# bash.exe, if you can prove that those aren't also symlinks ;-)
+#
+# If a symlink is found returns non-empty; we try to extract the
+# target of the symlink from the file and return that.
+#
+# Note: 1. only works on NT 2. path is a native path.
+local rule is-cygwin-symlink ( path )
+{
+ local is-symlink = ;
+
+ # Look for a file with the given path having the S attribute set,
+ # as cygwin symlinks do. /-C means "do not use thousands
+ # separators in file sizes."
+ local dir-listing = [ shell-cmd "DIR /-C /A:S "$(path) ] ;
+
+ if $(dir-listing)
     {
- .alias-defined = true ;
- alias python_for_extensions : python ;
+ # escape any special regex characters in the base part of the path
+ local base-pat = [ regex.escape $(path:D=) : ].[()*+?|\\$^ : \\ ] ;
+
+ # extract the file's size from the directory listing
+ local size-of-system-file = [ MATCH "([0-9]+) "$(base-pat) : $(dir-listing) : 1 ] ;
+
+ # if the file has a reasonably small size, look for the
+ # special symlink identification text
+ if $(size-of-system-file) && [ numbers.less $(size-of-system-file) 1000 ]
+ {
+ local link = [ SHELL "FIND /OFF \"!<symlink>\" \""$(path)"\" 2>&1" ] ;
+ if $(link[2]) != 0
+ {
+ local nl = "
+
+" ;
+ is-symlink = [ MATCH ".*!<symlink>([^"$(nl)"]*)" : $(link[1]) : 1 ] ;
+ if $(is-symlink)
+ {
+ is-symlink = [ *nix-path-to-native $(is-symlink) ] ;
+ is-symlink = $(is-symlink:R=$(path:D)) ;
+ }
+
+ }
+ }
     }
-
-
- project.pop-current ;
+ return $(is-symlink) ;
+}
+
+# Append ext to each member of names that does not contain '.'
+local rule default-extension ( names * : ext * )
+{
+ local result ;
+ for local n in $(names)
+ {
+ switch $(n)
+ {
+ case *.* : result += $(n) ;
+ case * : result += $(n)$(ext) ;
+ }
+ }
+ return $(result) ;
 }
 
-# Retrieves the Python interpreter
-rule get-python-interpreter ( )
+# Tries to determine whether invoking "cmd" would actually attempt to
+# launch a cygwin symlink.
+#
+# Note: only works on NT
+local rule invokes-cygwin-symlink ( cmd )
 {
- return $(PYTHON) ;
+ local dirs = $(cmd:D) ;
+ if ! $(dirs)
+ {
+ dirs = . [ os.executable-path ] ;
+ }
+ local base = [ default-extension $(cmd:D=) : .exe .bat ] ;
+ local paths = [ GLOB $(dirs) : $(base) ] ;
+ if $(paths)
+ {
+ # Make sure we didn't find a Cygwin symlink. Invoking such a
+ # file as an NT executable will be fatal to the bjam process.
+ return [ is-cygwin-symlink $(paths[1]) ] ;
+ }
 }
 
-# Retrieves the Python version number
-rule get-python-version ( )
+local rule debug-message ( message * )
 {
- return [ python-version [ get-python-interpreter ] ] ;
+ if --debug-configuration in [ modules.peek : ARGV ]
+ {
+ ECHO notice: [python-cfg] $(message) ;
+ }
 }
 
-local rule python-version ( cmd )
+# 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 ? )
 {
- cmd ?= python ;
- local version = [ SHELL $(cmd)" -c 'import sys; print sys.version'" : exit-status ] ;
-
- if $(version[2]) = 0
+ local result ;
+ for local root in HKEY_CURRENT_USER HKEY_LOCAL_MACHINE
     {
- return [ MATCH ^([0-9]+.[0-9]+) : $(version[1]) : 1 ] ;
+ for local x64elt in "" Wow6432node\\ # Account for 64-bit windows
+ {
+ if ! $(result)
+ {
+ result = [ W32_GETREG $(root)\\SOFTWARE\\$(x64elt)$(path) : $(data) ] ;
+ }
+ }
+
     }
- else
+ return $(result) ;
+}
+
+.windows-drive-letter-re = ^([A-Za-z]):[\\/](.*) ;
+.cygwin-drive-letter-re = ^/cygdrive/([a-z])/(.*) ;
+
+.working-directory = [ PWD ] ;
+.working-drive-letter = [ SUBST $(.working-directory) $(.windows-drive-letter-re) $1 ] ;
+.working-drive-letter ?= [ SUBST $(.working-directory) $(.cygwin-drive-letter-re) $1 ] ;
+
+local rule windows-to-cygwin-path ( path )
+{
+ # if path is rooted with a drive letter, rewrite it using the
+ # /cygdrive mountpoint
+ local p = [ SUBST $(path:T) $(.windows-drive-letter-re) /cygdrive/$1/$2 ] ;
+
+ # else if path is rooted without a drive letter, use the working directory
+ p ?= [ SUBST $(path:T) ^/(.*) /cygdrive/$(.working-drive-letter:L)/$2 ] ;
+
+ # else return the path unchanged
+ return $(p:E=$(path:T)) ;
+}
+
+# :W only works in Cygwin builds of bjam. This one works on NT builds
+# as well.
+local 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)
     {
- return ;
+ 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="") / \\ ] ;
+}
+
+# Convert a *nix path to native
+local rule *nix-path-to-native ( path )
+{
+ if [ os.name ] = NT
+ {
+ path = [ cygwin-to-windows-path $(path) ] ;
     }
+ return $(path) ;
 }
 
-local rule python-interpreter ( cmd )
+# Convert an NT path to native
+local rule windows-path-to-native ( path )
 {
- local which = [ SHELL "which "$(cmd) : exit-status ] ;
- if $(which[2]) = 0
+ if [ os.name ] = NT
     {
- return $(which[1]) ;
+ return $(path) ;
     }
     else
     {
- return ;
+ return [ windows-to-cygwin-path $(path) ] ;
     }
 }
 
-local rule python-root ( cmd )
+# Return nonempty if path looks like a windows path, i.e. it starts
+# with a drive letter or contains backslashes.
+local rule guess-windows-path ( path )
 {
- return [ MATCH (.*)/bin/[^/]* : [ SHELL "which "$(cmd) ] : 1 ] ;
+ return [ SUBST $(path) ($(.windows-drive-letter-re)|.*([\\]).*) $1 ] ;
 }
 
+local rule path-to-native ( paths * )
+{
+ local result ;
 
-local rule debug-message ( message * )
+ for local p in $(paths)
+ {
+ if [ guess-windows-path $(p) ]
+ {
+ result += [ windows-path-to-native $(p) ] ;
+ }
+ else
+ {
+ result += [ *nix-path-to-native $(p:T) ] ;
+ }
+ }
+ return $(result) ;
+}
+
+# Validate the version string and extract the major/minor part we care
+# about
+local rule split-version ( version )
 {
- if --debug-configuration in [ modules.peek : ARGV ]
+ local major-minor = [ MATCH ^([0-9]+)\.([0-9]+)(.*)$ : $(version) : 1 2 3 ] ;
+ if ! $(major-minor[2]) || $(major-minor[3])
     {
- ECHO notice: $(message) ;
+ ECHO "Warning: \"using python\" expects a two part (major, minor) version number; got" $(version) instead ;
+
+ # Add a zero to account for the missing digit if necessary.
+ major-minor += 0 ;
     }
+
+ return $(major-minor[1]) $(major-minor[2]) ;
 }
 
-# condition is a list of properties for which this python initialization applies.
-rule init-unix ( version ? : root ? : includes ? : libraries ? : condition * )
+# Build a list of versions from 3.0 down to 1.5. Because bjam
+# can't enumerate registry sub-keys, we have no way of finding
+# a version with a 2-digit minor version, e.g. 2.10 -- let's
+# hope that never happens.
+.version-countdown = ;
+for local v in [ numbers.range 15 30 ]
 {
- #
- # Autoconfiguration sequence
- #
- if $(version)
+ .version-countdown = [ SUBST $(v) (.)(.*) $1.$2 ] $(.version-countdown) ;
+}
+
+local rule windows-installed-pythons ( version ? )
+{
+ version ?= $(.version-countdown) ;
+ local interpreters ;
+
+ for local v in $(version)
     {
- local v = [ MATCH ^([0-9]+\.[0-9]+)(.*)$ : $(version) : 1 2 ] ;
- if ! $(v) || $(v[2])
+ local install-path = [
+ software-registry-value "Python\\PythonCore\\"$(v)"\\InstallPath" ] ;
+
+ if $(install-path)
         {
- ECHO "Warning: \"using python\" expects a two part (major, minor) version number; got" $(version) instead ;
- if $(v)
- {
- version = $(v[1]) ;
- }
+ install-path = [ windows-path-to-native $(install-path) ] ;
+ debug-message Registry indicates Python $(v) installed at \"$(install-path)\" ;
         }
- debug-message looking for python $(version) ;
+
+ interpreters += $(:E=python:R=$(install-path)) ;
     }
-
- # if root is explicitly specified, look in its bin subdirectory
- local bin = bin/ ;
- bin = $(bin:R=$(root)) ; # will null out $(bin) if $(root) is empty.
-
- if $(bin)
+ return $(interpreters) ;
+}
+
+local rule darwin-installed-pythons ( version ? )
+{
+ version ?= $(.version-countdown) ;
+
+ local prefix
+ = [ GLOB /System/Library/Frameworks /Library/Frameworks
+ : Python.framework ] ;
+
+ return $(prefix)/Versions/$(version)/bin/python ;
+}
+
+# Assume "python-cmd" invokes a python interpreter and invoke it to
+# extract all the information we care about from its "sys" module.
+# Returns void if unsuccessful.
+local rule probe ( python-cmd )
+{
+ # Avoid invoking a Cygwin symlink on NT
+ local skip-symlink ;
+ if [ os.name ] = NT
     {
- debug-message searching for python binaries in $(bin) ;
+ skip-symlink = [ invokes-cygwin-symlink $(python-cmd) ] ;
     }
-
- # Form the python commands to try in order. First look for python
- # with the explicit version number, then without it
- local python = python ;
- local cmds = $(python:D=$(bin:E=""))$(version:E="") $(python:D=$(bin:E="")) ;
-
- local interpreter ;
- while $(cmds)
- {
- # pop a command
- interpreter = $(cmds[0]) ; cmds = $(cmds[2-]) ;
- debug-message trying Python interpreter command $(interpreter) ;
-
- # Check to see what version that command actually runs, if any
- local true-version = [ python-version $(interpreter) ] ;
-
- if ! $(true-version)
+
+ if $(skip-symlink)
+ {
+ debug-message -------------------------------------------------------------------- ;
+ debug-message \"$(python-cmd)\" would attempt to invoke a Cygwin symlink, ;
+ debug-message causing a bjam built for Windows to hang. ;
+ debug-message ;
+ debug-message If you intend to target a Cygwin build of Python, please ;
+ debug-message replace the path to the link with the path to a real executable ;
+ debug-message (guessing: \"$(skip-symlink)\") "in" your 'using python' line ;
+ debug-message "in" user-config.jam or site-config.jam. Don't forget to escape ;
+ debug-message backslashes ;
+ debug-message -------------------------------------------------------------------- ;
+ }
+ else
+ {
+ # Prepare a List of Python format strings and expressions that
+ # can be used to print the constants we want from the sys
+ # module.
+
+ # We don't really want sys.version since that's a complicated
+ # string, so get the information from sys.version_info
+ # instead.
+ local format = "version=%d.%d" ;
+ local exprs = "version_info[0]" "version_info[1]" ;
+
+ for local s in $(sys-elements[2-])
         {
- debug-message $(interpreter) does not invoke a working Python interpreter ;
+ format += $(s)=%s ;
+ exprs += $(s) ;
         }
- else
+
+ # Invoke Python and ask it for all those values
+ local full-cmd =
+ $(python-cmd)" -c \"from sys import *; print '"$(format:J=\\n)"' % ("$(exprs:J=,)")\"" ;
+
+ local output = [ shell-cmd $(full-cmd) ] ;
+ if $(output)
         {
- debug-message $(interpreter) invokes actual Python (major,minor) version $(true-version) ;
-
- # if no version was specified, assume that's OK
- version ?= $(true-version) ;
-
- # if the version is a match, stop searching
- if $(version) = $(true-version)
+ # Parse the output to get all the results
+ local nl = "
+
+" ;
+ for s in $(sys-elements)
             {
- debug-message qualifying Python interpreter found ;
- root ?= [ python-root $(interpreter) ] ;
- cmds = ; # break
+ # These variables are expected to be declared local in
+ # the caller, so Jam's dynamic scoping will set their
+ # values there.
+ sys.$(s) = [ SUBST $(output) \\<$(s)=([^$(nl)]+) $1 ] ;
             }
         }
+ return $(output) ;
     }
- debug-message "Python interpreter command is" $(interpreter) ;
-
- includes ?= $(root)/include/python$(version) ;
- debug-message "Python include path is" $(includes) ;
-
- libraries ?= $(root)/lib/python$(version)/config ;
- debug-message "Python library path is" $(libraries) ;
-
- #
- # End autoconfiguration sequence
- #
-
-
- # Set up the PYTHON variable to point at the interpreter.
- # If no specific condition is specified, set global value
- # If condition is specified, set PYTHON on target. It will
- # override the global value.
- if ! $(condition)
+}
+
+# Make sure the "libraries" and "includes" variables (in an enclosing
+# scope) have a value based on the information given.
+local rule compute-default-paths (
+ target-os : version ? : prefix ? : exec-prefix ? )
+{
+ exec-prefix ?= $(prefix) ;
+
+ if $(target-os) = windows
     {
- PYTHON = $(interpreter) ;
+ # The exec_prefix is where you're supposed to look for
+ # machine-specific libraries.
+ local default-library-path = $(exec-prefix)\\libs ;
+ local default-include-path = $(:E=Include:R=$(prefix)) ;
+
+ # If the interpreter was found in a directory
+ # called "PCBuild" or "PCBuild8," assume we're
+ # looking at a Python built from the source
+ # distro, and go up one additional level to the
+ # default root. Otherwise, the default root is
+ # the directory where the interpreter was found.
+
+ # We ask Python itself what the executable path is
+ # in case of intermediate symlinks or shell
+ # scripts.
+ local executable-dir = $(sys.executable:D) ;
+
+ if [ MATCH ^(PCBuild) : $(executable-dir:D=) ]
+ {
+ debug-message "This Python appears to reside in a source distribution;" ;
+ debug-message "prepending \""$(executable-dir)"\" to default library search path" ;
+
+ default-library-path = $(executable-dir)
+ $(default-library-path) ;
+
+ default-include-path = $(:E=PC:R=$(executable-dir:D)) $(default-include-path) ;
+
+ debug-message "and \""$(default-include-path[1])"\" to default #include path" ;
+ }
+
+ libraries ?= $(default-library-path) ;
+ includes ?= $(default-include-path) ;
     }
     else
- {
- flags python.capture-output PYTHON $(condition:J=/) : $(interpreter) ;
- }
+ {
+ includes ?= $(prefix)/include/python$(version) ;
 
- # Provide system library dependencies for targets linking with
- # static Python libraries.
- #
- # On many systems, Python uses libraries such as pthreads or
- # libdl. Since static libraries carry no library dependency
- # information of their own that the linker can extract, these
- # extra dependencies have to be given explicitly on the link line
- # of the client. The information about these dependencies is
- # packaged into the "python" target below.
-
- # Even where Python itself uses pthreads, it never allows
- # extension modules to be entered concurrently (unless they
- # explicitly give up the interpreter lock). Therefore, extension
- # modules don't need the efficiency overhead of threadsafe code as
- # produced by <threading>multi, and we handle libpthread along
- # with other libraries here. Note: this optimization is based on
- # an assumption that the compiler generates link-compatible code
- # in both the single- and multi-threaded cases, and that system
- # libraries don't change their ABIs either.
-
- # Most libraries are added to 'extra-libs'. Those that depend on
- # the toolset are added to 'extra-libs-conditional', which will be
- # used to form more specific target alternatives.
-
- local extra-libs extra-libs-conditional ;
+ local lib = $(exec-prefix)/lib ;
+ libraries ?= $(lib)/python$(version)/config $(lib) ;
+ }
+}
 
- switch [ os.name ]
+# The version of the python interpreter to use
+feature.feature python : : propagated ;
+feature.feature python.interpreter : : free ;
+
+flags python.capture-output PYTHON : <python.interpreter> ;
+
+#
+# Support for Python configured --with-pydebug
+#
+feature.feature python-debugging : off on : propagated ;
+builtin.variant debug-python : debug : <python-debugging>on ;
+
+# Return a list of candidate commands to try when looking for a Python
+# interpreter. prefix is expected to be a native path.
+local rule candidate-interpreters ( version ? : prefix ? : target-os )
+{
+ local bin-path = bin ;
+ if $(target-os) = windows
     {
- case SOLARIS :
- {
- extra-libs = pthread dl ;
-
+ # on Windows, look in the root directory itself and, to work
+ # with the result of a build-from-source, the PCBuild directory
+ bin-path = PCBuild8 PCBuild "" ;
+ }
+
+ bin-path = $(bin-path:R=$(prefix)) ;
+
+ if $(target-os) in windows darwin
+ {
+ return # Search:
+ $(:E=python:R=$(bin-path)) # Relative to the prefix, if any
+ python # In the PATH
+ [ $(target-os)-installed-pythons $(version) ] # Standard install locations
+ ;
+ }
+ else
+ {
+ # Search relative to the prefix, or if none supplied, in PATH
+ local unversioned = $(:E=python:R=$(bin-path:E=)) ;
+
+ # if a version was specified, look for a python with that
+ # specific version appended before looking for one called,
+ # simply, "python"
+ return $(unversioned)$(version) $(unversioned) ;
+ }
+}
+
+# Compute system library dependencies for targets linking with
+# static Python libraries.
+#
+# On many systems, Python uses libraries such as pthreads or
+# libdl. Since static libraries carry no library dependency
+# information of their own that the linker can extract, these
+# extra dependencies have to be given explicitly on the link line
+# of the client. The information about these dependencies is
+# packaged into the "python" target below.
+
+# Even where Python itself uses pthreads, it never allows
+# extension modules to be entered concurrently (unless they
+# explicitly give up the interpreter lock). Therefore, extension
+# modules don't need the efficiency overhead of threadsafe code as
+# produced by <threading>multi, and we handle libpthread along
+# with other libraries here. Note: this optimization is based on
+# an assumption that the compiler generates link-compatible code
+# in both the single- and multi-threaded cases, and that system
+# libraries don't change their ABIs either.
+#
+# Returns a list of usage-requirements that link to the necessary
+# system libraries.
+local rule system-library-dependencies ( target-os )
+{
+ switch $(target-os)
+ {
+ case s[uo][nl]* : # solaris, sun, sunos
             # Add a librt dependency for the gcc toolset on SunOS (the
             # sun toolset adds -lrt unconditionally). While this
             # appears to duplicate the logic already in gcc.jam, it
             # doesn't as long as we're not forcing <threading>multi.
- extra-libs-conditional = <toolset>gcc:<source>rt ;
- }
-
- case OSF :
- {
- extra-libs = pthread ;
- extra-libs-conditional = <toolset>gcc:<source>rt ;
- }
-
- case QNX* :
- {
- extra-libs = ;
- }
-
- case HPUX :
+
+ # Caleb Epstein reports that his python's
+ # distutils.sysconfig.get_config_var('LIBS') yields
+ # -lresolv -lsocket -lnsl -lrt -ldl. However, we're not
+ # yet sure that is the right list for extension modules.
+ # Being conservative, we add rt and remove pthread, which
+ # was causing errors.
+ return <library>dl <toolset>gcc:<library>rt ;
+
+ case osf : return <library>pthread <toolset>gcc:<library>rt ;
+
+ case qnx* : return ;
+ case darwin : return ;
+ case windows : return ;
+
+ case hpux : return <library>rt ;
+
+ case aix : return <library>pthread <library>dl ;
+
+ case * : return <library>pthread <library>dl <toolset>gcc:<library>util ;
+ }
+}
+
+# Declare a target to represent Python's library.
+local rule declare-libpython-target ( version ? : requirements * )
+{
+ # Compute the representation of Python version in the name of
+ # Python's library file.
+ local lib-version = $(version) ;
+ if <target-os>windows in $(requirements)
+ {
+ local major-minor = [ split-version $(version) ] ;
+ lib-version = $(major-minor:J="") ;
+ if <python-debugging>on in $(requirements)
         {
- extra-libs = rt ;
+ lib-version = $(lib-version)_d ;
         }
-
- case * : extra-libs = pthread dl util ;
     }
-
- if ! [ os.on-windows ]
+
+ if ! $(lib-version)
     {
- # On *nix, we don't want to link either Boost.Python or Python
- # extensions to libpython, because the Python interpreter itself
- # provides all those symbols. If we linked to libpython, we'd get
- # duplicate symbols. So declare two targets -- one for building
- # extensions and another for embedding
- alias python_for_extensions
- :
- : $(condition)
- :
- : <include>$(includes)
- ;
+ ECHO *** warning: could not determine Python version, which will ;
+ ECHO *** warning: probably prevent us from linking with the python ;
+ ECHO *** warning: library. Consider explicitly passing the version ;
+ ECHO *** warning: to 'using python'. ;
     }
-
-
- # This should really be called python_for_embedding
- alias python
- : $(extra-libs)
- : $(condition) $(extra-libs-conditional)
- :
- : <include>$(includes)
- <library-path>$(libraries)
- <find-shared-library>python$(version)
- ;
+
+ # Declare it
+ lib python.lib : : <name>python$(lib-version) $(requirements) ;
 }
 
-rule init-mac ( version : root ? : includes ? : libraries ? )
+# implementation of init
+local rule configure (
+ version ? : cmd-or-prefix ? : includes * : libraries ? : condition * : extension-suffix ? )
 {
- if ! $(root)
+ local prefix ;
+ local exec-prefix ;
+ local cmds-to-try ;
+ local interpreter-cmd ;
+
+ local target-os = [ feature.get-values target-os : $(condition) ] ;
+ target-os ?= [ feature.defaults target-os ] ;
+ target-os = $(target-os:G=) ;
+
+ if $(target-os) = windows && <python-debugging>on in $(condition)
+ {
+ extension-suffix ?= _d ;
+ }
+ extension-suffix ?= "" ;
+
+ # Normalize and dissect any version number
+ local major-minor ;
+ if $(version)
+ {
+ major-minor = [ split-version $(version) ] ;
+ version = $(major-minor:J=.) ;
+ }
+
+ local cmds-to-try ;
+
+ if ! $(cmd-or-prefix) || [ GLOB $(cmd-or-prefix) : * ]
+ {
+ # if the user didn't pass a command, whatever we got was a prefix
+ prefix = $(cmd-or-prefix) ;
+ cmds-to-try = [ candidate-interpreters $(version) : $(prefix) : $(target-os) ] ;
+ }
+ else
     {
- if [ GLOB /System/Library/Frameworks : Python.framework ]
+ # Work with the command the user gave us.
+ cmds-to-try = $(cmd-or-prefix) ;
+
+ # On windows, don't nail down the interpreter command just yet
+ # in case the user specified something that turns out to be a
+ # cygwin symlink, which could bring down bjam if we invoke it.
+ if $(target-os) != windows
         {
- root = /System/Library/Frameworks/Python.framework/Versions/$(version) ;
+ interpreter-cmd = $(cmd-or-prefix) ;
         }
- else
+ }
+
+ # Values to use in case we can't really find anything in the system.
+ local fallback-cmd = $(cmds-to-try[1]) ;
+ local fallback-version ;
+
+ # Anything left to find or check?
+ if ! ( $(interpreter-cmd) && $(includes) && $(libraries) )
+ {
+ # Values to be extracted from python's sys module. These will
+ # be set by the probe rule, above, using Jam's dynamic scoping.
+ local sys-elements = version platform prefix exec_prefix executable ;
+ local sys.$(sys-elements) ;
+
+ # compute the string Python's sys.platform needs to match. If
+ # not targeting windows or cygwin we'll assume only native
+ # builds can possibly run, so we won't require a match and we
+ # leave sys.platform blank.
+ local platform ;
+ switch $(target-os)
         {
- root = /Library/Frameworks/Python.framework/Versions/$(version) ;
+ case windows : platform = win32 ;
+ case cygwin : platform = cygwin ;
         }
- }
+
+ while $(cmds-to-try)
+ {
+ # pop top command
+ local cmd = $(cmds-to-try[1]) ;
+ cmds-to-try = $(cmds-to-try[2-]) ;
 
- # includes ?= $(PYTHON_ROOT)/include/python$(PYTHON_VERSION) ;
- includes ?= $(root)/include/python$(version) ;
- libraries ?= $(root)/lib/python$(version)/config ;
-
- # Find the 'python' binary, which is used for testing.
- # Look first in $(root)/bin, then in PATH.
- local interpreter = [ common.get-invocation-command
- python : python : : $(root)/bin : path-last ] ;
+ debug-message Checking interpreter command \"$(cmd)\"... ;
+ if [ probe $(cmd) ]
+ {
+ fallback-version ?= $(sys.version) ;
+
+ # Check for version/platform validity
+ for local x in version platform
+ {
+ if $($(x)) && $($(x)) != $(sys.$(x))
+ {
+ debug-message ...$(x) "mismatch (looking for"
+ $($(x)) but found $(sys.$(x))")" ;
+ cmd = ;
+ }
+ }
+
+ if $(cmd)
+ {
+ debug-message ...requested configuration matched! ;
+
+ exec-prefix = $(sys.exec_prefix) ;
+
+ compute-default-paths
+ $(target-os)
+ : $(sys.version)
+ : $(sys.prefix)
+ : $(sys.exec_prefix) ;
+
+ version = $(sys.version) ;
+ interpreter-cmd ?= $(cmd) ;
+ cmds-to-try = ; # All done.
+ }
+ }
+ else
+ {
+ debug-message ...does not invoke a working interpreter ;
+ }
+ }
+ }
     
- # debug support
- if --debug-configuration in [ modules.peek : ARGV ]
+ # Anything left to compute?
+ if $(includes) && $(libraries)
     {
- ECHO "notice: Python include path is" $(includes) ;
- ECHO "notice: Python library path is" $(libraries) ;
- ECHO "notice: Python interpreter is" $(interpreter) ;
+ .configured = true ;
     }
-
- PYTHON = $(interpreter) ;
- flags python.capture-output PYTHON : $(interpreter) ;
-
- PYTHON_FRAMEWORK ?= $(root) ;
- while $(PYTHON_FRAMEWORK:D=) && $(PYTHON_FRAMEWORK:D=) != Python.framework
+ else
     {
- PYTHON_FRAMEWORK = $(PYTHON_FRAMEWORK:D) ;
+ version ?= $(fallback-version) ;
+ version ?= 2.5 ;
+ exec-prefix ?= $(prefix) ;
+ compute-default-paths $(target-os) : $(version) : $(prefix:E=) ;
     }
- PYTHON_FRAMEWORK = $(PYTHON_FRAMEWORK:D)/Python ;
 
- alias python
- :
- : <os>MACOSX <toolset>darwin
- :
- : <include>$(includes) <framework>$(PYTHON_FRAMEWORK)
- ;
+ if ! $(interpreter-cmd)
+ {
+ fallback-cmd ?= python ;
+ debug-message No working Python interpreter found. ;
+ if [ os.name ] != NT || ! [ invokes-cygwin-symlink $(fallback-cmd) ]
+ {
+ interpreter-cmd = $(fallback-cmd) ;
+ debug-message falling back to \"$(interpreter-cmd)\" ;
+ }
+ }
 
- # Unlike most *nix systems, Mac OS X's linker does not permit undefined
- # symbols when linking a shared library. So, we still need to link
- # against the Python framework, even when building extensions.
- # Note that framework builds of Python always use shared libraries,
- # so we do not need to worry about duplicate Python symbols.
- .alias-defined = true ;
- alias python_for_extensions : python ;
-}
+ includes = [ path-to-native $(includes) ] ;
+ libraries = [ path-to-native $(libraries) ] ;
 
-rule init-nt ( version : root ? : includes ? : libraries ? : cygwin-condition ? )
-{
- if ! $(cygwin-condition)
- {
- # The name of Python library file does not have a dot between
- # major and minor version.
- local PYTHON_VERSION_NODOT = [ regex.match ([0-9]+)[.]([0-9]+).* : $(version) : 1 2 ] ;
+ debug-message "Details of this Python configuration:" ;
+ debug-message " interpreter command:" \"$(interpreter-cmd:E=<empty>)\" ;
+ debug-message " include path:" \"$(includes:E=<empty>)\" ;
+ debug-message " library path:" \"$(libraries:E=<empty>)\" ;
+ if $(target-os) = windows
+ {
+ debug-message " DLL search path:" \"$(exec-prefix:E=<empty>)\" ;
+ }
 
- PYTHON_VERSION_NODOT = $(PYTHON_VERSION_NODOT:J="") ;
 
- root ?= c:/python$(PYTHON_VERSION_NODOT) ;
-
- local PATH = [ modules.peek : PATH ] ;
- local PATH = [ modules.peek : Path ] ;
-
- PYTHON_INCLUDES = $(includes) ;
- PYTHON_LIB_PATH = $(libraries) ;
+ #
+ # End autoconfiguration sequence
+ #
+ local target-requirements = $(condition) ;
 
- PYTHON_LIB_PATH ?= $(root)/libs [ GLOB $(root) : PCbuild ] ;
-
- PYTHON_INCLUDES ?= $(root)/include [ GLOB $(root) : PC ] ;
-
-
- PYTHON_DLL ?= [ GLOB $(PATH) $(Path) : python$(PYTHON_VERSION_NODOT).dll ] ;
- PYTHON_DEBUG_DLL ?= [ GLOB $(PATH) $(Path) : python$(PYTHON_VERSION_NODOT)_d.dll ] ;
- PYTHON_IMPORT_LIB ?= [ GLOB $(PYTHON_LIB_PATH) : libpython$(PYTHON_VERSION_NODOT).* ] ;
- PYTHON_DEBUG_IMPORT_LIB ?= [ GLOB $(PYTHON_LIB_PATH) : libpython$(PYTHON_VERSION_NODOT).* ] ;
-
- local interpreter = [ common.get-invocation-command
- python.exe : python.exe : : $(root)/bin
- $(root)
- $(root)/PCBuild
- : path-last ] ;
-
- if --debug-configuration in [ modules.peek : ARGV ]
+ # Add the version, if any, to the target requirements
+ if $(version)
+ {
+ if ! $(version) in [ feature.values python ]
         {
- ECHO "notice: Python include path is" $(PYTHON_INCLUDES) ;
- ECHO "notice: Python library path is" $(PYTHON_LIB_PATH) ;
- ECHO "notice: Python interpreter is" $(interpreter) ;
- ECHO "notice: Python library name is" python$(PYTHON_VERSION_NODOT) ;
+ feature.extend python : $(version) ;
         }
-
- PYTHON = $(interpreter) ;
- flags python.capture-output PYTHON : $(interpreter) ;
-
- properties += <library-path>$(PYTHON_LIB_PATH) ;
-
- # msvc compilers auto-find the python library
- # declare two alternatives -- one for msvc and another
- # for the rest of the world
- alias python
- :
- : <toolset>msvc
- :
- : <library-path>$(PYTHON_LIB_PATH)
- <include>$(PYTHON_INCLUDES)
- ;
-
- local lib = python$(PYTHON_VERSION_NODOT) ;
-
- alias python
- :
- :
- :
- : <library-path>$(PYTHON_LIB_PATH)
- <include>$(PYTHON_INCLUDES)
- <find-shared-library>$(lib) ;
+ target-requirements += <python>$(version:E=default) ;
     }
- else
- {
- root ?= /usr ;
- if $(root) = /usr
+
+ target-requirements += <target-os>$(target-os) ;
+
+ # See if we can find a framework directory on darwin
+ local framework-directory ;
+ if $(target-os) = darwin
+ {
+ # Search upward for the framework directory
+ local framework-directory = $(libraries[-1]) ;
+ while $(framework-directory:D=) && $(framework-directory:D=) != Python.framework
         {
- CYGWIN_PYTHON_DLL_PATH ?= /bin ;
+ framework-directory = $(framework-directory:D) ;
+ }
+
+ if $(framework-directory) = Python.framework
+ {
+ debug-message framework directory is \"$(fwk)\" ;
         }
         else
         {
- CYGWIN_PYTHON_DLL_PATH ?= $(root)/bin ;
+ debug-message no framework directory found; using library path ;
+ framework-directory = ;
         }
- CYGWIN_PYTHON_LIB_PATH ?= $(CYGWIN_PYTHON_ROOT)/lib/python$(version)/config ;
-
- CYGWIN_PYTHON_DEBUG_VERSION ?= $(version) ;
- CYGWIN_PYTHON_DEBUG_ROOT ?= /usr/local/pydebug ;
- CYGWIN_PYTHON_DEBUG_DLL_PATH ?= $(CYGWIN_PYTHON_DEBUG_ROOT)/bin ;
- CYGWIN_PYTHON_DEBUG_LIB_PATH ?= $(CYGWIN_PYTHON_DEBUG_ROOT)/lib/python$(CYGWIN_PYTHON_DEBUG_VERSION)/config ;
-
- local properties ;
+ }
 
- properties += <library-path>$(CYGWIN_PYTHON_LIB_PATH)
- <find-shared-library>python$(CYGWIN_PYTHON_VERSION).dll ;
-
- properties += <include>$(root)/include/python$(version) ;
-
+ local dll-path = $(libraries) ;
+
+ # Make sure that we can find the Python DLL on windows
+ if $(target-os) = windows && $(exec-prefix)
+ {
+ dll-path += $(exec-prefix) ;
+ }
+
+ #
+ # prepare usage requirements
+ #
+ local usage-requirements = [ system-library-dependencies $(target-os) ] ;
+ usage-requirements += <include>$(includes) <python.interpreter>$(interpreter-cmd) ;
+ if <python-debugging>on in $(condition)
+ {
+ if $(target-os) = windows
+ {
+ # in pyconfig.h, Py_DEBUG is set if _DEBUG is set. If we
+ # define Py_DEBUG we'll get multiple definition warnings.
+ usage-requirements += <define>_DEBUG ;
+ }
+ else
+ {
+ usage-requirements += <define>Py_DEBUG ;
+ }
+ }
+
+ # Register the right suffix for extensions
+ register-extension-suffix $(extension-suffix) : $(target-requirements) ;
+
+ #
+ # Declare the "python" target. This should really be called
+ # python_for_embedding
+ #
+
+ if $(framework-directory)
+ {
         alias python
           :
- : $(cygwin-condition)
+ : $(target-requirements)
           :
- : $(properties)
- ;
- }
-}
+ : $(usage-requirements) <framework>$(fwk)
+ ;
+ }
+ else
+ {
+ declare-libpython-target $(version) : $(target-requirements) ;
+ alias python
+ :
+ : $(target-requirements)
+ :
+ # why python.lib must be listed here instead of along with
+ # the system libs is a mystery, but if we don't do it, on
+ # cygwin, -lpythonX.Y never appears in the command line
+ # (although it does on linux).
+ : $(usage-requirements) <library-path>$(libraries) <dll-path>$(dll-path) <library>python.lib
+ ;
+ }
 
+ # On *nix, we don't want to link either Boost.Python or Python
+ # extensions to libpython, because the Python interpreter itself
+ # provides all those symbols. If we linked to libpython, we'd get
+ # duplicate symbols. So declare two targets -- one for building
+ # extensions and another for embedding
+ #
+ # Unlike most *nix systems, Mac OS X's linker does not permit undefined
+ # symbols when linking a shared library. So, we still need to link
+ # against the Python framework, even when building extensions.
+ # Note that framework builds of Python always use shared libraries,
+ # so we do not need to worry about duplicate Python symbols.
+ if $(target-os) in windows cygwin darwin
+ {
+ alias python_for_extensions : python : $(target-requirements) ;
+ }
+ # On AIX we need Python extensions and Boost.Python to import symbols
+ # from the Python interpreter. Dynamic libraries opened with dlopen()
+ # do not inherit the symbols from the Python interpreter.
+ else if $(target-os) = aix
+ {
+ alias python_for_extensions
+ :
+ : $(target-requirements)
+ :
+ : $(usage-requirements) <linkflags>-Wl,-bI:$(libraries[1])/python.exp
+ ;
+ }
+ else
+ {
+ alias python_for_extensions
+ :
+ : $(target-requirements)
+ :
+ : $(usage-requirements)
+ ;
+ }
+}
 
-rule configured ( )
+rule configured ( )
 {
      return $(.configured) ;
 }
-
+
 type.register PYTHON_EXTENSION : : SHARED_LIB ;
 
-# We can't give "dll" suffix to PYTHON_EXTENSION, because
-# we would not know what "a.dll" is: python extenstion or
-# ordinary library. Therefore, we specify only suffixes
-# used for generation of targets.
-type.set-generated-target-suffix PYTHON_EXTENSION : : so ;
-type.set-generated-target-suffix PYTHON_EXTENSION : <os>NT : pyd ;
-type.set-generated-target-suffix PYTHON_EXTENSION : <os>CYGWIN : dll ;
+local rule register-extension-suffix ( root : condition * )
+{
+ local suffix ;
+
+ switch [ feature.get-values target-os : $(condition) ]
+ {
+ case windows : suffix = pyd ;
+ case cygwin : suffix = dll ;
+ case hpux :
+ {
+ if [ feature.get-values python : $(condition) ] in 1.5 1.6 2.0 2.1 2.2 2.3 2.4
+ {
+ suffix = sl ;
+ }
+ else
+ {
+ suffix = so ;
+ }
+ }
+ case * : suffix = so ;
+ }
+
+ type.set-generated-target-suffix PYTHON_EXTENSION : $(condition) : <$(root).$(suffix)> ;
+}
 
 # Unset 'lib' prefix for PYTHON_EXTENSION
 type.set-generated-target-prefix PYTHON_EXTENSION : : "" ;
 
-rule python-extension ( name : sources * : requirements * : default-build * :
+rule python-extension ( name : sources * : requirements * : default-build * :
                         usage-requirements * )
 {
- requirements += <use>/python//python_for_extensions ;
-
+ requirements += <use>/python//python_for_extensions <suppress-import-lib>true ;
+
     local project = [ project.current ] ;
 
-
+
     targets.main-target-alternative
       [ new typed-target $(name) : $(project) : PYTHON_EXTENSION
         : [ targets.main-target-sources $(sources) : $(name) ]
- : [ targets.main-target-requirements $(requirements) : $(project) ]
- : [ targets.main-target-default-build $(default-build) : $(project) ]
+ : [ targets.main-target-requirements $(requirements) : $(project) ]
+ : [ targets.main-target-default-build $(default-build) : $(project) ]
       ] ;
-}
+}
 
 IMPORT python : python-extension : : python-extension ;
 
@@ -538,15 +1013,15 @@
 class python-test-generator : generator
 {
     import set ;
-
+
     rule __init__ ( * : * )
     {
         generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
         self.composing = true ;
     }
-
+
     rule run ( project name ? : property-set : sources * : multiple ? )
- {
+ {
         local python ;
         local other-pythons ;
         for local s in $(sources)
@@ -562,10 +1037,10 @@
                 {
                     # Other Python sources become dependencies.
                     other-pythons += $(s) ;
- }
+ }
             }
         }
-
+
         local extensions ;
         for local s in $(sources)
         {
@@ -574,53 +1049,69 @@
                 extensions += $(s) ;
             }
         }
-
+
         local libs ;
         for local s in $(sources)
         {
- if [ type.is-derived [ $(s).type ] LIB ]
+ if [ type.is-derived [ $(s).type ] LIB ]
               && ! $(s) in $(extensions)
             {
                 libs += $(s) ;
             }
         }
-
+
         local new-sources ;
         for local s in $(sources)
         {
- if [ type.is-derived [ $(s).type ] CPP ]
+ if [ type.is-derived [ $(s).type ] CPP ]
             {
                 local name = [ utility.basename [ $(s).name ] ] ;
                 if $(name) = [ utility.basename [ $(python).name ] ]
                 {
                     name = $(name)_ext ;
- }
+ }
                 local extension = [ generators.construct $(project) $(name) :
                   PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ;
 
- # The important part of usage requirements returned from
- # PYTHON_EXTENSION genrator are xdll-path properties that
- # will allow to find python extension at runtime.
+ # The important part of usage requirements returned
+ # from PYTHON_EXTENSION generator are xdll-path
+ # properties that will allow us to find the python
+ # extension at runtime.
                 property-set = [ $(property-set).add $(extension[1]) ] ;
- # Ignore usage requirements. We're top-level generator and
- # nobody is going to use us.
+
+ # Ignore usage requirements. We're a top-level
+ # generator and nobody is going to use what we
+ # generate.
                 new-sources += $(extension[2-]) ;
             }
         }
 
         property-set = [ $(property-set).add-raw <dependency>$(other-pythons) ] ;
-
- result = [ construct-result $(python) $(extensions) $(new-sources)
- : $(project) $(name) : $(property-set) ] ;
- }
+
+ result = [ construct-result $(python) $(extensions) $(new-sources)
+ : $(project) $(name) : $(property-set) ] ;
+ }
 }
 
-generators.register
+generators.register
   [ new python-test-generator python.capture-output : : RUN_PYD_OUTPUT ] ;
 
-generators.register-standard testing.expect-success
+generators.register-standard testing.expect-success
   : RUN_PYD_OUTPUT : RUN_PYD ;
 
+# There are two different ways of spelling OS names. One is used for
+# [ os.name ] and the other is used for the <host-os> and <target-os>
+# properties. Until that is remedied, this sets up a crude mapping
+# from the latter to the former, that will work *for the purposes of
+# cygwin/NT cross-builds only*. Couldn't think of a better name than
+# "translate"
+.translate-os-windows = NT ;
+.translate-os-cygwin = CYGWIN ;
+local rule translate-os ( src-os )
+{
+ local x = $(.translate-os-$(src-os)) [ os.name ] ;
+ return $(x[1]) ;
+}
 
 # The flag settings on testing.capture-output do not
 # apply to python.capture output at the moment.
@@ -633,24 +1124,44 @@
     # DLL. Only $(sources[1]) is passed to testing.capture-output,
     # so RUN_PATH variable on $(sources[2]) is not consulted. Move it
     # over explicitly.
- RUN_PATH on $(sources[1]) = [ on $(sources[2]) return $(RUN_PATH) ] ;
- PYTHONPATH = [ on $(sources[2]) return $(LOCATE) ] ;
+ RUN_PATH on $(sources[1]) = [ on $(sources[2-]) return $(RUN_PATH) ] ;
+
+ PYTHONPATH = [ on $(sources[2-]) return $(LOCATE) $(SEARCH) ] ;
+
     # After test is run, we remove the Python module, but not the Python
     # script.
- testing.capture-output $(target) : $(sources[1]) : $(properties)
- : $(sources[2]) ;
- local c = [ common.prepend-path-variable-command PYTHONPATH : $(PYTHONPATH) ] ;
- LAUNCHER on $(target) = $(c) [ on $(target) return $(PYTHON) ] ;
+ testing.capture-output $(target) : $(sources[1]) : $(properties)
+ : $(sources[2-]) ;
+
+ # 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 where we can run pythons for other OSes
+ # currently are NT and CYGWIN, so we only need to handle those
+ # cases.
+ local target-os = [ feature.get-values target-os : $(properties) ] ;
+ # oddly, host-os isn't in properties, so grab the default value.
+ local host-os = [ feature.defaults host-os ] ;
+ host-os = $(host-os:G=) ;
+ if $(target-os) != $(host-os)
+ {
+ PYTHONPATH =
+ [ sequence.transform $(host-os)-to-$(target-os)-path : $(PYTHONPATH) ] ;
+ }
+ local path-separator =
+ [ os.path-separator [ translate-os $(target-os) ] ] ;
+ local set-PYTHONPATH =
+ [ common.variable-setting-command PYTHONPATH : $(PYTHONPATH:J=$(path-separator)) ] ;
+ LAUNCHER on $(target) = $(set-PYTHONPATH) [ on $(target) return $(PYTHON) ] ;
 }
 
 rule bpl-test ( name : sources * : requirements * )
-{
+{
     sources ?= $(name).py $(name).cpp ;
- return [ testing.make-test
+ return [ testing.make-test
         run-pyd : $(sources) /boost/python//boost_python
           : $(requirements) : $(name) ] ;
 }
 
 IMPORT $(__name__) : bpl-test : : bpl-test ;
-
-
+
+


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk