0c1741afa630bf4e9249117155a3a754ba51175e
"""distutils.command.build_ext
Implements the Distutils 'build_ext' command, for building extension
modules (currently limited to C extensions, should accommodate C++
# This module should be kept compatible with Python 2.1.
__revision__
= "$Id: build_ext.py,v 1.98 2004/11/10 22:23:15 loewis Exp $"
import sys
, os
, string
, re
from distutils
.core
import Command
from distutils
.errors
import *
from distutils
.sysconfig
import customize_compiler
, get_python_version
from distutils
.dep_util
import newer_group
from distutils
.extension
import Extension
from distutils
import log
# An extension name is just a dot-separated list of Python NAMEs (ie.
# the same as a fully-qualified module name).
extension_name_re
= re
.compile \
(r
'^[a-zA-Z_][a-zA-Z_0-9]*(\.[a-zA-Z_][a-zA-Z_0-9]*)*$')
from distutils
.ccompiler
import show_compilers
class build_ext (Command
):
description
= "build C/C++ extensions (compile/link to build directory)"
# XXX thoughts on how to deal with complex command-line options like
# these, i.e. how to make it so fancy_getopt can suck them off the
# command line and make it look like setup.py defined the appropriate
# lists of tuples of what-have-you.
# - each command needs a callback to process its command-line options
# - Command.__init__() needs access to its share of the whole
# command line (must ultimately come from
# Distribution.parse_command_line())
# - it then calls the current command class' option-parsing
# callback to deal with weird options like -D, which have to
# parse the option text and churn out some custom data
# - that data structure (in this case, a list of 2-tuples)
# will then be present in the command object by the time
# we get to finalize_options() (i.e. the constructor
# takes care of both command-line and client options
# in between initialize_options() and finalize_options())
sep_by
= " (separated by '%s')" % os
.pathsep
"directory for compiled extension modules"),
"directory for temporary files (build by-products)"),
"ignore build-lib and put compiled extensions into the source " +
"directory alongside your pure Python modules"),
"list of directories to search for header files" + sep_by
),
"C preprocessor macros to define"),
"C preprocessor macros to undefine"),
"external C libraries to link with"),
"directories to search for external C libraries" + sep_by
),
"directories to search for shared C libraries at runtime"),
"extra explicit link objects to include in the link"),
"compile/link with debugging information"),
"forcibly build everything (ignore file timestamps)"),
"specify the compiler type"),
"make SWIG create C++ files (default is C)"),
"list of SWIG command line options"),
"path to the SWIG executable"),
boolean_options
= ['inplace', 'debug', 'force', 'swig-cpp']
"list available compilers", show_compilers
),
def initialize_options (self
):
def finalize_options (self
):
from distutils
import sysconfig
self
.set_undefined_options('build',
('build_lib', 'build_lib'),
('build_temp', 'build_temp'),
('compiler', 'compiler'),
self
.package
= self
.distribution
.ext_package
self
.extensions
= self
.distribution
.ext_modules
# Make sure Python's include directories (for Python.h, pyconfig.h,
# etc.) are in the include search path.
py_include
= sysconfig
.get_python_inc()
plat_py_include
= sysconfig
.get_python_inc(plat_specific
=1)
if self
.include_dirs
is None:
self
.include_dirs
= self
.distribution
.include_dirs
or []
if type(self
.include_dirs
) is StringType
:
self
.include_dirs
= string
.split(self
.include_dirs
, os
.pathsep
)
# Put the Python "system" include dir at the end, so that
# any local include dirs take precedence.
self
.include_dirs
.append(py_include
)
if plat_py_include
!= py_include
:
self
.include_dirs
.append(plat_py_include
)
if type(self
.libraries
) is StringType
:
self
.libraries
= [self
.libraries
]
# Life is easier if we're not forever checking for None, so
# simplify these options to empty lists if unset
if self
.libraries
is None:
if self
.library_dirs
is None:
elif type(self
.library_dirs
) is StringType
:
self
.library_dirs
= string
.split(self
.library_dirs
, os
.pathsep
)
elif type(self
.rpath
) is StringType
:
self
.rpath
= string
.split(self
.rpath
, os
.pathsep
)
# for extensions under windows use different directories
# for Release and Debug builds.
# also Python's library directory must be appended to library_dirs
self
.library_dirs
.append(os
.path
.join(sys
.exec_prefix
, 'libs'))
self
.build_temp
= os
.path
.join(self
.build_temp
, "Debug")
self
.build_temp
= os
.path
.join(self
.build_temp
, "Release")
# Append the source distribution include and library directories,
# this allows distutils on windows to work in the source tree
self
.include_dirs
.append(os
.path
.join(sys
.exec_prefix
, 'PC'))
self
.library_dirs
.append(os
.path
.join(sys
.exec_prefix
, 'PCBuild'))
# OS/2 (EMX) doesn't support Debug vs Release builds, but has the
# import libraries in its "Config" subdirectory
self
.library_dirs
.append(os
.path
.join(sys
.exec_prefix
, 'Config'))
# for extensions under Cygwin and AtheOS Python's library directory must be
# appended to library_dirs
if sys
.platform
[:6] == 'cygwin' or sys
.platform
[:6] == 'atheos':
if string
.find(sys
.executable
, sys
.exec_prefix
) != -1:
# building third party extensions
self
.library_dirs
.append(os
.path
.join(sys
.prefix
, "lib",
"python" + get_python_version(),
# building python standard extensions
self
.library_dirs
.append('.')
# The argument parsing will result in self.define being a string, but
# it has to be a list of 2-tuples. All the preprocessor symbols
# specified by the 'define' option will be set to '1'. Multiple
# symbols can be separated with commas.
defines
= string
.split(self
.define
, ',')
self
.define
= map(lambda symbol
: (symbol
, '1'), defines
)
# The option for macros to undefine is also a string from the
# option parsing, but has to be a list. Multiple symbols can also
# be separated with commas here.
self
.undef
= string
.split(self
.undef
, ',')
if self
.swig_opts
is None:
self
.swig_opts
= self
.swig_opts
.split(' ')
from distutils
.ccompiler
import new_compiler
# 'self.extensions', as supplied by setup.py, is a list of
# Extension instances. See the documentation for Extension (in
# distutils.extension) for details.
# For backwards compatibility with Distutils 0.8.2 and earlier, we
# also allow the 'extensions' list to be a list of tuples:
# where build_info is a dictionary containing everything that
# Extension instances do except the name, with a few things being
# differently named. We convert these 2-tuples to Extension
# If we were asked to build any C/C++ libraries, make sure that the
# directory where we put them is in the library search path for
if self
.distribution
.has_c_libraries():
build_clib
= self
.get_finalized_command('build_clib')
self
.libraries
.extend(build_clib
.get_library_names() or [])
self
.library_dirs
.append(build_clib
.build_clib
)
# Setup the CCompiler object that we'll use to do all the
self
.compiler
= new_compiler(compiler
=self
.compiler
,
customize_compiler(self
.compiler
)
# And make sure that any compile/link-related options (which might
# come from the command-line or from the setup script) are set in
# that CCompiler object -- that way, they automatically apply to
# all compiling and linking done here.
if self
.include_dirs
is not None:
self
.compiler
.set_include_dirs(self
.include_dirs
)
if self
.define
is not None:
# 'define' option is a list of (name,value) tuples
for (name
,value
) in self
.define
:
self
.compiler
.define_macro(name
, value
)
if self
.undef
is not None:
self
.compiler
.undefine_macro(macro
)
if self
.libraries
is not None:
self
.compiler
.set_libraries(self
.libraries
)
if self
.library_dirs
is not None:
self
.compiler
.set_library_dirs(self
.library_dirs
)
if self
.rpath
is not None:
self
.compiler
.set_runtime_library_dirs(self
.rpath
)
if self
.link_objects
is not None:
self
.compiler
.set_link_objects(self
.link_objects
)
# Now actually compile and link everything.
def check_extensions_list (self
, extensions
):
"""Ensure that the list of extensions (presumably provided as a
command option 'extensions') is valid, i.e. it is a list of
Extension objects. We also support the old-style list of 2-tuples,
where the tuples are (ext_name, build_info), which are converted to
Extension instances here.
Raise DistutilsSetupError if the structure is invalid anywhere;
if type(extensions
) is not ListType
:
raise DistutilsSetupError
, \
"'ext_modules' option must be a list of Extension instances"
for i
in range(len(extensions
)):
if isinstance(ext
, Extension
):
continue # OK! (assume type-checking done
# by Extension constructor)
(ext_name
, build_info
) = ext
log
.warn(("old-style (ext_name, build_info) tuple found in "
"ext_modules for extension '%s'"
"-- please convert to Extension instance" % ext_name
))
if type(ext
) is not TupleType
and len(ext
) != 2:
raise DistutilsSetupError
, \
("each element of 'ext_modules' option must be an "
"Extension instance or 2-tuple")
if not (type(ext_name
) is StringType
and
extension_name_re
.match(ext_name
)):
raise DistutilsSetupError
, \
("first element of each tuple in 'ext_modules' "
"must be the extension name (a string)")
if type(build_info
) is not DictionaryType
:
raise DistutilsSetupError
, \
("second element of each tuple in 'ext_modules' "
"must be a dictionary (build info)")
# OK, the (ext_name, build_info) dict is type-safe: convert it
# to an Extension instance.
ext
= Extension(ext_name
, build_info
['sources'])
# Easy stuff: one-to-one mapping from dict elements to
for key
in ('include_dirs',
val
= build_info
.get(key
)
# Medium-easy stuff: same syntax/semantics, different names.
ext
.runtime_library_dirs
= build_info
.get('rpath')
if build_info
.has_key('def_file'):
log
.warn("'def_file' element of build info dict "
# Non-trivial stuff: 'macros' split into 'define_macros'
macros
= build_info
.get('macros')
if not (type(macro
) is TupleType
and
raise DistutilsSetupError
, \
("'macros' element of build info dict "
ext
.undef_macros
.append(macro
[0])
ext
.define_macros
.append(macro
)
# check_extensions_list ()
def get_source_files (self
):
self
.check_extensions_list(self
.extensions
)
# Wouldn't it be neat if we knew the names of header files too...
for ext
in self
.extensions
:
filenames
.extend(ext
.sources
)
# Sanity check the 'extensions' list -- can't assume this is being
# done in the same run as a 'build_extensions()' call (in fact, we
# can probably assume that it *isn't*!).
self
.check_extensions_list(self
.extensions
)
# And build the list of output (built) filenames. Note that this
# ignores the 'inplace' flag, and assumes everything goes in the
for ext
in self
.extensions
:
fullname
= self
.get_ext_fullname(ext
.name
)
outputs
.append(os
.path
.join(self
.build_lib
,
self
.get_ext_filename(fullname
)))
def build_extensions(self
):
# First, sanity-check the 'extensions' list
self
.check_extensions_list(self
.extensions
)
for ext
in self
.extensions
:
self
.build_extension(ext
)
def build_extension(self
, ext
):
if sources
is None or type(sources
) not in (ListType
, TupleType
):
raise DistutilsSetupError
, \
("in 'ext_modules' option (extension '%s'), " +
"'sources' must be present and must be " +
"a list of source filenames") % ext
.name
fullname
= self
.get_ext_fullname(ext
.name
)
# ignore build-lib -- put the compiled extension into
# the source tree along with pure Python modules
modpath
= string
.split(fullname
, '.')
package
= string
.join(modpath
[0:-1], '.')
build_py
= self
.get_finalized_command('build_py')
package_dir
= build_py
.get_package_dir(package
)
ext_filename
= os
.path
.join(package_dir
,
self
.get_ext_filename(base
))
ext_filename
= os
.path
.join(self
.build_lib
,
self
.get_ext_filename(fullname
))
depends
= sources
+ ext
.depends
if not (self
.force
or newer_group(depends
, ext_filename
, 'newer')):
log
.debug("skipping '%s' extension (up-to-date)", ext
.name
)
log
.info("building '%s' extension", ext
.name
)
# First, scan the sources for SWIG definition files (.i), run
# SWIG on 'em to create .c files, and modify the sources list
sources
= self
.swig_sources(sources
, ext
)
# Next, compile the source code to object files.
# XXX not honouring 'define_macros' or 'undef_macros' -- the
# CCompiler API needs to change to accommodate this, and I
# want to do one thing at a time!
# Two possible sources for extra compiler arguments:
# - 'extra_compile_args' in Extension object
# - CFLAGS environment variable (not particularly
# elegant, but people seem to expect it and I
# The environment variable should take precedence, and
# any sensible compiler will give precedence to later
# command line args. Hence we combine them in order:
extra_args
= ext
.extra_compile_args
or []
macros
= ext
.define_macros
[:]
for undef
in ext
.undef_macros
:
objects
= self
.compiler
.compile(sources
,
output_dir
=self
.build_temp
,
include_dirs
=ext
.include_dirs
,
extra_postargs
=extra_args
,
# XXX -- this is a Vile HACK!
# The setup.py script for Python on Unix needs to be able to
# get this list so it can perform all the clean up needed to
# avoid keeping object files around when cleaning out a failed
# build of an extension module. Since Distutils does not
# track dependencies, we have to get rid of intermediates to
# ensure all the intermediates will be properly re-built.
self
._built
_objects
= objects
[:]
# Now link the object files together into a "shared object" --
# of course, first we have to figure out all the other things
objects
.extend(ext
.extra_objects
)
extra_args
= ext
.extra_link_args
or []
# Detect target language, if not provided
language
= ext
.language
or self
.compiler
.detect_language(sources
)
self
.compiler
.link_shared_object(
libraries
=self
.get_libraries(ext
),
library_dirs
=ext
.library_dirs
,
runtime_library_dirs
=ext
.runtime_library_dirs
,
extra_postargs
=extra_args
,
export_symbols
=self
.get_export_symbols(ext
),
build_temp
=self
.build_temp
,
def swig_sources (self
, sources
, extension
):
"""Walk the list of source files in 'sources', looking for SWIG
interface (.i) files. Run SWIG on all that are found, and
return a modified 'sources' list with SWIG source files replaced
by the generated C (or C++) files.
# XXX this drops generated C/C++ files into the source tree, which
# is fine for developers who want to distribute the generated
# source -- but there should be an option to put SWIG output in
log
.warn("--swig-cpp is deprecated - use --swig-opts=-c++")
if self
.swig_cpp
or ('-c++' in self
.swig_opts
):
(base
, ext
) = os
.path
.splitext(source
)
if ext
== ".i": # SWIG interface file
new_sources
.append(base
+ '_wrap' + target_ext
)
swig_sources
.append(source
)
swig_targets
[source
] = new_sources
[-1]
new_sources
.append(source
)
swig
= self
.swig
or self
.find_swig()
swig_cmd
= [swig
, "-python"]
swig_cmd
.extend(self
.swig_opts
)
# Do not override commandline arguments
for o
in extension
.swig_opts
:
for source
in swig_sources
:
target
= swig_targets
[source
]
log
.info("swigging %s to %s", source
, target
)
self
.spawn(swig_cmd
+ ["-o", target
, source
])
"""Return the name of the SWIG executable. On Unix, this is
just "swig" -- it should be in the PATH. Tries a bit harder on
# Look for SWIG in its standard installation directory on
# Windows (or so I presume!). If we find it there, great;
# if not, act like Unix and assume it's in the PATH.
for vers
in ("1.3", "1.2", "1.1"):
fn
= os
.path
.join("c:\\swig%s" % vers
, "swig.exe")
# assume swig available in the PATH.
raise DistutilsPlatformError
, \
("I don't know how to find (much less run) SWIG "
"on platform '%s'") % os
.name
# -- Name generators -----------------------------------------------
# (extension names, filenames, whatever)
def get_ext_fullname (self
, ext_name
):
return self
.package
+ '.' + ext_name
def get_ext_filename (self
, ext_name
):
r
"""Convert the name of an extension (eg. "foo.bar") into the name
of the file from which it will be loaded (eg. "foo/bar.so", or
from distutils
.sysconfig
import get_config_var
ext_path
= string
.split(ext_name
, '.')
# OS/2 has an 8 character module (extension) limit :-(
ext_path
[len(ext_path
) - 1] = ext_path
[len(ext_path
) - 1][:8]
# extensions in debug_mode are named 'module_d.pyd' under windows
so_ext
= get_config_var('SO')
if os
.name
== 'nt' and self
.debug
:
return apply(os
.path
.join
, ext_path
) + '_d' + so_ext
return apply(os
.path
.join
, ext_path
) + so_ext
def get_export_symbols (self
, ext
):
"""Return the list of symbols that a shared extension has to
export. This either uses 'ext.export_symbols' or, if it's not
provided, "init" + module_name. Only relevant on Windows, where
the .pyd file (DLL) must export the module "init" function.
initfunc_name
= "init" + string
.split(ext
.name
,'.')[-1]
if initfunc_name
not in ext
.export_symbols
:
ext
.export_symbols
.append(initfunc_name
)
return ext
.export_symbols
def get_libraries (self
, ext
):
"""Return the list of libraries to link against when building a
shared extension. On most platforms, this is just 'ext.libraries';
on Windows and OS/2, we add the Python library (eg. python20.dll).
# The python library is always needed on Windows. For MSVC, this
# is redundant, since the library is mentioned in a pragma in
# pyconfig.h that MSVC groks. The other Windows compilers all seem
# to need it mentioned explicitly, though, so that's what we do.
# Append '_d' to the python import library on debug builds.
if sys
.platform
== "win32":
from distutils
.msvccompiler
import MSVCCompiler
if not isinstance(self
.compiler
, MSVCCompiler
):
template
= template
+ '_d'
(sys
.hexversion
>> 24, (sys
.hexversion
>> 16) & 0xff))
# don't extend ext.libraries, it may be shared with other
# extensions, it is a reference to the original list
return ext
.libraries
+ [pythonlib
]
elif sys
.platform
== "os2emx":
# EMX/GCC requires the python library explicitly, and I
# believe VACPP does as well (though not confirmed) - AIM Apr01
# debug versions of the main DLL aren't supported, at least
# not at this time - AIM Apr01
# template = template + '_d'
(sys
.hexversion
>> 24, (sys
.hexversion
>> 16) & 0xff))
# don't extend ext.libraries, it may be shared with other
# extensions, it is a reference to the original list
return ext
.libraries
+ [pythonlib
]
elif sys
.platform
[:6] == "cygwin":
(sys
.hexversion
>> 24, (sys
.hexversion
>> 16) & 0xff))
# don't extend ext.libraries, it may be shared with other
# extensions, it is a reference to the original list
return ext
.libraries
+ [pythonlib
]
elif sys
.platform
[:6] == "atheos":
from distutils
import sysconfig
(sys
.hexversion
>> 24, (sys
.hexversion
>> 16) & 0xff))
# Get SHLIBS from Makefile
for lib
in sysconfig
.get_config_var('SHLIBS').split():
# don't extend ext.libraries, it may be shared with other
# extensions, it is a reference to the original list
return ext
.libraries
+ [pythonlib
, "m"] + extra