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