mirror of
https://github.com/moses-smt/mosesdecoder.git
synced 2025-01-05 02:22:21 +03:00
1268 lines
40 KiB
Plaintext
1268 lines
40 KiB
Plaintext
# Copyright 2004 Vladimir Prus.
|
|
# Distributed under the Boost Software License, Version 1.0. (See
|
|
# accompanying file LICENSE_1_0.txt or copy at
|
|
# http://www.boost.org/LICENSE_1_0.txt)
|
|
|
|
# Support for Python and the the Boost.Python library.
|
|
#
|
|
# This module defines
|
|
#
|
|
# - a project 'python' with a target 'python' in it, that corresponds to the
|
|
# python library
|
|
#
|
|
# - a main target rule 'python-extension' which can be used to build a python
|
|
# extension.
|
|
#
|
|
# Extensions that use Boost.Python must explicitly link to it.
|
|
|
|
import type ;
|
|
import testing ;
|
|
import generators ;
|
|
import project ;
|
|
import errors ;
|
|
import targets ;
|
|
import "class" : new ;
|
|
import os ;
|
|
import common ;
|
|
import toolset ;
|
|
import regex ;
|
|
import numbers ;
|
|
import string ;
|
|
import property ;
|
|
import sequence ;
|
|
import path ;
|
|
import feature ;
|
|
import set ;
|
|
import builtin ;
|
|
import version ;
|
|
|
|
|
|
# Make this module a project.
|
|
project.initialize $(__name__) ;
|
|
project python ;
|
|
|
|
# Save the project so that if 'init' is called several times we define new
|
|
# targets in the python project, not in whatever project we were called by.
|
|
.project = [ project.current ] ;
|
|
|
|
# Dynamic linker lib. Necessary to specify it explicitly on some platforms.
|
|
lib dl ;
|
|
# This contains 'openpty' function need by python. Again, on some system need to
|
|
# pass this to linker explicitly.
|
|
lib util ;
|
|
# Python uses pthread symbols.
|
|
lib pthread ;
|
|
# Extra library needed by phtread on some platforms.
|
|
lib rt ;
|
|
|
|
# The pythonpath feature specifies additional elements for the PYTHONPATH
|
|
# environment variable, set by run-pyd. For example, pythonpath can be used to
|
|
# access Python modules that are part of the product being built, but are not
|
|
# installed in the development system's default paths.
|
|
feature.feature pythonpath : : free optional path ;
|
|
|
|
# Initializes the Python toolset. Note that all parameters are optional.
|
|
#
|
|
# - version -- the version of Python to use. Should be in Major.Minor format,
|
|
# for example 2.3. Do not include the subminor version.
|
|
#
|
|
# - cmd-or-prefix: Preferably, a command that invokes a Python interpreter.
|
|
# Alternatively, the installation prefix for Python libraries and includes. If
|
|
# empty, will be guessed from the version, the platform's installation
|
|
# patterns, and the python executables that can be found in PATH.
|
|
#
|
|
# - includes: the include path to Python headers. If empty, will be guessed.
|
|
#
|
|
# - libraries: the path to Python library binaries. If empty, will be guessed.
|
|
# On MacOS/Darwin, you can also pass the path of the Python framework.
|
|
#
|
|
# - condition: if specified, should be a set of properties that are matched
|
|
# against the build configuration when Boost.Build selects a Python
|
|
# configuration to use.
|
|
#
|
|
# - extension-suffix: A string to append to the name of extension modules before
|
|
# the true filename extension. Ordinarily we would just compute this based on
|
|
# the value of the <python-debugging> feature. However ubuntu's python-dbg
|
|
# package uses the windows convention of appending _d to debug-build extension
|
|
# modules. We have no way of detecting ubuntu, or of probing python for the
|
|
# "_d" requirement, and if you configure and build python using
|
|
# --with-pydebug, you'll be using the standard *nix convention. Defaults to ""
|
|
# (or "_d" when targeting windows and <python-debugging> is set).
|
|
#
|
|
# Example usage:
|
|
#
|
|
# using python : 2.3 ;
|
|
# using python : 2.3 : /usr/local/bin/python ;
|
|
#
|
|
rule init ( version ? : cmd-or-prefix ? : includes * : libraries ?
|
|
: condition * : extension-suffix ? )
|
|
{
|
|
project.push-current $(.project) ;
|
|
|
|
debug-message Configuring python... ;
|
|
for local v in version cmd-or-prefix includes libraries condition
|
|
{
|
|
if $($(v))
|
|
{
|
|
debug-message " user-specified "$(v): \"$($(v))\" ;
|
|
}
|
|
}
|
|
|
|
configure $(version) : $(cmd-or-prefix) : $(includes) : $(libraries) : $(condition) : $(extension-suffix) ;
|
|
|
|
project.pop-current ;
|
|
}
|
|
|
|
# A simpler version of SHELL that grabs stderr as well as stdout, but returns
|
|
# nothing if there was an error.
|
|
#
|
|
local rule shell-cmd ( cmd )
|
|
{
|
|
debug-message running command '$(cmd)" 2>&1"' ;
|
|
x = [ SHELL $(cmd)" 2>&1" : exit-status ] ;
|
|
if $(x[2]) = 0
|
|
{
|
|
return $(x[1]) ;
|
|
}
|
|
else
|
|
{
|
|
return ;
|
|
}
|
|
}
|
|
|
|
|
|
# Try to identify Cygwin symlinks. Invoking such a file directly as an NT
|
|
# executable from a native Windows build of bjam would be fatal to the bjam
|
|
# process. One /can/ invoke them through sh.exe or bash.exe, if you can prove
|
|
# that those are not also symlinks. ;-)
|
|
#
|
|
# If a symlink is found returns non-empty; we try to extract the target of the
|
|
# symlink from the file and return that.
|
|
#
|
|
# Note: 1. only works on NT 2. path is a native path.
|
|
local rule is-cygwin-symlink ( path )
|
|
{
|
|
local is-symlink = ;
|
|
|
|
# Look for a file with the given path having the S attribute set, as cygwin
|
|
# symlinks do. /-C means "do not use thousands separators in file sizes."
|
|
local dir-listing = [ shell-cmd "DIR /-C /A:S \""$(path)"\"" ] ;
|
|
|
|
if $(dir-listing)
|
|
{
|
|
# Escape any special regex characters in the base part of the path.
|
|
local base-pat = [ regex.escape $(path:D=) : ].[()*+?|\\$^ : \\ ] ;
|
|
|
|
# Extract the file's size from the directory listing.
|
|
local size-of-system-file = [ MATCH "([0-9]+) "$(base-pat) : $(dir-listing) : 1 ] ;
|
|
|
|
# If the file has a reasonably small size, look for the special symlink
|
|
# identification text.
|
|
if $(size-of-system-file) && [ numbers.less $(size-of-system-file) 1000 ]
|
|
{
|
|
local link = [ SHELL "FIND /OFF \"!<symlink>\" \""$(path)"\" 2>&1" ] ;
|
|
if $(link[2]) != 0
|
|
{
|
|
local nl = "
|
|
|
|
" ;
|
|
is-symlink = [ MATCH ".*!<symlink>([^"$(nl)"]*)" : $(link[1]) : 1 ] ;
|
|
if $(is-symlink)
|
|
{
|
|
is-symlink = [ *nix-path-to-native $(is-symlink) ] ;
|
|
is-symlink = $(is-symlink:R=$(path:D)) ;
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
return $(is-symlink) ;
|
|
}
|
|
|
|
|
|
# Append ext to each member of names that does not contain '.'.
|
|
#
|
|
local rule default-extension ( names * : ext * )
|
|
{
|
|
local result ;
|
|
for local n in $(names)
|
|
{
|
|
switch $(n)
|
|
{
|
|
case *.* : result += $(n) ;
|
|
case * : result += $(n)$(ext) ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
|
|
# Tries to determine whether invoking "cmd" would actually attempt to launch a
|
|
# cygwin symlink.
|
|
#
|
|
# Note: only works on NT.
|
|
#
|
|
local rule invokes-cygwin-symlink ( cmd )
|
|
{
|
|
local dirs = $(cmd:D) ;
|
|
if ! $(dirs)
|
|
{
|
|
dirs = . [ os.executable-path ] ;
|
|
}
|
|
local base = [ default-extension $(cmd:D=) : .exe .cmd .bat ] ;
|
|
local paths = [ GLOB $(dirs) : $(base) ] ;
|
|
if $(paths)
|
|
{
|
|
# Make sure we have not run into a Cygwin symlink. Invoking such a file
|
|
# as an NT executable would be fatal for the bjam process.
|
|
return [ is-cygwin-symlink $(paths[1]) ] ;
|
|
}
|
|
}
|
|
|
|
|
|
local rule debug-message ( message * )
|
|
{
|
|
if --debug-configuration in [ modules.peek : ARGV ]
|
|
{
|
|
ECHO notice: [python-cfg] $(message) ;
|
|
}
|
|
}
|
|
|
|
|
|
# Like W32_GETREG, except prepend HKEY_CURRENT_USER\SOFTWARE and
|
|
# HKEY_LOCAL_MACHINE\SOFTWARE to the first argument, returning the first result
|
|
# found. Also accounts for the fact that on 64-bit machines, 32-bit software has
|
|
# its own area, under SOFTWARE\Wow6432node.
|
|
#
|
|
local rule software-registry-value ( path : data ? )
|
|
{
|
|
local result ;
|
|
for local root in HKEY_CURRENT_USER HKEY_LOCAL_MACHINE
|
|
{
|
|
for local x64elt in "" Wow6432node\\ # Account for 64-bit windows
|
|
{
|
|
if ! $(result)
|
|
{
|
|
result = [ W32_GETREG $(root)\\SOFTWARE\\$(x64elt)$(path) : $(data) ] ;
|
|
}
|
|
}
|
|
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
|
|
.windows-drive-letter-re = ^([A-Za-z]):[\\/](.*) ;
|
|
.cygwin-drive-letter-re = ^/cygdrive/([a-z])/(.*) ;
|
|
|
|
.working-directory = [ PWD ] ;
|
|
.working-drive-letter = [ SUBST $(.working-directory) $(.windows-drive-letter-re) $1 ] ;
|
|
.working-drive-letter ?= [ SUBST $(.working-directory) $(.cygwin-drive-letter-re) $1 ] ;
|
|
|
|
|
|
local rule windows-to-cygwin-path ( path )
|
|
{
|
|
# If path is rooted with a drive letter, rewrite it using the /cygdrive
|
|
# mountpoint.
|
|
local p = [ SUBST $(path:T) $(.windows-drive-letter-re) /cygdrive/$1/$2 ] ;
|
|
|
|
# Else if path is rooted without a drive letter, use the working directory.
|
|
p ?= [ SUBST $(path:T) ^/(.*) /cygdrive/$(.working-drive-letter:L)/$2 ] ;
|
|
|
|
# Else return the path unchanged.
|
|
return $(p:E=$(path:T)) ;
|
|
}
|
|
|
|
|
|
# :W only works in Cygwin builds of bjam. This one works on NT builds as well.
|
|
#
|
|
local rule cygwin-to-windows-path ( path )
|
|
{
|
|
path = $(path:R="") ; # strip any trailing slash
|
|
|
|
local drive-letter = [ SUBST $(path) $(.cygwin-drive-letter-re) $1:/$2 ] ;
|
|
if $(drive-letter)
|
|
{
|
|
path = $(drive-letter) ;
|
|
}
|
|
else if $(path:R=/x) = $(path) # already rooted?
|
|
{
|
|
# Look for a cygwin mount that includes each head sequence in $(path).
|
|
local head = $(path) ;
|
|
local tail = "" ;
|
|
|
|
while $(head)
|
|
{
|
|
local root = [ software-registry-value
|
|
"Cygnus Solutions\\Cygwin\\mounts v2\\"$(head) : native ] ;
|
|
|
|
if $(root)
|
|
{
|
|
path = $(tail:R=$(root)) ;
|
|
head = ;
|
|
}
|
|
tail = $(tail:R=$(head:D=)) ;
|
|
|
|
if $(head) = /
|
|
{
|
|
head = ;
|
|
}
|
|
else
|
|
{
|
|
head = $(head:D) ;
|
|
}
|
|
}
|
|
}
|
|
return [ regex.replace $(path:R="") / \\ ] ;
|
|
}
|
|
|
|
|
|
# Convert a *nix path to native.
|
|
#
|
|
local rule *nix-path-to-native ( path )
|
|
{
|
|
if [ os.name ] = NT
|
|
{
|
|
path = [ cygwin-to-windows-path $(path) ] ;
|
|
}
|
|
return $(path) ;
|
|
}
|
|
|
|
|
|
# Convert an NT path to native.
|
|
#
|
|
local rule windows-path-to-native ( path )
|
|
{
|
|
if [ os.name ] = NT
|
|
{
|
|
return $(path) ;
|
|
}
|
|
else
|
|
{
|
|
return [ windows-to-cygwin-path $(path) ] ;
|
|
}
|
|
}
|
|
|
|
|
|
# Return nonempty if path looks like a windows path, i.e. it starts with a drive
|
|
# letter or contains backslashes.
|
|
#
|
|
local rule guess-windows-path ( path )
|
|
{
|
|
return [ SUBST $(path) ($(.windows-drive-letter-re)|.*([\\]).*) $1 ] ;
|
|
}
|
|
|
|
|
|
local rule path-to-native ( paths * )
|
|
{
|
|
local result ;
|
|
|
|
for local p in $(paths)
|
|
{
|
|
if [ guess-windows-path $(p) ]
|
|
{
|
|
result += [ windows-path-to-native $(p) ] ;
|
|
}
|
|
else
|
|
{
|
|
result += [ *nix-path-to-native $(p:T) ] ;
|
|
}
|
|
}
|
|
return $(result) ;
|
|
}
|
|
|
|
|
|
# Validate the version string and extract the major/minor part we care about.
|
|
#
|
|
local rule split-version ( version )
|
|
{
|
|
local major-minor = [ MATCH ^([0-9]+)\.([0-9]+)(.*)$ : $(version) : 1 2 3 ] ;
|
|
if ! $(major-minor[2]) || $(major-minor[3])
|
|
{
|
|
ECHO "Warning: \"using python\" expects a two part (major, minor) version number; got" $(version) instead ;
|
|
|
|
# Add a zero to account for the missing digit if necessary.
|
|
major-minor += 0 ;
|
|
}
|
|
|
|
return $(major-minor[1]) $(major-minor[2]) ;
|
|
}
|
|
|
|
|
|
# Build a list of versions from 3.0 down to 1.5. Because bjam can not enumerate
|
|
# registry sub-keys, we have no way of finding a version with a 2-digit minor
|
|
# version, e.g. 2.10 -- let us hope that never happens.
|
|
#
|
|
.version-countdown = ;
|
|
for local v in [ numbers.range 15 30 ]
|
|
{
|
|
.version-countdown = [ SUBST $(v) (.)(.*) $1.$2 ] $(.version-countdown) ;
|
|
}
|
|
|
|
|
|
local rule windows-installed-pythons ( version ? )
|
|
{
|
|
version ?= $(.version-countdown) ;
|
|
local interpreters ;
|
|
|
|
for local v in $(version)
|
|
{
|
|
local install-path = [
|
|
software-registry-value "Python\\PythonCore\\"$(v)"\\InstallPath" ] ;
|
|
|
|
if $(install-path)
|
|
{
|
|
install-path = [ windows-path-to-native $(install-path) ] ;
|
|
debug-message Registry indicates Python $(v) installed at \"$(install-path)\" ;
|
|
}
|
|
|
|
interpreters += $(:E=python:R=$(install-path)) ;
|
|
}
|
|
return $(interpreters) ;
|
|
}
|
|
|
|
|
|
local rule darwin-installed-pythons ( version ? )
|
|
{
|
|
version ?= $(.version-countdown) ;
|
|
|
|
local prefix
|
|
= [ GLOB /System/Library/Frameworks /Library/Frameworks
|
|
: Python.framework ] ;
|
|
|
|
return $(prefix)/Versions/$(version)/bin/python ;
|
|
}
|
|
|
|
|
|
# Assume "python-cmd" invokes a python interpreter and invoke it to extract all
|
|
# the information we care about from its "sys" module. Returns void if
|
|
# unsuccessful.
|
|
#
|
|
local rule probe ( python-cmd )
|
|
{
|
|
# Avoid invoking a Cygwin symlink on NT.
|
|
local skip-symlink ;
|
|
if [ os.name ] = NT
|
|
{
|
|
skip-symlink = [ invokes-cygwin-symlink $(python-cmd) ] ;
|
|
}
|
|
|
|
if $(skip-symlink)
|
|
{
|
|
debug-message -------------------------------------------------------------------- ;
|
|
debug-message \"$(python-cmd)\" would attempt to invoke a Cygwin symlink, ;
|
|
debug-message causing a bjam built for Windows to hang. ;
|
|
debug-message ;
|
|
debug-message If you intend to target a Cygwin build of Python, please ;
|
|
debug-message replace the path to the link with the path to a real executable ;
|
|
debug-message (guessing: \"$(skip-symlink)\") "in" your 'using python' line ;
|
|
debug-message "in" user-config.jam or site-config.jam. Do not forget to escape ;
|
|
debug-message backslashes ;
|
|
debug-message -------------------------------------------------------------------- ;
|
|
}
|
|
else
|
|
{
|
|
# Prepare a List of Python format strings and expressions that can be
|
|
# used to print the constants we want from the sys module.
|
|
|
|
# We do not really want sys.version since that is a complicated string,
|
|
# so get the information from sys.version_info instead.
|
|
local format = "version=%d.%d" ;
|
|
local exprs = "version_info[0]" "version_info[1]" ;
|
|
|
|
for local s in $(sys-elements[2-])
|
|
{
|
|
format += $(s)=%s ;
|
|
exprs += $(s) ;
|
|
}
|
|
|
|
# Invoke Python and ask it for all those values.
|
|
if [ version.check-jam-version 3 1 17 ] || ( [ os.name ] != NT )
|
|
{
|
|
# Prior to version 3.1.17 Boost Jam's SHELL command did not support
|
|
# quoted commands correctly on Windows. This means that on that
|
|
# platform we do not support using a Python command interpreter
|
|
# executable whose path contains a space character.
|
|
python-cmd = \"$(python-cmd)\" ;
|
|
}
|
|
local full-cmd =
|
|
$(python-cmd)" -c \"from sys import *; print('"$(format:J=\\n)"' % ("$(exprs:J=,)"))\"" ;
|
|
|
|
local output = [ shell-cmd $(full-cmd) ] ;
|
|
if $(output)
|
|
{
|
|
# Parse the output to get all the results.
|
|
local nl = "
|
|
|
|
" ;
|
|
for s in $(sys-elements)
|
|
{
|
|
# These variables are expected to be declared local in the
|
|
# caller, so Jam's dynamic scoping will set their values there.
|
|
sys.$(s) = [ SUBST $(output) \\<$(s)=([^$(nl)]+) $1 ] ;
|
|
}
|
|
}
|
|
return $(output) ;
|
|
}
|
|
}
|
|
|
|
|
|
# Make sure the "libraries" and "includes" variables (in an enclosing scope)
|
|
# have a value based on the information given.
|
|
#
|
|
local rule compute-default-paths ( target-os : version ? : prefix ? :
|
|
exec-prefix ? )
|
|
{
|
|
exec-prefix ?= $(prefix) ;
|
|
|
|
if $(target-os) = windows
|
|
{
|
|
# The exec_prefix is where you're supposed to look for machine-specific
|
|
# libraries.
|
|
local default-library-path = $(exec-prefix)\\libs ;
|
|
local default-include-path = $(:E=Include:R=$(prefix)) ;
|
|
|
|
# If the interpreter was found in a directory called "PCBuild" or
|
|
# "PCBuild8," assume we're looking at a Python built from the source
|
|
# distro, and go up one additional level to the default root. Otherwise,
|
|
# the default root is the directory where the interpreter was found.
|
|
|
|
# We ask Python itself what the executable path is in case of
|
|
# intermediate symlinks or shell scripts.
|
|
local executable-dir = $(sys.executable:D) ;
|
|
|
|
if [ MATCH ^(PCBuild) : $(executable-dir:D=) ]
|
|
{
|
|
debug-message "This Python appears to reside in a source distribution;" ;
|
|
debug-message "prepending \""$(executable-dir)"\" to default library search path" ;
|
|
|
|
default-library-path = $(executable-dir) $(default-library-path) ;
|
|
|
|
default-include-path = $(:E=PC:R=$(executable-dir:D)) $(default-include-path) ;
|
|
|
|
debug-message "and \""$(default-include-path[1])"\" to default #include path" ;
|
|
}
|
|
|
|
libraries ?= $(default-library-path) ;
|
|
includes ?= $(default-include-path) ;
|
|
}
|
|
else
|
|
{
|
|
includes ?= $(prefix)/include/python$(version) ;
|
|
|
|
local lib = $(exec-prefix)/lib ;
|
|
libraries ?= $(lib)/python$(version)/config $(lib) ;
|
|
}
|
|
}
|
|
|
|
# The version of the python interpreter to use.
|
|
feature.feature python : : propagated ;
|
|
feature.feature python.interpreter : : free ;
|
|
|
|
toolset.flags python.capture-output PYTHON : <python.interpreter> ;
|
|
|
|
#
|
|
# Support for Python configured --with-pydebug
|
|
#
|
|
feature.feature python-debugging : off on : propagated ;
|
|
builtin.variant debug-python : debug : <python-debugging>on ;
|
|
|
|
|
|
# Return a list of candidate commands to try when looking for a Python
|
|
# interpreter. prefix is expected to be a native path.
|
|
#
|
|
local rule candidate-interpreters ( version ? : prefix ? : target-os )
|
|
{
|
|
local bin-path = bin ;
|
|
if $(target-os) = windows
|
|
{
|
|
# On Windows, look in the root directory itself and, to work with the
|
|
# result of a build-from-source, the PCBuild directory.
|
|
bin-path = PCBuild8 PCBuild "" ;
|
|
}
|
|
|
|
bin-path = $(bin-path:R=$(prefix)) ;
|
|
|
|
if $(target-os) in windows darwin
|
|
{
|
|
return # Search:
|
|
$(:E=python:R=$(bin-path)) # Relative to the prefix, if any
|
|
python # In the PATH
|
|
[ $(target-os)-installed-pythons $(version) ] # Standard install locations
|
|
;
|
|
}
|
|
else
|
|
{
|
|
# Search relative to the prefix, or if none supplied, in PATH.
|
|
local unversioned = $(:E=python:R=$(bin-path:E=)) ;
|
|
|
|
# If a version was specified, look for a python with that specific
|
|
# version appended before looking for one called, simply, "python"
|
|
return $(unversioned)$(version) $(unversioned) ;
|
|
}
|
|
}
|
|
|
|
|
|
# Compute system library dependencies for targets linking with static Python
|
|
# libraries.
|
|
#
|
|
# On many systems, Python uses libraries such as pthreads or libdl. Since static
|
|
# libraries carry no library dependency information of their own that the linker
|
|
# can extract, these extra dependencies have to be given explicitly on the link
|
|
# line of the client. The information about these dependencies is packaged into
|
|
# the "python" target below.
|
|
#
|
|
# Even where Python itself uses pthreads, it never allows extension modules to
|
|
# be entered concurrently (unless they explicitly give up the interpreter lock).
|
|
# Therefore, extension modules do not need the efficiency overhead of threadsafe
|
|
# code as produced by <threading>multi, and we handle libpthread along with
|
|
# other libraries here. Note: this optimization is based on an assumption that
|
|
# the compiler generates link-compatible code in both the single- and
|
|
# multi-threaded cases, and that system libraries do not change their ABIs
|
|
# either.
|
|
#
|
|
# Returns a list of usage-requirements that link to the necessary system
|
|
# libraries.
|
|
#
|
|
local rule system-library-dependencies ( target-os )
|
|
{
|
|
switch $(target-os)
|
|
{
|
|
case s[uo][nl]* : # solaris, sun, sunos
|
|
# Add a librt dependency for the gcc toolset on SunOS (the sun
|
|
# toolset adds -lrt unconditionally). While this appears to
|
|
# duplicate the logic already in gcc.jam, it does not as long as
|
|
# we are not forcing <threading>multi.
|
|
|
|
# On solaris 10, distutils.sysconfig.get_config_var('LIBS') yields
|
|
# '-lresolv -lsocket -lnsl -lrt -ldl'. However, that does not seem
|
|
# to be the right list for extension modules. For example, on my
|
|
# installation, adding -ldl causes at least one test to fail because
|
|
# the library can not be found and removing it causes no failures.
|
|
|
|
# Apparently, though, we need to add -lrt for gcc.
|
|
return <toolset>gcc:<library>rt ;
|
|
|
|
case osf : return <library>pthread <toolset>gcc:<library>rt ;
|
|
|
|
case qnx* : return ;
|
|
case darwin : return ;
|
|
case windows : return ;
|
|
|
|
case hpux : return <library>rt ;
|
|
case *bsd : return <library>pthread <toolset>gcc:<library>util ;
|
|
|
|
case aix : return <library>pthread <library>dl ;
|
|
|
|
case * : return <library>pthread <library>dl
|
|
<toolset>gcc:<library>util <toolset-intel:platform>linux:<library>util ;
|
|
}
|
|
}
|
|
|
|
|
|
# Declare a target to represent Python's library.
|
|
#
|
|
local rule declare-libpython-target ( version ? : requirements * )
|
|
{
|
|
# Compute the representation of Python version in the name of Python's
|
|
# library file.
|
|
local lib-version = $(version) ;
|
|
if <target-os>windows in $(requirements)
|
|
{
|
|
local major-minor = [ split-version $(version) ] ;
|
|
lib-version = $(major-minor:J="") ;
|
|
if <python-debugging>on in $(requirements)
|
|
{
|
|
lib-version = $(lib-version)_d ;
|
|
}
|
|
}
|
|
|
|
if ! $(lib-version)
|
|
{
|
|
ECHO *** warning: could not determine Python version, which will ;
|
|
ECHO *** warning: probably prevent us from linking with the python ;
|
|
ECHO *** warning: library. Consider explicitly passing the version ;
|
|
ECHO *** warning: to 'using python'. ;
|
|
}
|
|
|
|
# Declare it.
|
|
lib python.lib : : <name>python$(lib-version) $(requirements) ;
|
|
}
|
|
|
|
|
|
# Implementation of init.
|
|
local rule configure ( version ? : cmd-or-prefix ? : includes * : libraries ? :
|
|
condition * : extension-suffix ? )
|
|
{
|
|
local prefix ;
|
|
local exec-prefix ;
|
|
local cmds-to-try ;
|
|
local interpreter-cmd ;
|
|
|
|
local target-os = [ feature.get-values target-os : $(condition) ] ;
|
|
target-os ?= [ feature.defaults target-os ] ;
|
|
target-os = $(target-os:G=) ;
|
|
|
|
if $(target-os) = windows && <python-debugging>on in $(condition)
|
|
{
|
|
extension-suffix ?= _d ;
|
|
}
|
|
extension-suffix ?= "" ;
|
|
|
|
# Normalize and dissect any version number.
|
|
local major-minor ;
|
|
if $(version)
|
|
{
|
|
major-minor = [ split-version $(version) ] ;
|
|
version = $(major-minor:J=.) ;
|
|
}
|
|
|
|
local cmds-to-try ;
|
|
|
|
if ! $(cmd-or-prefix) || [ GLOB $(cmd-or-prefix) : * ]
|
|
{
|
|
# If the user did not pass a command, whatever we got was a prefix.
|
|
prefix = $(cmd-or-prefix) ;
|
|
cmds-to-try = [ candidate-interpreters $(version) : $(prefix) : $(target-os) ] ;
|
|
}
|
|
else
|
|
{
|
|
# Work with the command the user gave us.
|
|
cmds-to-try = $(cmd-or-prefix) ;
|
|
|
|
# On Windows, do not nail down the interpreter command just yet in case
|
|
# the user specified something that turns out to be a cygwin symlink,
|
|
# which could bring down bjam if we invoke it.
|
|
if $(target-os) != windows
|
|
{
|
|
interpreter-cmd = $(cmd-or-prefix) ;
|
|
}
|
|
}
|
|
|
|
# Values to use in case we can not really find anything in the system.
|
|
local fallback-cmd = $(cmds-to-try[1]) ;
|
|
local fallback-version ;
|
|
|
|
# Anything left to find or check?
|
|
if ! ( $(interpreter-cmd) && $(includes) && $(libraries) )
|
|
{
|
|
# Values to be extracted from python's sys module. These will be set by
|
|
# the probe rule, above, using Jam's dynamic scoping.
|
|
local sys-elements = version platform prefix exec_prefix executable ;
|
|
local sys.$(sys-elements) ;
|
|
|
|
# Compute the string Python's sys.platform needs to match. If not
|
|
# targeting Windows or cygwin we will assume only native builds can
|
|
# possibly run, so we will not require a match and we leave sys.platform
|
|
# blank.
|
|
local platform ;
|
|
switch $(target-os)
|
|
{
|
|
case windows : platform = win32 ;
|
|
case cygwin : platform = cygwin ;
|
|
}
|
|
|
|
while $(cmds-to-try)
|
|
{
|
|
# Pop top command.
|
|
local cmd = $(cmds-to-try[1]) ;
|
|
cmds-to-try = $(cmds-to-try[2-]) ;
|
|
|
|
debug-message Checking interpreter command \"$(cmd)\"... ;
|
|
if [ probe $(cmd) ]
|
|
{
|
|
fallback-version ?= $(sys.version) ;
|
|
|
|
# Check for version/platform validity.
|
|
for local x in version platform
|
|
{
|
|
if $($(x)) && $($(x)) != $(sys.$(x))
|
|
{
|
|
debug-message ...$(x) "mismatch (looking for"
|
|
$($(x)) but found $(sys.$(x))")" ;
|
|
cmd = ;
|
|
}
|
|
}
|
|
|
|
if $(cmd)
|
|
{
|
|
debug-message ...requested configuration matched! ;
|
|
|
|
exec-prefix = $(sys.exec_prefix) ;
|
|
|
|
compute-default-paths $(target-os) : $(sys.version) :
|
|
$(sys.prefix) : $(sys.exec_prefix) ;
|
|
|
|
version = $(sys.version) ;
|
|
interpreter-cmd ?= $(cmd) ;
|
|
cmds-to-try = ; # All done.
|
|
}
|
|
}
|
|
else
|
|
{
|
|
debug-message ...does not invoke a working interpreter ;
|
|
}
|
|
}
|
|
}
|
|
|
|
# Anything left to compute?
|
|
if $(includes) && $(libraries)
|
|
{
|
|
.configured = true ;
|
|
}
|
|
else
|
|
{
|
|
version ?= $(fallback-version) ;
|
|
version ?= 2.5 ;
|
|
exec-prefix ?= $(prefix) ;
|
|
compute-default-paths $(target-os) : $(version) : $(prefix:E=) ;
|
|
}
|
|
|
|
if ! $(interpreter-cmd)
|
|
{
|
|
fallback-cmd ?= python ;
|
|
debug-message No working Python interpreter found. ;
|
|
if [ os.name ] != NT || ! [ invokes-cygwin-symlink $(fallback-cmd) ]
|
|
{
|
|
interpreter-cmd = $(fallback-cmd) ;
|
|
debug-message falling back to \"$(interpreter-cmd)\" ;
|
|
}
|
|
}
|
|
|
|
includes = [ path-to-native $(includes) ] ;
|
|
libraries = [ path-to-native $(libraries) ] ;
|
|
|
|
debug-message "Details of this Python configuration:" ;
|
|
debug-message " interpreter command:" \"$(interpreter-cmd:E=<empty>)\" ;
|
|
debug-message " include path:" \"$(includes:E=<empty>)\" ;
|
|
debug-message " library path:" \"$(libraries:E=<empty>)\" ;
|
|
if $(target-os) = windows
|
|
{
|
|
debug-message " DLL search path:" \"$(exec-prefix:E=<empty>)\" ;
|
|
}
|
|
|
|
#
|
|
# End autoconfiguration sequence.
|
|
#
|
|
local target-requirements = $(condition) ;
|
|
|
|
# Add the version, if any, to the target requirements.
|
|
if $(version)
|
|
{
|
|
if ! $(version) in [ feature.values python ]
|
|
{
|
|
feature.extend python : $(version) ;
|
|
}
|
|
target-requirements += <python>$(version:E=default) ;
|
|
}
|
|
|
|
target-requirements += <target-os>$(target-os) ;
|
|
|
|
# See if we can find a framework directory on darwin.
|
|
local framework-directory ;
|
|
if $(target-os) = darwin
|
|
{
|
|
# Search upward for the framework directory.
|
|
local framework-directory = $(libraries[-1]) ;
|
|
while $(framework-directory:D=) && $(framework-directory:D=) != Python.framework
|
|
{
|
|
framework-directory = $(framework-directory:D) ;
|
|
}
|
|
|
|
if $(framework-directory:D=) = Python.framework
|
|
{
|
|
debug-message framework directory is \"$(framework-directory)\" ;
|
|
}
|
|
else
|
|
{
|
|
debug-message "no framework directory found; using library path" ;
|
|
framework-directory = ;
|
|
}
|
|
}
|
|
|
|
local dll-path = $(libraries) ;
|
|
|
|
# Make sure that we can find the Python DLL on Windows.
|
|
if ( $(target-os) = windows ) && $(exec-prefix)
|
|
{
|
|
dll-path += $(exec-prefix) ;
|
|
}
|
|
|
|
#
|
|
# Prepare usage requirements.
|
|
#
|
|
local usage-requirements = [ system-library-dependencies $(target-os) ] ;
|
|
usage-requirements += <include>$(includes) <python.interpreter>$(interpreter-cmd) ;
|
|
if <python-debugging>on in $(condition)
|
|
{
|
|
if $(target-os) = windows
|
|
{
|
|
# In pyconfig.h, Py_DEBUG is set if _DEBUG is set. If we define
|
|
# Py_DEBUG we will get multiple definition warnings.
|
|
usage-requirements += <define>_DEBUG ;
|
|
}
|
|
else
|
|
{
|
|
usage-requirements += <define>Py_DEBUG ;
|
|
}
|
|
}
|
|
|
|
# Global, but conditional, requirements to give access to the interpreter
|
|
# for general utilities, like other toolsets, that run Python scripts.
|
|
toolset.add-requirements
|
|
$(target-requirements:J=,):<python.interpreter>$(interpreter-cmd) ;
|
|
|
|
# Register the right suffix for extensions.
|
|
register-extension-suffix $(extension-suffix) : $(target-requirements) ;
|
|
|
|
#
|
|
# Declare the "python" target. This should really be called
|
|
# python_for_embedding.
|
|
#
|
|
|
|
if $(framework-directory)
|
|
{
|
|
alias python
|
|
:
|
|
: $(target-requirements)
|
|
:
|
|
: $(usage-requirements) <framework>$(framework-directory)
|
|
;
|
|
}
|
|
else
|
|
{
|
|
declare-libpython-target $(version) : $(target-requirements) ;
|
|
|
|
# This is an evil hack. On, Windows, when Python is embedded, nothing
|
|
# seems to set up sys.path to include Python's standard library
|
|
# (http://article.gmane.org/gmane.comp.python.general/544986). The evil
|
|
# here, aside from the workaround necessitated by Python's bug, is that:
|
|
#
|
|
# a. we're guessing the location of the python standard library from the
|
|
# location of pythonXX.lib
|
|
#
|
|
# b. we're hijacking the <testing.launcher> property to get the
|
|
# environment variable set up, and the user may want to use it for
|
|
# something else (e.g. launch the debugger).
|
|
local set-PYTHONPATH ;
|
|
if $(target-os) = windows
|
|
{
|
|
set-PYTHONPATH = [ common.prepend-path-variable-command PYTHONPATH :
|
|
$(libraries:D)/Lib ] ;
|
|
}
|
|
|
|
alias python
|
|
:
|
|
: $(target-requirements)
|
|
:
|
|
# Why python.lib must be listed here instead of along with the
|
|
# system libs is a mystery, but if we do not do it, on cygwin,
|
|
# -lpythonX.Y never appears in the command line (although it does on
|
|
# linux).
|
|
: $(usage-requirements)
|
|
<testing.launcher>$(set-PYTHONPATH)
|
|
<library-path>$(libraries) <dll-path>$(dll-path) <library>python.lib
|
|
;
|
|
}
|
|
|
|
# On *nix, we do not want to link either Boost.Python or Python extensions
|
|
# to libpython, because the Python interpreter itself provides all those
|
|
# symbols. If we linked to libpython, we would get duplicate symbols. So
|
|
# declare two targets -- one for building extensions and another for
|
|
# embedding.
|
|
#
|
|
# Unlike most *nix systems, Mac OS X's linker does not permit undefined
|
|
# symbols when linking a shared library. So, we still need to link against
|
|
# the Python framework, even when building extensions. Note that framework
|
|
# builds of Python always use shared libraries, so we do not need to worry
|
|
# about duplicate Python symbols.
|
|
if $(target-os) in windows cygwin darwin
|
|
{
|
|
alias python_for_extensions : python : $(target-requirements) ;
|
|
}
|
|
# On AIX we need Python extensions and Boost.Python to import symbols from
|
|
# the Python interpreter. Dynamic libraries opened with dlopen() do not
|
|
# inherit the symbols from the Python interpreter.
|
|
else if $(target-os) = aix
|
|
{
|
|
alias python_for_extensions
|
|
:
|
|
: $(target-requirements)
|
|
:
|
|
: $(usage-requirements) <linkflags>-Wl,-bI:$(libraries[1])/python.exp
|
|
;
|
|
}
|
|
else
|
|
{
|
|
alias python_for_extensions
|
|
:
|
|
: $(target-requirements)
|
|
:
|
|
: $(usage-requirements)
|
|
;
|
|
}
|
|
}
|
|
|
|
|
|
rule configured ( )
|
|
{
|
|
return $(.configured) ;
|
|
}
|
|
|
|
|
|
type.register PYTHON_EXTENSION : : SHARED_LIB ;
|
|
|
|
|
|
local rule register-extension-suffix ( root : condition * )
|
|
{
|
|
local suffix ;
|
|
|
|
switch [ feature.get-values target-os : $(condition) ]
|
|
{
|
|
case windows : suffix = pyd ;
|
|
case cygwin : suffix = dll ;
|
|
case hpux :
|
|
{
|
|
if [ feature.get-values python : $(condition) ] in 1.5 1.6 2.0 2.1 2.2 2.3 2.4
|
|
{
|
|
suffix = sl ;
|
|
}
|
|
else
|
|
{
|
|
suffix = so ;
|
|
}
|
|
}
|
|
case * : suffix = so ;
|
|
}
|
|
|
|
type.set-generated-target-suffix PYTHON_EXTENSION : $(condition) : <$(root).$(suffix)> ;
|
|
}
|
|
|
|
|
|
# Unset 'lib' prefix for PYTHON_EXTENSION
|
|
type.set-generated-target-prefix PYTHON_EXTENSION : : "" ;
|
|
|
|
|
|
rule python-extension ( name : sources * : requirements * : default-build * :
|
|
usage-requirements * )
|
|
{
|
|
if [ configured ]
|
|
{
|
|
requirements += <use>/python//python_for_extensions ;
|
|
}
|
|
requirements += <suppress-import-lib>true ;
|
|
|
|
local project = [ project.current ] ;
|
|
|
|
targets.main-target-alternative
|
|
[ new typed-target $(name) : $(project) : PYTHON_EXTENSION
|
|
: [ targets.main-target-sources $(sources) : $(name) ]
|
|
: [ targets.main-target-requirements $(requirements) : $(project) ]
|
|
: [ targets.main-target-default-build $(default-build) : $(project) ]
|
|
] ;
|
|
}
|
|
|
|
IMPORT python : python-extension : : python-extension ;
|
|
|
|
rule py2to3
|
|
{
|
|
common.copy $(>) $(<) ;
|
|
2to3 $(<) ;
|
|
}
|
|
|
|
actions 2to3
|
|
{
|
|
2to3 -wn "$(<)"
|
|
2to3 -dwn "$(<)"
|
|
}
|
|
|
|
|
|
# Support for testing.
|
|
type.register PY : py ;
|
|
type.register RUN_PYD_OUTPUT ;
|
|
type.register RUN_PYD : : TEST ;
|
|
|
|
|
|
class python-test-generator : generator
|
|
{
|
|
import set ;
|
|
|
|
rule __init__ ( * : * )
|
|
{
|
|
generator.__init__ $(1) : $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
|
self.composing = true ;
|
|
}
|
|
|
|
rule run ( project name ? : property-set : sources * : multiple ? )
|
|
{
|
|
local pyversion = [ $(property-set).get <python> ] ;
|
|
local python ;
|
|
local other-pythons ;
|
|
|
|
# Make new target that converting Python source by 2to3 when running with Python 3.
|
|
local rule make-2to3-source ( source )
|
|
{
|
|
if $(pyversion) >= 3.0
|
|
{
|
|
local a = [ new action $(source) : python.py2to3 : $(property-set) ] ;
|
|
local t = [ utility.basename [ $(s).name ] ] ;
|
|
local p = [ new file-target $(t) : PY : $(project) : $(a) ] ;
|
|
return $(p) ;
|
|
}
|
|
else
|
|
{
|
|
return $(source) ;
|
|
}
|
|
}
|
|
|
|
for local s in $(sources)
|
|
{
|
|
if [ $(s).type ] = PY
|
|
{
|
|
if ! $(python)
|
|
{
|
|
# First Python source ends up on command line.
|
|
python = [ make-2to3-source $(s) ] ;
|
|
|
|
}
|
|
else
|
|
{
|
|
# Other Python sources become dependencies.
|
|
other-pythons += [ make-2to3-source $(s) ] ;
|
|
}
|
|
}
|
|
}
|
|
|
|
local extensions ;
|
|
for local s in $(sources)
|
|
{
|
|
if [ $(s).type ] = PYTHON_EXTENSION
|
|
{
|
|
extensions += $(s) ;
|
|
}
|
|
}
|
|
|
|
local libs ;
|
|
for local s in $(sources)
|
|
{
|
|
if [ type.is-derived [ $(s).type ] LIB ]
|
|
&& ! $(s) in $(extensions)
|
|
{
|
|
libs += $(s) ;
|
|
}
|
|
}
|
|
|
|
local new-sources ;
|
|
for local s in $(sources)
|
|
{
|
|
if [ type.is-derived [ $(s).type ] CPP ]
|
|
{
|
|
local name = [ utility.basename [ $(s).name ] ] ;
|
|
if $(name) = [ utility.basename [ $(python).name ] ]
|
|
{
|
|
name = $(name)_ext ;
|
|
}
|
|
local extension = [ generators.construct $(project) $(name) :
|
|
PYTHON_EXTENSION : $(property-set) : $(s) $(libs) ] ;
|
|
|
|
# The important part of usage requirements returned from
|
|
# PYTHON_EXTENSION generator are xdll-path properties that will
|
|
# allow us to find the python extension at runtime.
|
|
property-set = [ $(property-set).add $(extension[1]) ] ;
|
|
|
|
# Ignore usage requirements. We're a top-level generator and
|
|
# nobody is going to use what we generate.
|
|
new-sources += $(extension[2-]) ;
|
|
}
|
|
}
|
|
|
|
property-set = [ $(property-set).add-raw <dependency>$(other-pythons) ] ;
|
|
|
|
result = [ construct-result $(python) $(extensions) $(new-sources) :
|
|
$(project) $(name) : $(property-set) ] ;
|
|
}
|
|
}
|
|
|
|
|
|
generators.register
|
|
[ new python-test-generator python.capture-output : : RUN_PYD_OUTPUT ] ;
|
|
|
|
generators.register-standard testing.expect-success
|
|
: RUN_PYD_OUTPUT : RUN_PYD ;
|
|
|
|
|
|
# There are two different ways of spelling OS names. One is used for [ os.name ]
|
|
# and the other is used for the <host-os> and <target-os> properties. Until that
|
|
# is remedied, this sets up a crude mapping from the latter to the former, that
|
|
# will work *for the purposes of cygwin/NT cross-builds only*. Could not think
|
|
# of a better name than "translate".
|
|
#
|
|
.translate-os-windows = NT ;
|
|
.translate-os-cygwin = CYGWIN ;
|
|
local rule translate-os ( src-os )
|
|
{
|
|
local x = $(.translate-os-$(src-os)) [ os.name ] ;
|
|
return $(x[1]) ;
|
|
}
|
|
|
|
|
|
# Extract the path to a single ".pyd" source. This is used to build the
|
|
# PYTHONPATH for running bpl tests.
|
|
#
|
|
local rule pyd-pythonpath ( source )
|
|
{
|
|
return [ on $(source) return $(LOCATE) $(SEARCH) ] ;
|
|
}
|
|
|
|
|
|
# The flag settings on testing.capture-output do not apply to python.capture
|
|
# output at the moment. Redo this explicitly.
|
|
toolset.flags python.capture-output ARGS <testing.arg> ;
|
|
|
|
|
|
rule capture-output ( target : sources * : properties * )
|
|
{
|
|
# Setup up a proper DLL search path. Here, $(sources[1]) is a python module
|
|
# and $(sources[2]) is a DLL. Only $(sources[1]) is passed to
|
|
# testing.capture-output, so RUN_PATH variable on $(sources[2]) is not
|
|
# consulted. Move it over explicitly.
|
|
RUN_PATH on $(sources[1]) = [ on $(sources[2-]) return $(RUN_PATH) ] ;
|
|
|
|
PYTHONPATH = [ sequence.transform pyd-pythonpath : $(sources[2-]) ] ;
|
|
PYTHONPATH += [ feature.get-values pythonpath : $(properties) ] ;
|
|
|
|
# After test is run, we remove the Python module, but not the Python script.
|
|
testing.capture-output $(target) : $(sources[1]) : $(properties) :
|
|
$(sources[2-]) ;
|
|
|
|
# PYTHONPATH is different; it will be interpreted by whichever Python is
|
|
# invoked and so must follow path rules for the target os. The only OSes
|
|
# where we can run python for other OSes currently are NT and CYGWIN so we
|
|
# only need to handle those cases.
|
|
local target-os = [ feature.get-values target-os : $(properties) ] ;
|
|
# Oddly, host-os is not in properties, so grab the default value.
|
|
local host-os = [ feature.defaults host-os ] ;
|
|
host-os = $(host-os:G=) ;
|
|
if $(target-os) != $(host-os)
|
|
{
|
|
PYTHONPATH = [ sequence.transform $(host-os)-to-$(target-os)-path :
|
|
$(PYTHONPATH) ] ;
|
|
}
|
|
local path-separator = [ os.path-separator [ translate-os $(target-os) ] ] ;
|
|
local set-PYTHONPATH = [ common.variable-setting-command PYTHONPATH :
|
|
$(PYTHONPATH:J=$(path-separator)) ] ;
|
|
LAUNCHER on $(target) = $(set-PYTHONPATH) [ on $(target) return \"$(PYTHON)\" ] ;
|
|
}
|
|
|
|
|
|
rule bpl-test ( name : sources * : requirements * )
|
|
{
|
|
local s ;
|
|
sources ?= $(name).py $(name).cpp ;
|
|
return [ testing.make-test run-pyd : $(sources) /boost/python//boost_python
|
|
: $(requirements) : $(name) ] ;
|
|
}
|
|
|
|
|
|
IMPORT $(__name__) : bpl-test : : bpl-test ;
|