]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/build/src/tools/python.jam
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / boost / tools / build / src / tools / python.jam
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
18 import type ;
19 import testing ;
20 import generators ;
21 import project ;
22 import errors ;
23 import targets ;
24 import "class" : new ;
25 import os ;
26 import common ;
27 import toolset ;
28 import regex ;
29 import numbers ;
30 import string ;
31 import property ;
32 import sequence ;
33 import path ;
34 import feature ;
35 import set ;
36 import builtin ;
37
38
39 # Make this module a project.
40 project.initialize $(__name__) ;
41 project 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.
48 lib dl ;
49 # This contains 'openpty' function need by python. Again, on some system need to
50 # pass this to linker explicitly.
51 lib util ;
52 # Python uses pthread symbols.
53 lib pthread ;
54 # Extra library needed by phtread on some platforms.
55 lib 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.
61 feature.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 #
96 rule 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 #
118 local 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.
142 local 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 #
184 local 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 #
204 local 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
222 local 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 #
236 local 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
262 local 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 #
278 local 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 #
321 local 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 #
333 local 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 #
349 local rule guess-windows-path ( path )
350 {
351 return [ SUBST $(path) ($(.windows-drive-letter-re)|.*([\\]).*) $1 ] ;
352 }
353
354
355 local 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 #
376 local 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 = ;
396 for local v in [ numbers.range 15 34 ]
397 {
398 .version-countdown = [ SUBST $(v) (.)(.*) $1.$2 ] $(.version-countdown) ;
399 }
400
401
402 local 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
424 local 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 #
440 local 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 #
504 local 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.
550 feature.feature python : : propagated ;
551 feature.feature python.interpreter : : free ;
552
553 toolset.flags python.capture-output PYTHON : <python.interpreter> ;
554
555 #
556 # Support for Python configured --with-pydebug
557 #
558 feature.feature python-debugging : off on : propagated ;
559 builtin.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 #
565 local 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 #
618 local 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 #
657 local 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.
686 local 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) && $(version) && $(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 # Check whether configuration succeeded.
801 if ! ( $(includes) && $(libraries) )
802 {
803 debug-message Python headers and libraries not found. ;
804 return ;
805 }
806
807 .configured = true ;
808
809 if ! $(interpreter-cmd)
810 {
811 fallback-cmd ?= python ;
812 debug-message No working Python interpreter found. ;
813 if [ os.name ] != NT || ! [ invokes-cygwin-symlink $(fallback-cmd) ]
814 {
815 interpreter-cmd = $(fallback-cmd) ;
816 debug-message falling back to \"$(interpreter-cmd)\" ;
817 }
818 }
819
820 includes = [ path-to-native $(includes) ] ;
821 libraries = [ path-to-native $(libraries) ] ;
822
823 debug-message "Details of this Python configuration:" ;
824 debug-message " interpreter command:" \"$(interpreter-cmd:E=<empty>)\" ;
825 debug-message " include path:" \"$(includes:E=<empty>)\" ;
826 debug-message " library path:" \"$(libraries:E=<empty>)\" ;
827 if $(target-os) = windows
828 {
829 debug-message " DLL search path:" \"$(exec-prefix:E=<empty>)\" ;
830 }
831
832 #
833 # Discover the presence of NumPy
834 #
835 debug-message "Checking for NumPy..." ;
836 local full-cmd = "import sys; sys.stderr = sys.stdout; import numpy; print(numpy.get_include())" ;
837 local full-cmd = $(interpreter-cmd)" -c \"$(full-cmd)\"" ;
838 debug-message "running command '$(full-cmd)'" ;
839 local result = [ SHELL $(full-cmd) : strip-eol : exit-status ] ;
840 if $(result[2]) = 0
841 {
842 .numpy = true ;
843 .numpy-include = $(result[1]) ;
844 debug-message "NumPy enabled" ;
845 }
846 else
847 {
848 debug-message "NumPy disabled. Reason:" ;
849 debug-message " $(full-cmd) aborted with " ;
850 debug-message " $(result[1])" ;
851 }
852
853 #
854 # End autoconfiguration sequence.
855 #
856 local target-requirements = $(condition) ;
857
858 # Add the version, if any, to the target requirements.
859 if $(version)
860 {
861 if ! $(version) in [ feature.values python ]
862 {
863 feature.extend python : $(version) ;
864 }
865 target-requirements += <python>$(version:E=default) ;
866 }
867
868 target-requirements += <target-os>$(target-os) ;
869
870 # See if we can find a framework directory on darwin.
871 local framework-directory ;
872 if $(target-os) = darwin
873 {
874 # Search upward for the framework directory.
875 local framework-directory = $(libraries[-1]) ;
876 while $(framework-directory:D=) && $(framework-directory:D=) != Python.framework
877 {
878 framework-directory = $(framework-directory:D) ;
879 }
880
881 if $(framework-directory:D=) = Python.framework
882 {
883 debug-message framework directory is \"$(framework-directory)\" ;
884 }
885 else
886 {
887 debug-message "no framework directory found; using library path" ;
888 framework-directory = ;
889 }
890 }
891
892 local dll-path = $(libraries) ;
893
894 # Make sure that we can find the Python DLL on Windows.
895 if ( $(target-os) = windows ) && $(exec-prefix)
896 {
897 dll-path += $(exec-prefix) ;
898 }
899
900 #
901 # Prepare usage requirements.
902 #
903 local usage-requirements = [ system-library-dependencies $(target-os) ] ;
904 usage-requirements += <include>$(includes) <python.interpreter>$(interpreter-cmd) ;
905 if <python-debugging>on in $(condition)
906 {
907 if $(target-os) = windows
908 {
909 # In pyconfig.h, Py_DEBUG is set if _DEBUG is set. If we define
910 # Py_DEBUG we will get multiple definition warnings.
911 usage-requirements += <define>_DEBUG ;
912 }
913 else
914 {
915 usage-requirements += <define>Py_DEBUG ;
916 }
917 }
918
919 # Global, but conditional, requirements to give access to the interpreter
920 # for general utilities, like other toolsets, that run Python scripts.
921 toolset.add-requirements
922 $(target-requirements:J=,):<python.interpreter>$(interpreter-cmd) ;
923
924 # We also set a default requirement that assigns the first python configured
925 # for a particular target OS as the default. This makes it so that we can
926 # select a python interpreter with only knowledge of the target OS. And hence
927 # can configure different Pythons based on the target OS only.
928 local toolset-requirements = [ toolset.requirements ] ;
929 local toolset-target-os-requirements
930 = [ property.evaluate-conditionals-in-context
931 [ $(toolset-requirements).raw ] : <target-os>$(target-os) ] ;
932 if ! <python> in $(toolset-target-os-requirements:G)
933 {
934 toolset.add-requirements <target-os>$(target-os):<python>$(version:E=default) ;
935 }
936
937 # We also set a default requirement that assigns the first python configured
938 # for a particular target OS as the default. This makes it so that we can
939 # select a python interpreter with only knowledge of the target OS. And hence
940 # can configure different Pythons based on the target OS only.
941 local toolset-requirements = [ toolset.requirements ] ;
942 local toolset-target-os-requirements
943 = [ property.evaluate-conditionals-in-context
944 [ $(toolset-requirements).raw ] : <target-os>$(target-os) ] ;
945 if ! <python> in $(toolset-target-os-requirements:G)
946 {
947 toolset.add-requirements <target-os>$(target-os):<python>$(version:E=default) ;
948 }
949
950 # Register the right suffix for extensions.
951 register-extension-suffix $(extension-suffix) : $(target-requirements) ;
952
953 #
954 # Declare the "python" target. This should really be called
955 # python_for_embedding.
956 #
957
958 if $(framework-directory)
959 {
960 alias python
961 :
962 : $(target-requirements)
963 :
964 : $(usage-requirements) <framework>$(framework-directory)
965 ;
966 }
967 else
968 {
969 declare-libpython-target $(version) : $(target-requirements) ;
970
971 # This is an evil hack. On, Windows, when Python is embedded, nothing
972 # seems to set up sys.path to include Python's standard library
973 # (http://article.gmane.org/gmane.comp.python.general/544986). The evil
974 # here, aside from the workaround necessitated by Python's bug, is that:
975 #
976 # a. we're guessing the location of the python standard library from the
977 # location of pythonXX.lib
978 #
979 # b. we're hijacking the <testing.launcher> property to get the
980 # environment variable set up, and the user may want to use it for
981 # something else (e.g. launch the debugger).
982 local set-PYTHONPATH ;
983 if $(target-os) = windows
984 {
985 set-PYTHONPATH = [ common.prepend-path-variable-command PYTHONPATH :
986 $(libraries:D)/Lib ] ;
987 }
988
989 alias python
990 :
991 : $(target-requirements)
992 :
993 # Why python.lib must be listed here instead of along with the
994 # system libs is a mystery, but if we do not do it, on cygwin,
995 # -lpythonX.Y never appears in the command line (although it does on
996 # linux).
997 : $(usage-requirements)
998 <testing.launcher>$(set-PYTHONPATH)
999 <library-path>$(libraries) <dll-path>$(dll-path) <library>python.lib
1000 ;
1001 }
1002
1003 # On *nix, we do not want to link either Boost.Python or Python extensions
1004 # to libpython, because the Python interpreter itself provides all those
1005 # symbols. If we linked to libpython, we would get duplicate symbols. So
1006 # declare two targets -- one for building extensions and another for
1007 # embedding.
1008 if $(target-os) in windows cygwin
1009 {
1010 alias python_for_extensions : python : $(target-requirements) ;
1011 }
1012 else if $(target-os) = darwin {
1013 alias python_for_extensions
1014 :
1015 : $(target-requirements)
1016 :
1017 : $(usage-requirements) <linkflags>"-undefined dynamic_lookup"
1018 ;
1019 }
1020 # On AIX we need Python extensions and Boost.Python to import symbols from
1021 # the Python interpreter. Dynamic libraries opened with dlopen() do not
1022 # inherit the symbols from the Python interpreter.
1023 else if $(target-os) = aix
1024 {
1025 alias python_for_extensions
1026 :
1027 : $(target-requirements)
1028 :
1029 : $(usage-requirements) <linkflags>-Wl,-bI:$(libraries[1])/python.exp
1030 ;
1031 }
1032 else
1033 {
1034 alias python_for_extensions
1035 :
1036 : $(target-requirements)
1037 :
1038 : $(usage-requirements)
1039 ;
1040 }
1041 }
1042
1043
1044 rule configured ( )
1045 {
1046 return $(.configured) ;
1047 }
1048
1049 rule numpy ( )
1050 {
1051 return $(.numpy) ;
1052 }
1053
1054 rule numpy-include ( )
1055 {
1056 return $(.numpy-include) ;
1057 }
1058
1059
1060 type.register PYTHON_EXTENSION : : SHARED_LIB ;
1061
1062
1063 local rule register-extension-suffix ( root : condition * )
1064 {
1065 local suffix ;
1066
1067 switch [ feature.get-values target-os : $(condition) ]
1068 {
1069 case windows : suffix = pyd ;
1070 case cygwin : suffix = dll ;
1071 case hpux :
1072 {
1073 if [ feature.get-values python : $(condition) ] in 1.5 1.6 2.0 2.1 2.2 2.3 2.4
1074 {
1075 suffix = sl ;
1076 }
1077 else
1078 {
1079 suffix = so ;
1080 }
1081 }
1082 case * : suffix = so ;
1083 }
1084
1085 type.set-generated-target-suffix PYTHON_EXTENSION : $(condition) : <$(root).$(suffix)> ;
1086 }
1087
1088
1089 # Unset 'lib' prefix for PYTHON_EXTENSION
1090 type.set-generated-target-prefix PYTHON_EXTENSION : : "" ;
1091
1092
1093 rule python-extension ( name : sources * : requirements * : default-build * :
1094 usage-requirements * )
1095 {
1096 if [ configured ]
1097 {
1098 requirements += <use>/python//python_for_extensions ;
1099 }
1100 requirements += <suppress-import-lib>true ;
1101
1102 local project = [ project.current ] ;
1103
1104 targets.main-target-alternative
1105 [ new typed-target $(name) : $(project) : PYTHON_EXTENSION
1106 : [ targets.main-target-sources $(sources) : $(name) ]
1107 : [ targets.main-target-requirements $(requirements) : $(project) ]
1108 : [ targets.main-target-default-build $(default-build) : $(project) ]
1109 ] ;
1110 }
1111
1112 IMPORT python : python-extension : : python-extension ;
1113
1114 # Support for testing.
1115 type.register PY : py ;
1116 type.register RUN_PYD_OUTPUT ;
1117 type.register RUN_PYD : : TEST ;
1118
1119
1120 class python-test-generator : generator
1121 {
1122 import set ;
1123
1124 rule __init__ ( * : * )
1125 {
1126 generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
1127 self.composing = true ;
1128 }
1129
1130 rule run ( project name ? : property-set : sources * : multiple ? )
1131 {
1132 local pyversion = [ $(property-set).get <python> ] ;
1133 local python ;
1134 local other-pythons ;
1135
1136 for local s in $(sources)
1137 {
1138 if [ $(s).type ] = PY
1139 {
1140 if ! $(python)
1141 {
1142 # First Python source ends up on command line.
1143 python = $(s) ;
1144
1145 }
1146 else
1147 {
1148 # Other Python sources become dependencies.
1149 other-pythons += $(s) ;
1150 }
1151 }
1152 }
1153
1154 local extensions ;
1155 for local s in $(sources)
1156 {
1157 if [ $(s).type ] = PYTHON_EXTENSION
1158 {
1159 extensions += $(s) ;
1160 }
1161 }
1162
1163 local libs ;
1164 for local s in $(sources)
1165 {
1166 if [ type.is-derived [ $(s).type ] LIB ]
1167 && ! $(s) in $(extensions)
1168 {
1169 libs += $(s) ;
1170 }
1171 }
1172
1173 local new-sources ;
1174 for local s in $(sources)
1175 {
1176 if [ type.is-derived [ $(s).type ] CPP ]
1177 {
1178 local name = [ utility.basename [ $(s).name ] ] ;
1179 if $(name) = [ utility.basename [ $(python).name ] ]
1180 {
1181 name = $(name)_ext ;
1182 }
1183 local extension = [ generators.construct $(project) $(name) :
1184 PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ;
1185
1186 # The important part of usage requirements returned from
1187 # PYTHON_EXTENSION generator are xdll-path properties that will
1188 # allow us to find the python extension at runtime.
1189 property-set = [ $(property-set).add $(extension[1]) ] ;
1190
1191 # Ignore usage requirements. We're a top-level generator and
1192 # nobody is going to use what we generate.
1193 new-sources += $(extension[2-]) ;
1194 }
1195 }
1196
1197 property-set = [ $(property-set).add-raw <dependency>$(other-pythons) ] ;
1198
1199 return [ construct-result $(python) $(extensions) $(new-sources) :
1200 $(project) $(name) : $(property-set) ] ;
1201 }
1202 }
1203
1204
1205 generators.register
1206 [ new python-test-generator python.capture-output : : RUN_PYD_OUTPUT ] ;
1207
1208 generators.register-standard testing.expect-success
1209 : RUN_PYD_OUTPUT : RUN_PYD ;
1210
1211
1212 # There are two different ways of spelling OS names. One is used for [ os.name ]
1213 # and the other is used for the <host-os> and <target-os> properties. Until that
1214 # is remedied, this sets up a crude mapping from the latter to the former, that
1215 # will work *for the purposes of cygwin/NT cross-builds only*. Could not think
1216 # of a better name than "translate".
1217 #
1218 .translate-os-windows = NT ;
1219 .translate-os-cygwin = CYGWIN ;
1220 local rule translate-os ( src-os )
1221 {
1222 local x = $(.translate-os-$(src-os)) [ os.name ] ;
1223 return $(x[1]) ;
1224 }
1225
1226
1227 # Extract the path to a single ".pyd" source. This is used to build the
1228 # PYTHONPATH for running bpl tests.
1229 #
1230 local rule pyd-pythonpath ( source )
1231 {
1232 return [ on $(source) return $(LOCATE) $(SEARCH) ] ;
1233 }
1234
1235
1236 # The flag settings on testing.capture-output do not apply to python.capture
1237 # output at the moment. Redo this explicitly.
1238 toolset.flags python.capture-output ARGS <testing.arg> ;
1239 toolset.flags python.capture-output INPUT_FILES <testing.input-file> ;
1240
1241 rule capture-output ( target : sources * : properties * )
1242 {
1243 # Setup up a proper DLL search path. Here, $(sources[1]) is a python module
1244 # and $(sources[2]) is a DLL. Only $(sources[1]) is passed to
1245 # testing.capture-output, so RUN_PATH variable on $(sources[2]) is not
1246 # consulted. Move it over explicitly.
1247 RUN_PATH on $(sources[1]) = [ on $(sources[2-]) return $(RUN_PATH) ] ;
1248
1249 PYTHONPATH = [ sequence.transform pyd-pythonpath : $(sources[2-]) ] ;
1250 PYTHONPATH += [ feature.get-values pythonpath : $(properties) ] ;
1251
1252 # After test is run, we remove the Python module, but not the Python script.
1253 local targets-to-remove = $(sources[2-]) ;
1254 targets-to-remove ?= none ;
1255 testing.capture-output $(target) : $(sources[1]) : $(properties) :
1256 $(targets-to-remove) ;
1257
1258 # PYTHONPATH is different; it will be interpreted by whichever Python is
1259 # invoked and so must follow path rules for the target os. The only OSes
1260 # where we can run python for other OSes currently are NT and CYGWIN so we
1261 # only need to handle those cases.
1262 local target-os = [ feature.get-values target-os : $(properties) ] ;
1263 # Oddly, host-os is not in properties, so grab the default value.
1264 local host-os = [ feature.defaults host-os ] ;
1265 host-os = $(host-os:G=) ;
1266 if $(target-os) != $(host-os) && $(target-os) in windows cygwin && $(host-os) in windows cygwin
1267 {
1268 PYTHONPATH = [ sequence.transform $(host-os)-to-$(target-os)-path :
1269 $(PYTHONPATH) ] ;
1270 }
1271 local path-separator = [ os.path-separator [ translate-os $(target-os) ] ] ;
1272 local set-PYTHONPATH = [ common.variable-setting-command PYTHONPATH :
1273 $(PYTHONPATH:J=$(path-separator)) ] ;
1274 LAUNCHER on $(target) = $(set-PYTHONPATH) [ on $(target) return \"$(PYTHON)\" ] ;
1275 }
1276
1277
1278 rule bpl-test ( name : sources * : requirements * )
1279 {
1280 local s ;
1281 sources ?= $(name).py $(name).cpp ;
1282 return [ testing.make-test run-pyd : $(sources) /boost/python//boost_python
1283 : $(requirements) : $(name) ] ;
1284 }
1285
1286 # The same as bpl-test but additionally require (and link to) boost_numpy.
1287 # Masked whenever NumPy is not enabled.
1288 rule numpy-test ( name : sources * : requirements * )
1289 {
1290 numpy-include = [ python.numpy-include ] ;
1291 # yuk !
1292 if ! $(.numpy) { requirements += <build>no ; }
1293 sources ?= $(name).py $(name).cpp ;
1294 name = [ regex.replace $(name) "[/]" "~" ] ;
1295 return [ testing.make-test run-pyd
1296 : $(sources) /boost/python//boost_numpy /boost/python//boost_python
1297 : $(requirements) <include>$(numpy-include)
1298 : $(name) ] ;
1299 }
1300
1301 IMPORT $(__name__) : bpl-test : : bpl-test ;
1302 IMPORT $(__name__) : numpy-test : : numpy-test ;