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