1# Copyright 2004 Vladimir Prus.
2# Distributed under the Boost Software License, Version 1.0. (See
3# accompanying file LICENSE_1_0.txt or copy at
4# http://www.boost.org/LICENSE_1_0.txt)
5
6# Support for Python and the the Boost.Python library.
7#
8# This module defines
9#
10# - a project 'python' with a target 'python' in it, that corresponds to the
11#   python library
12#
13# - a main target rule 'python-extension' which can be used to build a python
14#   extension.
15#
16# Extensions that use Boost.Python must explicitly link to it.
17
18import type ;
19import testing ;
20import generators ;
21import project ;
22import errors ;
23import targets ;
24import "class" : new ;
25import os ;
26import common ;
27import toolset ;
28import regex ;
29import numbers ;
30import string ;
31import property ;
32import sequence ;
33import path ;
34import feature ;
35import set ;
36import builtin ;
37
38
39# Make this module a project.
40project.initialize $(__name__) ;
41project python ;
42
43# Save the project so that if 'init' is called several times we define new
44# targets in the python project, not in whatever project we were called by.
45.project = [ project.current ] ;
46
47# Dynamic linker lib. Necessary to specify it explicitly on some platforms.
48lib dl ;
49# This contains 'openpty' function need by python. Again, on some system need to
50# pass this to linker explicitly.
51lib util ;
52# Python uses pthread symbols.
53lib pthread ;
54# Extra library needed by phtread on some platforms.
55lib rt ;
56
57# The pythonpath feature specifies additional elements for the PYTHONPATH
58# environment variable, set by run-pyd. For example, pythonpath can be used to
59# access Python modules that are part of the product being built, but are not
60# installed in the development system's default paths.
61feature.feature pythonpath : : free optional path ;
62
63# Initializes the Python toolset. Note that all parameters are optional.
64#
65# - version -- the version of Python to use. Should be in Major.Minor format,
66#   for example 2.3.  Do not include the subminor version.
67#
68# - cmd-or-prefix: Preferably, a command that invokes a Python interpreter.
69#   Alternatively, the installation prefix for Python libraries and includes. If
70#   empty, will be guessed from the version, the platform's installation
71#   patterns, and the python executables that can be found in PATH.
72#
73# - includes: the include path to Python headers. If empty, will be guessed.
74#
75# - libraries: the path to Python library binaries. If empty, will be guessed.
76#   On MacOS/Darwin, you can also pass the path of the Python framework.
77#
78# - condition: if specified, should be a set of properties that are matched
79#   against the build configuration when Boost.Build selects a Python
80#   configuration to use.
81#
82# - extension-suffix: A string to append to the name of extension modules before
83#   the true filename extension.  Ordinarily we would just compute this based on
84#   the value of the <python-debugging> feature. However ubuntu's python-dbg
85#   package uses the windows convention of appending _d to debug-build extension
86#   modules. We have no way of detecting ubuntu, or of probing python for the
87#   "_d" requirement, and if you configure and build python using
88#   --with-pydebug, you'll be using the standard *nix convention. Defaults to ""
89#   (or "_d" when targeting windows and <python-debugging> is set).
90#
91# Example usage:
92#
93#   using python : 2.3 ;
94#   using python : 2.3 : /usr/local/bin/python ;
95#
96rule init ( version ? : cmd-or-prefix ? : includes * : libraries ?
97    : condition * : extension-suffix ? )
98{
99    project.push-current $(.project) ;
100
101    debug-message Configuring python... ;
102    for local v in version cmd-or-prefix includes libraries condition
103    {
104        if $($(v))
105        {
106            debug-message "  user-specified "$(v): \"$($(v))\" ;
107        }
108    }
109
110    configure $(version) : $(cmd-or-prefix) : $(includes) : $(libraries) : $(condition) : $(extension-suffix) ;
111
112    project.pop-current ;
113}
114
115# A simpler version of SHELL that grabs stderr as well as stdout, but returns
116# nothing if there was an error.
117#
118local rule shell-cmd ( cmd )
119{
120    debug-message running command '$(cmd)" 2>&1"' ;
121    x = [ SHELL $(cmd)" 2>&1" : exit-status ] ;
122    if $(x[2]) = 0
123    {
124        return $(x[1]) ;
125    }
126    else
127    {
128        return ;
129    }
130}
131
132
133# Try to identify Cygwin symlinks. Invoking such a file directly as an NT
134# executable from a native Windows build of bjam would be fatal to the bjam
135# process. One /can/ invoke them through sh.exe or bash.exe, if you can prove
136# that those are not also symlinks. ;-)
137#
138# If a symlink is found returns non-empty; we try to extract the target of the
139# symlink from the file and return that.
140#
141# Note: 1. only works on NT  2. path is a native path.
142local rule is-cygwin-symlink ( path )
143{
144    local is-symlink = ;
145
146    # Look for a file with the given path having the S attribute set, as cygwin
147    # symlinks do. /-C means "do not use thousands separators in file sizes."
148    local dir-listing = [ shell-cmd "DIR /-C /A:S \""$(path)"\"" ] ;
149
150    if $(dir-listing)
151    {
152        # Escape any special regex characters in the base part of the path.
153        local base-pat = [ regex.escape $(path:D=) : ].[()*+?|\\$^ : \\ ] ;
154
155        # Extract the file's size from the directory listing.
156        local size-of-system-file = [ MATCH "([0-9]+) "$(base-pat) : $(dir-listing) : 1 ] ;
157
158        # If the file has a reasonably small size, look for the special symlink
159        # identification text.
160        if $(size-of-system-file) && [ numbers.less $(size-of-system-file) 1000 ]
161        {
162            local link = [ SHELL "FIND /OFF \"!<symlink>\" \""$(path)"\" 2>&1" ] ;
163            if $(link[2]) != 0
164            {
165                local nl = "
166
167" ;
168                is-symlink = [ MATCH ".*!<symlink>([^"$(nl)"]*)" : $(link[1]) : 1 ] ;
169                if $(is-symlink)
170                {
171                    is-symlink = [ *nix-path-to-native $(is-symlink) ] ;
172                    is-symlink = $(is-symlink:R=$(path:D)) ;
173                }
174
175            }
176        }
177    }
178    return $(is-symlink) ;
179}
180
181
182# Append ext to each member of names that does not contain '.'.
183#
184local rule default-extension ( names * : ext * )
185{
186    local result ;
187    for local n in $(names)
188    {
189        switch $(n)
190        {
191            case *.* : result += $(n) ;
192            case * : result += $(n)$(ext) ;
193        }
194    }
195    return $(result) ;
196}
197
198
199# Tries to determine whether invoking "cmd" would actually attempt to launch a
200# cygwin symlink.
201#
202# Note: only works on NT.
203#
204local rule invokes-cygwin-symlink ( cmd )
205{
206    local dirs = $(cmd:D) ;
207    if ! $(dirs)
208    {
209        dirs = . [ os.executable-path ] ;
210    }
211    local base = [ default-extension $(cmd:D=) : .exe .cmd .bat ] ;
212    local paths = [ GLOB $(dirs) : $(base) ] ;
213    if $(paths)
214    {
215        # Make sure we have not run into a Cygwin symlink. Invoking such a file
216        # as an NT executable would be fatal for the bjam process.
217        return [ is-cygwin-symlink $(paths[1]) ] ;
218    }
219}
220
221
222local rule debug-message ( message * )
223{
224    if --debug-configuration in [ modules.peek : ARGV ]
225    {
226        ECHO notice: [python-cfg] $(message) ;
227    }
228}
229
230
231# Like W32_GETREG, except prepend HKEY_CURRENT_USER\SOFTWARE and
232# HKEY_LOCAL_MACHINE\SOFTWARE to the first argument, returning the first result
233# found. Also accounts for the fact that on 64-bit machines, 32-bit software has
234# its own area, under SOFTWARE\Wow6432node.
235#
236local rule software-registry-value ( path : data ? )
237{
238    local result ;
239    for local root in HKEY_CURRENT_USER HKEY_LOCAL_MACHINE
240    {
241        for local x64elt in "" Wow6432node\\ # Account for 64-bit windows
242        {
243            if ! $(result)
244            {
245                result = [ W32_GETREG $(root)\\SOFTWARE\\$(x64elt)$(path) : $(data) ] ;
246            }
247        }
248
249    }
250    return $(result) ;
251}
252
253
254.windows-drive-letter-re = ^([A-Za-z]):[\\/](.*) ;
255.cygwin-drive-letter-re = ^/cygdrive/([a-z])/(.*) ;
256
257.working-directory = [ PWD ] ;
258.working-drive-letter = [ SUBST $(.working-directory) $(.windows-drive-letter-re) $1 ] ;
259.working-drive-letter ?= [ SUBST $(.working-directory) $(.cygwin-drive-letter-re) $1 ] ;
260
261
262local rule windows-to-cygwin-path ( path )
263{
264    # If path is rooted with a drive letter, rewrite it using the /cygdrive
265    # mountpoint.
266    local p = [ SUBST $(path:T) $(.windows-drive-letter-re) /cygdrive/$1/$2 ] ;
267
268    # Else if path is rooted without a drive letter, use the working directory.
269    p ?= [ SUBST $(path:T) ^/(.*) /cygdrive/$(.working-drive-letter:L)/$2 ] ;
270
271    # Else return the path unchanged.
272    return $(p:E=$(path:T)) ;
273}
274
275
276# :W only works in Cygwin builds of bjam.  This one works on NT builds as well.
277#
278local rule cygwin-to-windows-path ( path )
279{
280    path = $(path:R="") ; # strip any trailing slash
281
282    local drive-letter = [ SUBST $(path) $(.cygwin-drive-letter-re) $1:/$2 ] ;
283    if $(drive-letter)
284    {
285        path = $(drive-letter) ;
286    }
287    else if $(path:R=/x) = $(path) # already rooted?
288    {
289        # Look for a cygwin mount that includes each head sequence in $(path).
290        local head = $(path) ;
291        local tail = "" ;
292
293        while $(head)
294        {
295            local root = [ software-registry-value
296                "Cygnus Solutions\\Cygwin\\mounts v2\\"$(head) : native ] ;
297
298            if $(root)
299            {
300                path = $(tail:R=$(root)) ;
301                head = ;
302            }
303            tail = $(tail:R=$(head:D=)) ;
304
305            if $(head) = /
306            {
307                head = ;
308            }
309            else
310            {
311                head = $(head:D) ;
312            }
313        }
314    }
315    return [ regex.replace $(path:R="") / \\ ] ;
316}
317
318
319# Convert a *nix path to native.
320#
321local rule *nix-path-to-native ( path )
322{
323    if [ os.name ] = NT
324    {
325        path = [ cygwin-to-windows-path $(path) ] ;
326    }
327    return $(path) ;
328}
329
330
331# Convert an NT path to native.
332#
333local rule windows-path-to-native ( path )
334{
335    if [ os.name ] = NT
336    {
337        return $(path) ;
338    }
339    else
340    {
341        return [ windows-to-cygwin-path $(path) ] ;
342    }
343}
344
345
346# Return nonempty if path looks like a windows path, i.e. it starts with a drive
347# letter or contains backslashes.
348#
349local rule guess-windows-path ( path )
350{
351    return [ SUBST $(path) ($(.windows-drive-letter-re)|.*([\\]).*) $1 ] ;
352}
353
354
355local rule path-to-native ( paths * )
356{
357    local result ;
358
359    for local p in $(paths)
360    {
361        if [ guess-windows-path $(p) ]
362        {
363            result += [ windows-path-to-native $(p) ] ;
364        }
365        else
366        {
367            result += [ *nix-path-to-native $(p:T) ] ;
368        }
369    }
370    return $(result) ;
371}
372
373
374# Validate the version string and extract the major/minor part we care about.
375#
376local rule split-version ( version )
377{
378    local major-minor = [ MATCH ^([0-9]+)\.([0-9]+)(.*)$ : $(version) : 1 2 3 ] ;
379    if ! $(major-minor[2]) || $(major-minor[3])
380    {
381        ECHO "Warning: \"using python\" expects a two part (major, minor) version number; got" $(version) instead ;
382
383        # Add a zero to account for the missing digit if necessary.
384        major-minor += 0 ;
385    }
386
387    return $(major-minor[1]) $(major-minor[2]) ;
388}
389
390
391# Build a list of versions from 3.4 down to 1.5. Because bjam can not enumerate
392# registry sub-keys, we have no way of finding a version with a 2-digit minor
393# version, e.g. 2.10 -- let us hope that never happens.
394#
395.version-countdown = ;
396for local v in [ numbers.range 15 34 ]
397{
398    .version-countdown = [ SUBST $(v) (.)(.*) $1.$2 ] $(.version-countdown) ;
399}
400
401
402local rule windows-installed-pythons ( version ? )
403{
404    version ?= $(.version-countdown) ;
405    local interpreters ;
406
407    for local v in $(version)
408    {
409        local install-path = [
410          software-registry-value "Python\\PythonCore\\"$(v)"\\InstallPath" ] ;
411
412        if $(install-path)
413        {
414            install-path = [ windows-path-to-native $(install-path) ] ;
415            debug-message Registry indicates Python $(v) installed at \"$(install-path)\" ;
416        }
417
418        interpreters += $(:E=python:R=$(install-path)) ;
419    }
420    return $(interpreters) ;
421}
422
423
424local rule darwin-installed-pythons ( version ? )
425{
426    version ?= $(.version-countdown) ;
427
428    local prefix
429      = [ GLOB /System/Library/Frameworks /Library/Frameworks
430          : Python.framework ] ;
431
432    return $(prefix)/Versions/$(version)/bin/python ;
433}
434
435
436# Assume "python-cmd" invokes a python interpreter and invoke it to extract all
437# the information we care about from its "sys" module. Returns void if
438# unsuccessful.
439#
440local rule probe ( python-cmd )
441{
442    # Avoid invoking a Cygwin symlink on NT.
443    local skip-symlink ;
444    if [ os.name ] = NT
445    {
446        skip-symlink = [ invokes-cygwin-symlink $(python-cmd) ] ;
447    }
448
449    if $(skip-symlink)
450    {
451        debug-message -------------------------------------------------------------------- ;
452        debug-message \"$(python-cmd)\" would attempt to invoke a Cygwin symlink, ;
453        debug-message causing a bjam built for Windows to hang. ;
454        debug-message ;
455        debug-message If you intend to target a Cygwin build of Python, please ;
456        debug-message replace the path to the link with the path to a real executable ;
457        debug-message (guessing: \"$(skip-symlink)\") "in" your 'using python' line ;
458        debug-message "in" user-config.jam or site-config.jam. Do not forget to escape ;
459        debug-message backslashes ;
460        debug-message -------------------------------------------------------------------- ;
461    }
462    else
463    {
464        # Prepare a List of Python format strings and expressions that can be
465        # used to print the constants we want from the sys module.
466
467        # We do not really want sys.version since that is a complicated string,
468        # so get the information from sys.version_info instead.
469        local format = "version=%d.%d" ;
470        local exprs = "version_info[0]" "version_info[1]" ;
471
472        for local s in $(sys-elements[2-])
473        {
474            format += $(s)=%s ;
475            exprs += $(s) ;
476        }
477
478        # Invoke Python and ask it for all those values.
479        local full-cmd =
480            $(python-cmd)" -c \"from sys import *; print('"$(format:J=\\n)"' % ("$(exprs:J=,)"))\"" ;
481
482        local output = [ shell-cmd $(full-cmd) ] ;
483        if $(output)
484        {
485            # Parse the output to get all the results.
486            local nl = "
487
488" ;
489            for s in $(sys-elements)
490            {
491                # These variables are expected to be declared local in the
492                # caller, so Jam's dynamic scoping will set their values there.
493                sys.$(s) = [ SUBST $(output) \\<$(s)=([^$(nl)]+) $1 ] ;
494            }
495        }
496        return $(output) ;
497    }
498}
499
500
501# Make sure the "libraries" and "includes" variables (in an enclosing scope)
502# have a value based on the information given.
503#
504local rule compute-default-paths ( target-os : version ? : prefix ? :
505    exec-prefix ? )
506{
507    exec-prefix ?= $(prefix) ;
508
509    if $(target-os) = windows
510    {
511        # The exec_prefix is where you're supposed to look for machine-specific
512        # libraries.
513        local default-library-path = $(exec-prefix)\\libs ;
514        local default-include-path = $(:E=Include:R=$(prefix)) ;
515
516        # If the interpreter was found in a directory called "PCBuild" or
517        # "PCBuild8," assume we're looking at a Python built from the source
518        # distro, and go up one additional level to the default root. Otherwise,
519        # the default root is the directory where the interpreter was found.
520
521        # We ask Python itself what the executable path is in case of
522        # intermediate symlinks or shell scripts.
523        local executable-dir = $(sys.executable:D) ;
524
525        if [ MATCH ^(PCBuild) : $(executable-dir:D=) ]
526        {
527            debug-message "This Python appears to reside in a source distribution;" ;
528            debug-message "prepending \""$(executable-dir)"\" to default library search path" ;
529
530            default-library-path = $(executable-dir) $(default-library-path) ;
531
532            default-include-path = $(:E=PC:R=$(executable-dir:D)) $(default-include-path) ;
533
534            debug-message "and \""$(default-include-path[1])"\" to default #include path" ;
535        }
536
537        libraries ?= $(default-library-path) ;
538        includes ?= $(default-include-path) ;
539    }
540    else
541    {
542        includes ?= $(prefix)/include/python$(version) ;
543
544        local lib = $(exec-prefix)/lib ;
545        libraries ?= $(lib)/python$(version)/config $(lib) ;
546    }
547}
548
549# The version of the python interpreter to use.
550feature.feature python : : propagated ;
551feature.feature python.interpreter : : free ;
552
553toolset.flags python.capture-output PYTHON : <python.interpreter> ;
554
555#
556# Support for Python configured --with-pydebug
557#
558feature.feature python-debugging : off on : propagated ;
559builtin.variant debug-python : debug : <python-debugging>on ;
560
561
562# Return a list of candidate commands to try when looking for a Python
563# interpreter. prefix is expected to be a native path.
564#
565local rule candidate-interpreters ( version ? : prefix ? : target-os )
566{
567    local bin-path = bin ;
568    if $(target-os) = windows
569    {
570        # On Windows, look in the root directory itself and, to work with the
571        # result of a build-from-source, the PCBuild directory.
572        bin-path = PCBuild8 PCBuild "" ;
573    }
574
575    bin-path = $(bin-path:R=$(prefix)) ;
576
577    if $(target-os) in windows darwin
578    {
579        return                                            # Search:
580            $(:E=python:R=$(bin-path))                    #   Relative to the prefix, if any
581            python                                        #   In the PATH
582            [ $(target-os)-installed-pythons $(version) ] #   Standard install locations
583        ;
584    }
585    else
586    {
587        # Search relative to the prefix, or if none supplied, in PATH.
588        local unversioned = $(:E=python:R=$(bin-path:E=)) ;
589
590        # If a version was specified, look for a python with that specific
591        # version appended before looking for one called, simply, "python"
592        return $(unversioned)$(version) $(unversioned) ;
593    }
594}
595
596
597# Compute system library dependencies for targets linking with static Python
598# libraries.
599#
600# On many systems, Python uses libraries such as pthreads or libdl. Since static
601# libraries carry no library dependency information of their own that the linker
602# can extract, these extra dependencies have to be given explicitly on the link
603# line of the client.  The information about these dependencies is packaged into
604# the "python" target below.
605#
606# Even where Python itself uses pthreads, it never allows extension modules to
607# be entered concurrently (unless they explicitly give up the interpreter lock).
608# Therefore, extension modules do not need the efficiency overhead of threadsafe
609# code as produced by <threading>multi, and we handle libpthread along with
610# other libraries here. Note: this optimization is based on an assumption that
611# the compiler generates link-compatible code in both the single- and
612# multi-threaded cases, and that system libraries do not change their ABIs
613# either.
614#
615# Returns a list of usage-requirements that link to the necessary system
616# libraries.
617#
618local rule system-library-dependencies ( target-os )
619{
620    switch $(target-os)
621    {
622        case s[uo][nl]* : # solaris, sun, sunos
623            # Add a librt dependency for the gcc toolset on SunOS (the sun
624            # toolset adds -lrt unconditionally). While this appears to
625            # duplicate the logic already in gcc.jam, it does not as long as
626            # we are not forcing <threading>multi.
627
628            # On solaris 10, distutils.sysconfig.get_config_var('LIBS') yields
629            # '-lresolv -lsocket -lnsl -lrt -ldl'. However, that does not seem
630            # to be the right list for extension modules. For example, on my
631            # installation, adding -ldl causes at least one test to fail because
632            # the library can not be found and removing it causes no failures.
633
634            # Apparently, though, we need to add -lrt for gcc.
635            return <toolset>gcc:<library>rt ;
636
637        case osf : return  <library>pthread <toolset>gcc:<library>rt ;
638
639        case qnx* : return ;
640        case darwin : return ;
641        case windows : return ;
642        case haiku : return ;
643
644        case hpux : return  <library>rt ;
645        case *bsd : return  <library>pthread <toolset>gcc:<library>util ;
646
647        case aix : return  <library>pthread <library>dl ;
648
649        case * : return  <library>pthread <library>dl
650            <toolset>gcc:<library>util <toolset-intel:platform>linux:<library>util ;
651    }
652}
653
654
655# Declare a target to represent Python's library.
656#
657local rule declare-libpython-target ( version ? : requirements * )
658{
659    # Compute the representation of Python version in the name of Python's
660    # library file.
661    local lib-version = $(version) ;
662    if <target-os>windows in $(requirements)
663    {
664        local major-minor = [ split-version $(version) ] ;
665        lib-version = $(major-minor:J="") ;
666        if <python-debugging>on in $(requirements)
667        {
668            lib-version = $(lib-version)_d ;
669        }
670    }
671
672    if ! $(lib-version)
673    {
674        ECHO *** warning: could not determine Python version, which will ;
675        ECHO *** warning: probably prevent us from linking with the python ;
676        ECHO *** warning: library.  Consider explicitly passing the version ;
677        ECHO *** warning: to 'using python'. ;
678    }
679
680    # Declare it.
681    lib python.lib : : <name>python$(lib-version) $(requirements) ;
682}
683
684
685# Implementation of init.
686local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? :
687    condition * : extension-suffix ? )
688{
689    local prefix ;
690    local exec-prefix ;
691    local cmds-to-try ;
692    local interpreter-cmd ;
693
694    local target-os = [ feature.get-values target-os : $(condition) ] ;
695    target-os ?= [ feature.defaults target-os ] ;
696    target-os = $(target-os:G=) ;
697
698    if $(target-os) = windows && <python-debugging>on in $(condition)
699    {
700        extension-suffix ?= _d ;
701    }
702    extension-suffix ?= "" ;
703
704    # Normalize and dissect any version number.
705    local major-minor ;
706    if $(version)
707    {
708        major-minor = [ split-version $(version) ] ;
709        version = $(major-minor:J=.) ;
710    }
711
712    local cmds-to-try ;
713
714    if ! $(cmd-or-prefix) || [ GLOB $(cmd-or-prefix) : * ]
715    {
716        # If the user did not pass a command, whatever we got was a prefix.
717        prefix = $(cmd-or-prefix) ;
718        cmds-to-try = [ candidate-interpreters $(version) : $(prefix) : $(target-os) ] ;
719    }
720    else
721    {
722        # Work with the command the user gave us.
723        cmds-to-try = $(cmd-or-prefix) ;
724
725        # On Windows, do not nail down the interpreter command just yet in case
726        # the user specified something that turns out to be a cygwin symlink,
727        # which could bring down bjam if we invoke it.
728        if $(target-os) != windows
729        {
730            interpreter-cmd = $(cmd-or-prefix) ;
731        }
732    }
733
734    # Values to use in case we can not really find anything in the system.
735    local fallback-cmd = $(cmds-to-try[1]) ;
736    local fallback-version ;
737
738    # Anything left to find or check?
739    if ! ( $(interpreter-cmd) && $(includes) && $(libraries) )
740    {
741        # Values to be extracted from python's sys module. These will be set by
742        # the probe rule, above, using Jam's dynamic scoping.
743        local sys-elements = version platform prefix exec_prefix executable ;
744        local sys.$(sys-elements) ;
745
746        # Compute the string Python's sys.platform needs to match. If not
747        # targeting Windows or cygwin we will assume only native builds can
748        # possibly run, so we will not require a match and we leave sys.platform
749        # blank.
750        local platform ;
751        switch $(target-os)
752        {
753            case windows : platform = win32 ;
754            case cygwin : platform = cygwin ;
755        }
756
757        while $(cmds-to-try)
758        {
759            # Pop top command.
760            local cmd = $(cmds-to-try[1]) ;
761            cmds-to-try = $(cmds-to-try[2-]) ;
762
763            debug-message Checking interpreter command \"$(cmd)\"... ;
764            if [ probe $(cmd) ]
765            {
766                fallback-version ?= $(sys.version) ;
767
768                # Check for version/platform validity.
769                for local x in version platform
770                {
771                    if $($(x)) && $($(x)) != $(sys.$(x))
772                    {
773                        debug-message ...$(x) "mismatch (looking for"
774                            $($(x)) but found $(sys.$(x))")" ;
775                        cmd = ;
776                    }
777                }
778
779                if $(cmd)
780                {
781                    debug-message ...requested configuration matched! ;
782
783                    exec-prefix = $(sys.exec_prefix) ;
784
785                    compute-default-paths $(target-os) : $(sys.version) :
786                        $(sys.prefix) : $(sys.exec_prefix) ;
787
788                    version = $(sys.version) ;
789                    interpreter-cmd ?= $(cmd) ;
790                    cmds-to-try = ;  # All done.
791                }
792            }
793            else
794            {
795                debug-message ...does not invoke a working interpreter ;
796            }
797        }
798    }
799
800    # Anything left to compute?
801    if $(includes) && $(libraries)
802    {
803        .configured = true ;
804    }
805    else
806    {
807        version ?= $(fallback-version) ;
808        version ?= 2.5 ;
809        exec-prefix ?= $(prefix) ;
810        compute-default-paths $(target-os) : $(version) : $(prefix:E=) ;
811    }
812
813    if ! $(interpreter-cmd)
814    {
815        fallback-cmd ?= python ;
816        debug-message No working Python interpreter found. ;
817        if [ os.name ] != NT || ! [ invokes-cygwin-symlink $(fallback-cmd) ]
818        {
819            interpreter-cmd = $(fallback-cmd) ;
820            debug-message falling back to \"$(interpreter-cmd)\" ;
821        }
822    }
823
824    includes = [ path-to-native $(includes) ] ;
825    libraries = [ path-to-native $(libraries) ] ;
826
827    debug-message "Details of this Python configuration:" ;
828    debug-message "  interpreter command:" \"$(interpreter-cmd:E=<empty>)\" ;
829    debug-message "  include path:" \"$(includes:E=<empty>)\" ;
830    debug-message "  library path:" \"$(libraries:E=<empty>)\" ;
831    if $(target-os) = windows
832    {
833        debug-message "  DLL search path:" \"$(exec-prefix:E=<empty>)\" ;
834    }
835
836    #
837    # End autoconfiguration sequence.
838    #
839    local target-requirements = $(condition) ;
840
841    # Add the version, if any, to the target requirements.
842    if $(version)
843    {
844        if ! $(version) in [ feature.values python ]
845        {
846            feature.extend python : $(version) ;
847        }
848        target-requirements += <python>$(version:E=default) ;
849    }
850
851    target-requirements += <target-os>$(target-os) ;
852
853    # See if we can find a framework directory on darwin.
854    local framework-directory ;
855    if $(target-os) = darwin
856    {
857        # Search upward for the framework directory.
858        local framework-directory = $(libraries[-1]) ;
859        while $(framework-directory:D=) && $(framework-directory:D=) != Python.framework
860        {
861            framework-directory = $(framework-directory:D) ;
862        }
863
864        if $(framework-directory:D=) = Python.framework
865        {
866            debug-message framework directory is \"$(framework-directory)\" ;
867        }
868        else
869        {
870            debug-message "no framework directory found; using library path" ;
871            framework-directory = ;
872        }
873    }
874
875    local dll-path = $(libraries) ;
876
877    # Make sure that we can find the Python DLL on Windows.
878    if ( $(target-os) = windows ) && $(exec-prefix)
879    {
880        dll-path += $(exec-prefix) ;
881    }
882
883    #
884    # Prepare usage requirements.
885    #
886    local usage-requirements = [ system-library-dependencies $(target-os) ] ;
887    usage-requirements += <include>$(includes) <python.interpreter>$(interpreter-cmd) ;
888    if <python-debugging>on in $(condition)
889    {
890        if $(target-os) = windows
891        {
892            # In pyconfig.h, Py_DEBUG is set if _DEBUG is set. If we define
893            # Py_DEBUG we will get multiple definition warnings.
894            usage-requirements += <define>_DEBUG ;
895        }
896        else
897        {
898            usage-requirements += <define>Py_DEBUG ;
899        }
900    }
901
902    # Global, but conditional, requirements to give access to the interpreter
903    # for general utilities, like other toolsets, that run Python scripts.
904    toolset.add-requirements
905        $(target-requirements:J=,):<python.interpreter>$(interpreter-cmd) ;
906
907    # Register the right suffix for extensions.
908    register-extension-suffix $(extension-suffix) : $(target-requirements) ;
909
910    #
911    # Declare the "python" target. This should really be called
912    # python_for_embedding.
913    #
914
915    if $(framework-directory)
916    {
917        alias python
918          :
919          : $(target-requirements)
920          :
921          : $(usage-requirements) <framework>$(framework-directory)
922          ;
923    }
924    else
925    {
926        declare-libpython-target $(version) : $(target-requirements) ;
927
928        # This is an evil hack.  On, Windows, when Python is embedded, nothing
929        # seems to set up sys.path to include Python's standard library
930        # (http://article.gmane.org/gmane.comp.python.general/544986). The evil
931        # here, aside from the workaround necessitated by Python's bug, is that:
932        #
933        # a. we're guessing the location of the python standard library from the
934        #    location of pythonXX.lib
935        #
936        # b. we're hijacking the <testing.launcher> property to get the
937        #    environment variable set up, and the user may want to use it for
938        #    something else (e.g. launch the debugger).
939        local set-PYTHONPATH ;
940        if $(target-os) = windows
941        {
942            set-PYTHONPATH = [ common.prepend-path-variable-command PYTHONPATH :
943                $(libraries:D)/Lib ] ;
944        }
945
946        alias python
947          :
948          : $(target-requirements)
949          :
950            # Why python.lib must be listed here instead of along with the
951            # system libs is a mystery, but if we do not do it, on cygwin,
952            # -lpythonX.Y never appears in the command line (although it does on
953            # linux).
954          : $(usage-requirements)
955            <testing.launcher>$(set-PYTHONPATH)
956              <library-path>$(libraries) <dll-path>$(dll-path) <library>python.lib
957          ;
958    }
959
960    # On *nix, we do not want to link either Boost.Python or Python extensions
961    # to libpython, because the Python interpreter itself provides all those
962    # symbols. If we linked to libpython, we would get duplicate symbols. So
963    # declare two targets -- one for building extensions and another for
964    # embedding.
965    if $(target-os) in windows cygwin
966    {
967        alias python_for_extensions : python : $(target-requirements) ;
968    }
969    else if $(target-os) = darwin {
970        alias python_for_extensions
971            :
972            : $(target-requirements)
973            :
974            : $(usage-requirements) <linkflags>"-undefined dynamic_lookup"
975            ;
976    }
977    # On AIX we need Python extensions and Boost.Python to import symbols from
978    # the Python interpreter. Dynamic libraries opened with dlopen() do not
979    # inherit the symbols from the Python interpreter.
980    else if $(target-os) = aix
981    {
982        alias python_for_extensions
983            :
984            : $(target-requirements)
985            :
986            : $(usage-requirements) <linkflags>-Wl,-bI:$(libraries[1])/python.exp
987            ;
988    }
989    else
990    {
991        alias python_for_extensions
992            :
993            : $(target-requirements)
994            :
995            : $(usage-requirements)
996            ;
997    }
998}
999
1000
1001rule configured ( )
1002{
1003     return $(.configured) ;
1004}
1005
1006
1007type.register PYTHON_EXTENSION : : SHARED_LIB ;
1008
1009
1010local rule register-extension-suffix ( root : condition * )
1011{
1012    local suffix ;
1013
1014    switch [ feature.get-values target-os : $(condition) ]
1015    {
1016        case windows : suffix = pyd ;
1017        case cygwin : suffix = dll ;
1018        case hpux :
1019        {
1020            if [ feature.get-values python : $(condition) ] in 1.5 1.6 2.0 2.1 2.2 2.3 2.4
1021            {
1022                suffix = sl ;
1023            }
1024            else
1025            {
1026                suffix = so ;
1027            }
1028        }
1029        case * : suffix = so ;
1030    }
1031
1032    type.set-generated-target-suffix PYTHON_EXTENSION : $(condition) : <$(root).$(suffix)> ;
1033}
1034
1035
1036# Unset 'lib' prefix for PYTHON_EXTENSION
1037type.set-generated-target-prefix PYTHON_EXTENSION : : "" ;
1038
1039
1040rule python-extension ( name : sources * : requirements * : default-build * :
1041                        usage-requirements * )
1042{
1043    if [ configured ]
1044    {
1045        requirements += <use>/python//python_for_extensions ;
1046    }
1047    requirements += <suppress-import-lib>true ;
1048
1049    local project = [ project.current ] ;
1050
1051    targets.main-target-alternative
1052        [ new typed-target $(name) : $(project) : PYTHON_EXTENSION
1053            : [ targets.main-target-sources $(sources) : $(name) ]
1054            : [ targets.main-target-requirements $(requirements) : $(project) ]
1055            : [ targets.main-target-default-build $(default-build) : $(project) ]
1056        ] ;
1057}
1058
1059IMPORT python : python-extension : : python-extension ;
1060
1061rule py2to3
1062{
1063    common.copy $(<) : $(>) ;
1064    2to3 $(<) ;
1065}
1066
1067actions 2to3
1068{
1069    2to3 -wn --no-diffs "$(<)"
1070    2to3 -dwn --no-diffs "$(<)"
1071}
1072
1073
1074# Support for testing.
1075type.register PY : py ;
1076type.register RUN_PYD_OUTPUT ;
1077type.register RUN_PYD : : TEST ;
1078
1079
1080class python-test-generator : generator
1081{
1082    import set ;
1083
1084    rule __init__ ( * : * )
1085    {
1086        generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
1087        self.composing = true ;
1088    }
1089
1090    rule run ( project name ? : property-set : sources * : multiple ? )
1091    {
1092        local pyversion = [ $(property-set).get <python> ] ;
1093        local python ;
1094        local other-pythons ;
1095
1096        # Make new target that converting Python source by 2to3 when running with Python 3.
1097        local rule make-2to3-source ( source )
1098        {
1099            if $(pyversion) >= 3.0
1100            {
1101                local a = [ new action $(source) : python.py2to3 : $(property-set) ] ;
1102                local t =  [ utility.basename [ $(s).name ] ] ;
1103                local p = [ new file-target $(t) : PY : $(project) : $(a) ] ;
1104                return $(p) ;
1105            }
1106            else
1107            {
1108                return $(source) ;
1109            }
1110        }
1111
1112        for local s in $(sources)
1113        {
1114            if [ $(s).type ] = PY
1115            {
1116                if ! $(python)
1117                {
1118                    # First Python source ends up on command line.
1119                    python = [ make-2to3-source $(s) ] ;
1120
1121                }
1122                else
1123                {
1124                    # Other Python sources become dependencies.
1125                    other-pythons += [ make-2to3-source $(s) ] ;
1126                }
1127            }
1128        }
1129
1130        local extensions ;
1131        for local s in $(sources)
1132        {
1133            if [ $(s).type ] = PYTHON_EXTENSION
1134            {
1135                extensions += $(s) ;
1136            }
1137        }
1138
1139        local libs ;
1140        for local s in $(sources)
1141        {
1142            if [ type.is-derived [ $(s).type ] LIB ]
1143              && ! $(s) in $(extensions)
1144            {
1145                libs += $(s) ;
1146            }
1147        }
1148
1149        local new-sources ;
1150        for local s in $(sources)
1151        {
1152            if [ type.is-derived [ $(s).type ] CPP ]
1153            {
1154                local name = [ utility.basename [ $(s).name ] ] ;
1155                if $(name) = [ utility.basename [ $(python).name ] ]
1156                {
1157                    name = $(name)_ext ;
1158                }
1159                local extension = [ generators.construct $(project) $(name) :
1160                  PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ;
1161
1162                # The important part of usage requirements returned from
1163                # PYTHON_EXTENSION generator are xdll-path properties that will
1164                # allow us to find the python extension at runtime.
1165                property-set = [ $(property-set).add $(extension[1]) ] ;
1166
1167                # Ignore usage requirements. We're a top-level generator and
1168                # nobody is going to use what we generate.
1169                new-sources += $(extension[2-]) ;
1170            }
1171        }
1172
1173        property-set = [ $(property-set).add-raw <dependency>$(other-pythons) ] ;
1174
1175        return [ construct-result $(python) $(extensions) $(new-sources) :
1176            $(project) $(name) : $(property-set) ] ;
1177    }
1178}
1179
1180
1181generators.register
1182  [ new python-test-generator python.capture-output : : RUN_PYD_OUTPUT ] ;
1183
1184generators.register-standard testing.expect-success
1185  : RUN_PYD_OUTPUT : RUN_PYD ;
1186
1187
1188# There are two different ways of spelling OS names. One is used for [ os.name ]
1189# and the other is used for the <host-os> and <target-os> properties. Until that
1190# is remedied, this sets up a crude mapping from the latter to the former, that
1191# will work *for the purposes of cygwin/NT cross-builds only*. Could not think
1192# of a better name than "translate".
1193#
1194.translate-os-windows = NT ;
1195.translate-os-cygwin = CYGWIN ;
1196local rule translate-os ( src-os )
1197{
1198    local x = $(.translate-os-$(src-os)) [ os.name ] ;
1199    return $(x[1]) ;
1200}
1201
1202
1203# Extract the path to a single ".pyd" source. This is used to build the
1204# PYTHONPATH for running bpl tests.
1205#
1206local rule pyd-pythonpath ( source )
1207{
1208    return [ on $(source) return $(LOCATE) $(SEARCH) ] ;
1209}
1210
1211
1212# The flag settings on testing.capture-output do not apply to python.capture
1213# output at the moment. Redo this explicitly.
1214toolset.flags python.capture-output ARGS <testing.arg> ;
1215
1216
1217rule capture-output ( target : sources * : properties * )
1218{
1219    # Setup up a proper DLL search path. Here, $(sources[1]) is a python module
1220    # and $(sources[2]) is a DLL. Only $(sources[1]) is passed to
1221    # testing.capture-output, so RUN_PATH variable on $(sources[2]) is not
1222    # consulted. Move it over explicitly.
1223    RUN_PATH on $(sources[1]) = [ on $(sources[2-]) return $(RUN_PATH) ] ;
1224
1225    PYTHONPATH  = [ sequence.transform pyd-pythonpath : $(sources[2-]) ] ;
1226    PYTHONPATH += [ feature.get-values pythonpath : $(properties) ] ;
1227
1228    # After test is run, we remove the Python module, but not the Python script.
1229    testing.capture-output $(target) : $(sources[1]) : $(properties) :
1230        $(sources[2-]) ;
1231
1232    # PYTHONPATH is different; it will be interpreted by whichever Python is
1233    # invoked and so must follow path rules for the target os. The only OSes
1234    # where we can run python for other OSes currently are NT and CYGWIN so we
1235    # only need to handle those cases.
1236    local target-os = [ feature.get-values target-os : $(properties) ] ;
1237    # Oddly, host-os is not in properties, so grab the default value.
1238    local host-os = [ feature.defaults host-os ] ;
1239    host-os = $(host-os:G=) ;
1240    if $(target-os) != $(host-os) && $(target-os) in windows cygwin && $(host-os) in windows cygwin
1241    {
1242        PYTHONPATH = [ sequence.transform $(host-os)-to-$(target-os)-path :
1243            $(PYTHONPATH) ] ;
1244    }
1245    local path-separator = [ os.path-separator [ translate-os $(target-os) ] ] ;
1246    local set-PYTHONPATH = [ common.variable-setting-command PYTHONPATH :
1247        $(PYTHONPATH:J=$(path-separator)) ] ;
1248    LAUNCHER on $(target) = $(set-PYTHONPATH) [ on $(target) return \"$(PYTHON)\" ] ;
1249}
1250
1251
1252rule bpl-test ( name : sources * : requirements * )
1253{
1254    local s ;
1255    sources ?= $(name).py $(name).cpp ;
1256    return [ testing.make-test run-pyd : $(sources) /boost/python//boost_python
1257        : $(requirements) : $(name) ] ;
1258}
1259
1260
1261IMPORT $(__name__) : bpl-test : : bpl-test ;
1262