$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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 ;
-  
-  
+
+