reverting partially distutils to its 2.6.x state so 2.7a4 looks more like the 2.7b1 in this. the whole revert will occur after a4 is tagged

This commit is contained in:
Tarek Ziadé 2010-03-05 00:16:02 +00:00
parent ab5e17f896
commit dd7bef9bf5
14 changed files with 1156 additions and 1233 deletions

View File

@ -4,27 +4,21 @@ Implements the Distutils 'build_ext' command, for building extension
modules (currently limited to C extensions, should accommodate C++
extensions ASAP)."""
# This module should be kept compatible with Python 2.1.
__revision__ = "$Id$"
import sys, os, re
from warnings import warn
from distutils.util import get_platform
import sys, os, string, re
from types import *
from site import USER_BASE, USER_SITE
from distutils.core import Command
from distutils.errors import *
from distutils.ccompiler import customize_compiler
from distutils.sysconfig import customize_compiler, get_python_version
from distutils.dep_util import newer_group
from distutils.extension import Extension
from distutils.util import get_platform
from distutils import log
# this keeps compatibility from 2.3 to 2.5
if sys.version < "2.6":
USER_BASE = None
HAS_USER_SITE = False
else:
from site import USER_BASE
HAS_USER_SITE = True
if os.name == 'nt':
from distutils.msvccompiler import get_build_version
MSVC_VERSION = int(get_build_version())
@ -40,7 +34,7 @@ def show_compilers ():
show_compilers()
class build_ext(Command):
class build_ext (Command):
description = "build C/C++ extensions (compile/link to build directory)"
@ -100,55 +94,18 @@ class build_ext(Command):
"list of SWIG command line options"),
('swig=', None,
"path to the SWIG executable"),
('user', None,
"add user include, library and rpath"),
]
boolean_options = ['inplace', 'debug', 'force', 'swig-cpp']
if HAS_USER_SITE:
user_options.append(('user', None,
"add user include, library and rpath"))
boolean_options.append('user')
boolean_options = ['inplace', 'debug', 'force', 'swig-cpp', 'user']
help_options = [
('help-compiler', None,
"list available compilers", show_compilers),
]
# making 'compiler' a property to deprecate
# its usage as something else than a compiler type
# e.g. like a compiler instance
def __init__(self, dist):
self._compiler = None
Command.__init__(self, dist)
def __setattr__(self, name, value):
# need this to make sure setattr() (used in distutils)
# doesn't kill our property
if name == 'compiler':
self._set_compiler(value)
else:
self.__dict__[name] = value
def _set_compiler(self, compiler):
if not isinstance(compiler, str) and compiler is not None:
# we don't want to allow that anymore in the future
warn("'compiler' specifies the compiler type in build_ext. "
"If you want to get the compiler object itself, "
"use 'compiler_obj'", DeprecationWarning)
self._compiler = compiler
def _get_compiler(self):
if not isinstance(self._compiler, str) and self._compiler is not None:
# we don't want to allow that anymore in the future
warn("'compiler' specifies the compiler type in build_ext. "
"If you want to get the compiler object itself, "
"use 'compiler_obj'", DeprecationWarning)
return self._compiler
compiler = property(_get_compiler, _set_compiler)
def initialize_options(self):
def initialize_options (self):
self.extensions = None
self.build_lib = None
self.plat_name = None
@ -172,7 +129,8 @@ class build_ext(Command):
self.user = None
def finalize_options(self):
_sysconfig = __import__('sysconfig')
from distutils import sysconfig
self.set_undefined_options('build',
('build_lib', 'build_lib'),
('build_temp', 'build_temp'),
@ -189,8 +147,8 @@ class build_ext(Command):
# Make sure Python's include directories (for Python.h, pyconfig.h,
# etc.) are in the include search path.
py_include = _sysconfig.get_path('include')
plat_py_include = _sysconfig.get_path('platinclude')
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 isinstance(self.include_dirs, str):
@ -211,13 +169,13 @@ class build_ext(Command):
self.libraries = []
if self.library_dirs is None:
self.library_dirs = []
elif isinstance(self.library_dirs, str):
self.library_dirs = self.library_dirs.split(os.pathsep)
elif type(self.library_dirs) is StringType:
self.library_dirs = string.split(self.library_dirs, os.pathsep)
if self.rpath is None:
self.rpath = []
elif isinstance(self.rpath, str):
self.rpath = self.rpath.split(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.
@ -268,7 +226,7 @@ class build_ext(Command):
if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")):
# building third party extensions
self.library_dirs.append(os.path.join(sys.prefix, "lib",
"python" + _sysconfig.get_python_version(),
"python" + get_python_version(),
"config"))
else:
# building python standard extensions
@ -276,13 +234,13 @@ class build_ext(Command):
# for extensions under Linux or Solaris with a shared Python library,
# Python's library directory must be appended to library_dirs
_sysconfig.get_config_var('Py_ENABLE_SHARED')
sysconfig.get_config_var('Py_ENABLE_SHARED')
if ((sys.platform.startswith('linux') or sys.platform.startswith('gnu')
or sys.platform.startswith('sunos'))
and _sysconfig.get_config_var('Py_ENABLE_SHARED')):
and sysconfig.get_config_var('Py_ENABLE_SHARED')):
if sys.executable.startswith(os.path.join(sys.exec_prefix, "bin")):
# building third party extensions
self.library_dirs.append(_sysconfig.get_config_var('LIBDIR'))
self.library_dirs.append(sysconfig.get_config_var('LIBDIR'))
else:
# building python standard extensions
self.library_dirs.append('.')
@ -294,7 +252,7 @@ class build_ext(Command):
if self.define:
defines = self.define.split(',')
self.define = [(symbol, '1') for symbol in defines]
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
@ -345,50 +303,38 @@ class build_ext(Command):
# Setup the CCompiler object that we'll use to do all the
# compiling and linking
# used to prevent the usage of an existing compiler for the
# compiler option when calling new_compiler()
# this will be removed in 3.3 and 2.8
if not isinstance(self._compiler, str):
self._compiler = None
self.compiler_obj = new_compiler(compiler=self._compiler,
verbose=self.verbose,
dry_run=self.dry_run,
force=self.force)
# used to keep the compiler object reachable with
# "self.compiler". this will be removed in 3.3 and 2.8
self._compiler = self.compiler_obj
customize_compiler(self.compiler_obj)
self.compiler = new_compiler(compiler=self.compiler,
verbose=self.verbose,
dry_run=self.dry_run,
force=self.force)
customize_compiler(self.compiler)
# If we are cross-compiling, init the compiler now (if we are not
# cross-compiling, init would not hurt, but people may rely on
# late initialization of compiler even if they shouldn't...)
if os.name == 'nt' and self.plat_name != get_platform():
self.compiler_obj.initialize(self.plat_name)
self.compiler.initialize(self.plat_name)
# 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_obj.set_include_dirs(self.include_dirs)
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_obj.define_macro(name, value)
self.compiler.define_macro(name, value)
if self.undef is not None:
for macro in self.undef:
self.compiler_obj.undefine_macro(macro)
self.compiler.undefine_macro(macro)
if self.libraries is not None:
self.compiler_obj.set_libraries(self.libraries)
self.compiler.set_libraries(self.libraries)
if self.library_dirs is not None:
self.compiler_obj.set_library_dirs(self.library_dirs)
self.compiler.set_library_dirs(self.library_dirs)
if self.rpath is not None:
self.compiler_obj.set_runtime_library_dirs(self.rpath)
self.compiler.set_runtime_library_dirs(self.rpath)
if self.link_objects is not None:
self.compiler_obj.set_link_objects(self.link_objects)
self.compiler.set_link_objects(self.link_objects)
# Now actually compile and link everything.
self.build_extensions()
@ -500,17 +446,11 @@ class build_ext(Command):
self.check_extensions_list(self.extensions)
for ext in self.extensions:
try:
self.build_extension(ext)
except (CCompilerError, DistutilsError, CompileError), e:
if not ext.optional:
raise
self.warn('building extension "%s" failed: %s' %
(ext.name, e))
self.build_extension(ext)
def build_extension(self, ext):
sources = ext.sources
if sources is None or not isinstance(sources, (list, tuple)):
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 " +
@ -550,13 +490,13 @@ class build_ext(Command):
for undef in ext.undef_macros:
macros.append((undef,))
objects = self.compiler_obj.compile(sources,
output_dir=self.build_temp,
macros=macros,
include_dirs=ext.include_dirs,
debug=self.debug,
extra_postargs=extra_args,
depends=ext.depends)
objects = self.compiler.compile(sources,
output_dir=self.build_temp,
macros=macros,
include_dirs=ext.include_dirs,
debug=self.debug,
extra_postargs=extra_args,
depends=ext.depends)
# XXX -- this is a Vile HACK!
#
@ -577,9 +517,9 @@ class build_ext(Command):
extra_args = ext.extra_link_args or []
# Detect target language, if not provided
language = ext.language or self.compiler_obj.detect_language(sources)
language = ext.language or self.compiler.detect_language(sources)
self.compiler_obj.link_shared_object(
self.compiler.link_shared_object(
objects, ext_path,
libraries=self.get_libraries(ext),
library_dirs=ext.library_dirs,
@ -591,12 +531,14 @@ class build_ext(Command):
target_lang=language)
def swig_sources(self, sources, extension):
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.
"""
new_sources = []
swig_sources = []
swig_targets = {}
@ -645,7 +587,9 @@ class build_ext(Command):
return new_sources
def find_swig(self):
# swig_sources ()
def find_swig (self):
"""Return the name of the SWIG executable. On Unix, this is
just "swig" -- it should be in the PATH. Tries a bit harder on
Windows.
@ -674,6 +618,8 @@ class build_ext(Command):
("I don't know how to find (much less run) SWIG "
"on platform '%s'") % os.name
# find_swig ()
# -- Name generators -----------------------------------------------
# (extension names, filenames, whatever)
def get_ext_fullpath(self, ext_name):
@ -682,9 +628,14 @@ class build_ext(Command):
The file is located in `build_lib` or directly in the package
(inplace option).
"""
# makes sure the extension name is only using dots
all_dots = string.maketrans('/'+os.sep, '..')
ext_name = ext_name.translate(all_dots)
fullname = self.get_ext_fullname(ext_name)
modpath = fullname.split('.')
filename = self.get_ext_filename(modpath[-1])
filename = self.get_ext_filename(ext_name)
filename = os.path.split(filename)[-1]
if not self.inplace:
# no further work needed
@ -717,18 +668,18 @@ class build_ext(Command):
of the file from which it will be loaded (eg. "foo/bar.so", or
"foo\bar.pyd").
"""
_sysconfig = __import__('sysconfig')
ext_path = ext_name.split('.')
from distutils.sysconfig import get_config_var
ext_path = string.split(ext_name, '.')
# OS/2 has an 8 character module (extension) limit :-(
if os.name == "os2":
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 = _sysconfig.get_config_var('SO')
so_ext = get_config_var('SO')
if os.name == 'nt' and self.debug:
return os.path.join(*ext_path) + '_d' + so_ext
return apply(os.path.join, ext_path) + '_d' + so_ext
return os.path.join(*ext_path) + so_ext
def get_export_symbols(self, 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
@ -739,7 +690,7 @@ class build_ext(Command):
ext.export_symbols.append(initfunc_name)
return ext.export_symbols
def get_libraries(self, ext):
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).
@ -751,7 +702,7 @@ class build_ext(Command):
# Append '_d' to the python import library on debug builds.
if sys.platform == "win32":
from distutils.msvccompiler import MSVCCompiler
if not isinstance(self.compiler_obj, MSVCCompiler):
if not isinstance(self.compiler, MSVCCompiler):
template = "python%d%d"
if self.debug:
template = template + '_d'
@ -783,13 +734,14 @@ class build_ext(Command):
# extensions, it is a reference to the original list
return ext.libraries + [pythonlib]
elif sys.platform[:6] == "atheos":
_sysconfig = __import__('sysconfig')
from distutils import sysconfig
template = "python%d.%d"
pythonlib = (template %
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
# Get SHLIBS from Makefile
extra = []
for lib in _sysconfig.get_config_var('SHLIBS').split():
for lib in sysconfig.get_config_var('SHLIBS').split():
if lib.startswith('-l'):
extra.append(lib[2:])
else:
@ -803,11 +755,13 @@ class build_ext(Command):
return ext.libraries
else:
_sysconfig = __import__('sysconfig')
if _sysconfig.get_config_var('Py_ENABLE_SHARED'):
from distutils import sysconfig
if sysconfig.get_config_var('Py_ENABLE_SHARED'):
template = "python%d.%d"
pythonlib = (template %
(sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff))
return ext.libraries + [pythonlib]
else:
return ext.libraries
# class build_ext

View File

@ -2,22 +2,26 @@
Implements the Distutils 'install' command."""
from distutils import log
# This module should be kept compatible with Python 2.1.
__revision__ = "$Id$"
import sys
import os
from sysconfig import get_config_vars, get_paths, get_path, get_config_var
from distutils import log
import sys, os, string
from types import *
from distutils.core import Command
from distutils.debug import DEBUG
from distutils.sysconfig import get_config_vars
from distutils.errors import DistutilsPlatformError
from distutils.file_util import write_file
from distutils.util import convert_path, change_root, get_platform
from distutils.util import convert_path, subst_vars, change_root
from distutils.util import get_platform
from distutils.errors import DistutilsOptionError
from site import USER_BASE
from site import USER_SITE
# kept for backward compat, will be removed in 3.2
if sys.version < "2.2":
WINDOWS_SCHEME = {
'purelib': '$base',
@ -95,19 +99,13 @@ INSTALL_SCHEMES = {
},
}
# The keys to an installation scheme; if any new types of files are to be
# installed, be sure to add an entry to every installation scheme above,
# and to SCHEME_KEYS here.
SCHEME_KEYS = ('purelib', 'platlib', 'headers', 'scripts', 'data')
# end of backward compat
def _subst_vars(s, local_vars):
try:
return s.format(**local_vars)
except KeyError:
try:
return s.format(**os.environ)
except KeyError, var:
raise AttributeError('{%s}' % var)
class install(Command):
class install (Command):
description = "install everything from build directory"
@ -119,6 +117,8 @@ class install(Command):
"(Unix only) prefix for platform-specific files"),
('home=', None,
"(Unix only) home directory to install under"),
('user', None,
"install in user site-package '%s'" % USER_SITE),
# Or, just set the base director(y|ies)
('install-base=', None,
@ -170,17 +170,12 @@ class install(Command):
"filename in which to record list of installed files"),
]
boolean_options = ['compile', 'force', 'skip-build']
user_options.append(('user', None,
"install in user site-package '%s'" % \
get_path('purelib', '%s_user' % os.name)))
boolean_options.append('user')
boolean_options = ['compile', 'force', 'skip-build', 'user']
negative_opt = {'no-compile' : 'compile'}
def initialize_options(self):
"""Initializes options."""
def initialize_options (self):
# High-level options: these select both an installation base
# and scheme.
self.prefix = None
@ -205,8 +200,8 @@ class install(Command):
self.install_lib = None # set to either purelib or platlib
self.install_scripts = None
self.install_data = None
self.install_userbase = get_config_var('userbase')
self.install_usersite = get_path('purelib', '%s_user' % os.name)
self.install_userbase = USER_BASE
self.install_usersite = USER_SITE
self.compile = None
self.optimize = None
@ -256,8 +251,8 @@ class install(Command):
# party Python modules on various platforms given a wide
# array of user input is decided. Yes, it's quite complex!)
def finalize_options(self):
"""Finalizes options."""
def finalize_options (self):
# This method (and its pliant slaves, like 'finalize_unix()',
# 'finalize_other()', and 'select_scheme()') is where the default
# installation directories for modules, extension modules, and
@ -315,10 +310,8 @@ class install(Command):
# $platbase in the other installation directories and not worry
# about needing recursive variable expansion (shudder).
py_version = sys.version.split()[0]
prefix, exec_prefix, srcdir = get_config_vars('prefix', 'exec_prefix',
'srcdir')
py_version = (string.split(sys.version))[0]
(prefix, exec_prefix) = get_config_vars('prefix', 'exec_prefix')
self.config_vars = {'dist_name': self.distribution.get_name(),
'dist_version': self.distribution.get_version(),
'dist_fullname': self.distribution.get_fullname(),
@ -329,11 +322,9 @@ class install(Command):
'prefix': prefix,
'sys_exec_prefix': exec_prefix,
'exec_prefix': exec_prefix,
'srcdir': srcdir,
'userbase': self.install_userbase,
'usersite': self.install_usersite,
}
self.config_vars['userbase'] = self.install_userbase
self.config_vars['usersite'] = self.install_usersite
self.expand_basedirs()
self.dump_dirs("post-expand_basedirs()")
@ -399,27 +390,29 @@ class install(Command):
# Punt on doc directories for now -- after all, we're punting on
# documentation completely!
def dump_dirs(self, msg):
"""Dumps the list of user options."""
if not DEBUG:
return
from distutils.fancy_getopt import longopt_xlate
log.debug(msg + ":")
for opt in self.user_options:
opt_name = opt[0]
if opt_name[-1] == "=":
opt_name = opt_name[0:-1]
if opt_name in self.negative_opt:
opt_name = self.negative_opt[opt_name]
opt_name = opt_name.translate(longopt_xlate)
val = not getattr(self, opt_name)
else:
opt_name = opt_name.translate(longopt_xlate)
val = getattr(self, opt_name)
log.debug(" %s: %s" % (opt_name, val))
# finalize_options ()
def dump_dirs (self, msg):
if DEBUG:
from distutils.fancy_getopt import longopt_xlate
print msg + ":"
for opt in self.user_options:
opt_name = opt[0]
if opt_name[-1] == "=":
opt_name = opt_name[0:-1]
if opt_name in self.negative_opt:
opt_name = string.translate(self.negative_opt[opt_name],
longopt_xlate)
val = not getattr(self, opt_name)
else:
opt_name = string.translate(opt_name, longopt_xlate)
val = getattr(self, opt_name)
print " %s: %s" % (opt_name, val)
def finalize_unix (self):
def finalize_unix(self):
"""Finalizes options for posix platforms."""
if self.install_base is not None or self.install_platbase is not None:
if ((self.install_lib is None and
self.install_purelib is None and
@ -437,10 +430,10 @@ class install(Command):
raise DistutilsPlatformError(
"User base directory is not specified")
self.install_base = self.install_platbase = self.install_userbase
self.select_scheme("posix_user")
self.select_scheme("unix_user")
elif self.home is not None:
self.install_base = self.install_platbase = self.home
self.select_scheme("posix_home")
self.select_scheme("unix_home")
else:
if self.prefix is None:
if self.exec_prefix is not None:
@ -456,10 +449,13 @@ class install(Command):
self.install_base = self.prefix
self.install_platbase = self.exec_prefix
self.select_scheme("posix_prefix")
self.select_scheme("unix_prefix")
# finalize_unix ()
def finalize_other (self): # Windows and Mac OS for now
def finalize_other(self):
"""Finalizes options for non-posix platforms"""
if self.user:
if self.install_userbase is None:
raise DistutilsPlatformError(
@ -468,7 +464,7 @@ class install(Command):
self.select_scheme(os.name + "_user")
elif self.home is not None:
self.install_base = self.install_platbase = self.home
self.select_scheme("posix_home")
self.select_scheme("unix_home")
else:
if self.prefix is None:
self.prefix = os.path.normpath(sys.prefix)
@ -480,58 +476,61 @@ class install(Command):
raise DistutilsPlatformError, \
"I don't know how to install stuff on '%s'" % os.name
def select_scheme(self, name):
"""Sets the install directories by applying the install schemes."""
# it's the caller's problem if they supply a bad name!
scheme = get_paths(name, expand=False)
for key, value in scheme.items():
if key == 'platinclude':
key = 'headers'
value = os.path.join(value, self.distribution.get_name())
attrname = 'install_' + key
if hasattr(self, attrname):
if getattr(self, attrname) is None:
setattr(self, attrname, value)
# finalize_other ()
def _expand_attrs(self, attrs):
def select_scheme (self, name):
# it's the caller's problem if they supply a bad name!
scheme = INSTALL_SCHEMES[name]
for key in SCHEME_KEYS:
attrname = 'install_' + key
if getattr(self, attrname) is None:
setattr(self, attrname, scheme[key])
def _expand_attrs (self, attrs):
for attr in attrs:
val = getattr(self, attr)
if val is not None:
if os.name == 'posix' or os.name == 'nt':
val = os.path.expanduser(val)
val = _subst_vars(val, self.config_vars)
val = subst_vars(val, self.config_vars)
setattr(self, attr, val)
def expand_basedirs(self):
"""Calls `os.path.expanduser` on install_base, install_platbase and
root."""
self._expand_attrs(['install_base', 'install_platbase', 'root'])
def expand_dirs(self):
"""Calls `os.path.expanduser` on install dirs."""
self._expand_attrs(['install_purelib', 'install_platlib',
'install_lib', 'install_headers',
'install_scripts', 'install_data',])
def expand_basedirs (self):
self._expand_attrs(['install_base',
'install_platbase',
'root'])
def convert_paths(self, *names):
"""Call `convert_path` over `names`."""
def expand_dirs (self):
self._expand_attrs(['install_purelib',
'install_platlib',
'install_lib',
'install_headers',
'install_scripts',
'install_data',])
def convert_paths (self, *names):
for name in names:
attr = "install_" + name
setattr(self, attr, convert_path(getattr(self, attr)))
def handle_extra_path(self):
"""Set `path_file` and `extra_dirs` using `extra_path`."""
def handle_extra_path (self):
if self.extra_path is None:
self.extra_path = self.distribution.extra_path
if self.extra_path is not None:
if isinstance(self.extra_path, str):
self.extra_path = self.extra_path.split(',')
if type(self.extra_path) is StringType:
self.extra_path = string.split(self.extra_path, ',')
if len(self.extra_path) == 1:
path_file = extra_dirs = self.extra_path[0]
elif len(self.extra_path) == 2:
path_file, extra_dirs = self.extra_path
(path_file, extra_dirs) = self.extra_path
else:
raise DistutilsOptionError, \
("'extra_path' option must be a list, tuple, or "
@ -540,6 +539,7 @@ class install(Command):
# convert to local form in case Unix notation used (as it
# should be in setup scripts)
extra_dirs = convert_path(extra_dirs)
else:
path_file = None
extra_dirs = ''
@ -549,14 +549,17 @@ class install(Command):
self.path_file = path_file
self.extra_dirs = extra_dirs
def change_roots(self, *names):
"""Change the install direcories pointed by name using root."""
# handle_extra_path ()
def change_roots (self, *names):
for name in names:
attr = "install_" + name
setattr(self, attr, change_root(self.root, getattr(self, attr)))
def create_home_path(self):
"""Create directories under ~."""
"""Create directories under ~
"""
if not self.user:
return
home = convert_path(os.path.expanduser("~"))
@ -567,8 +570,8 @@ class install(Command):
# -- Command execution methods -------------------------------------
def run(self):
"""Runs the command."""
def run (self):
# Obviously have to build before we can install
if not self.skip_build:
self.run_command('build')
@ -611,8 +614,9 @@ class install(Command):
"you'll have to change the search path yourself"),
self.install_lib)
def create_path_file(self):
"""Creates the .pth file"""
# run ()
def create_path_file (self):
filename = os.path.join(self.install_libbase,
self.path_file + ".pth")
if self.install_path_file:
@ -625,8 +629,8 @@ class install(Command):
# -- Reporting methods ---------------------------------------------
def get_outputs(self):
"""Assembles the outputs of all the sub-commands."""
def get_outputs (self):
# Assemble the outputs of all the sub-commands.
outputs = []
for cmd_name in self.get_sub_commands():
cmd = self.get_finalized_command(cmd_name)
@ -642,8 +646,7 @@ class install(Command):
return outputs
def get_inputs(self):
"""Returns the inputs of all the sub-commands"""
def get_inputs (self):
# XXX gee, this looks familiar ;-(
inputs = []
for cmd_name in self.get_sub_commands():
@ -652,29 +655,25 @@ class install(Command):
return inputs
# -- Predicates for sub-command list -------------------------------
def has_lib(self):
"""Returns true if the current distribution has any Python
def has_lib (self):
"""Return true if the current distribution has any Python
modules to install."""
return (self.distribution.has_pure_modules() or
self.distribution.has_ext_modules())
def has_headers(self):
"""Returns true if the current distribution has any headers to
install."""
def has_headers (self):
return self.distribution.has_headers()
def has_scripts(self):
"""Returns true if the current distribution has any scripts to.
install."""
def has_scripts (self):
return self.distribution.has_scripts()
def has_data(self):
"""Returns true if the current distribution has any data to.
install."""
def has_data (self):
return self.distribution.has_data_files()
# 'sub_commands': a list of commands this command might have to run to
# get its work done. See cmd.py for more info.
sub_commands = [('install_lib', has_lib),
@ -683,3 +682,5 @@ class install(Command):
('install_data', has_data),
('install_egg_info', lambda self:True),
]
# class install

View File

@ -45,18 +45,16 @@ cygwin in no-cygwin mode).
# * mingw gcc 3.2/ld 2.13 works
# (ld supports -shared)
# This module should be kept compatible with Python 2.1.
__revision__ = "$Id$"
import os
import sys
import copy
import re
from warnings import warn
import os,sys,copy
from distutils.ccompiler import gen_preprocess_options, gen_lib_options
from distutils.unixccompiler import UnixCCompiler
from distutils.file_util import write_file
from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
from distutils.util import get_compiler_versions
from distutils import log
def get_msvcr():
"""Include the appropriate MSVC runtime library if Python was built
@ -81,9 +79,8 @@ def get_msvcr():
raise ValueError("Unknown MS Compiler version %s " % msc_ver)
class CygwinCCompiler(UnixCCompiler):
""" Handles the Cygwin port of the GNU C compiler to Windows.
"""
class CygwinCCompiler (UnixCCompiler):
compiler_type = 'cygwin'
obj_extension = ".o"
static_lib_extension = ".a"
@ -92,11 +89,11 @@ class CygwinCCompiler(UnixCCompiler):
shared_lib_format = "%s%s"
exe_extension = ".exe"
def __init__(self, verbose=0, dry_run=0, force=0):
def __init__ (self, verbose=0, dry_run=0, force=0):
UnixCCompiler.__init__(self, verbose, dry_run, force)
UnixCCompiler.__init__ (self, verbose, dry_run, force)
status, details = check_config_h()
(status, details) = check_config_h()
self.debug_print("Python's GCC status: %s (details: %s)" %
(status, details))
if status is not CONFIG_H_OK:
@ -107,7 +104,7 @@ class CygwinCCompiler(UnixCCompiler):
% details)
self.gcc_version, self.ld_version, self.dllwrap_version = \
get_compiler_versions()
get_versions()
self.debug_print(self.compiler_type + ": gcc %s, ld %s, dllwrap %s\n" %
(self.gcc_version,
self.ld_version,
@ -151,8 +148,10 @@ class CygwinCCompiler(UnixCCompiler):
# with MSVC 7.0 or later.
self.dll_libraries = get_msvcr()
# __init__ ()
def _compile(self, obj, src, ext, cc_args, extra_postargs, pp_opts):
"""Compiles the source by spawing GCC and windres if needed."""
if ext == '.rc' or ext == '.res':
# gcc needs '.res' and '.rc' compiled to object files !!!
try:
@ -166,11 +165,21 @@ class CygwinCCompiler(UnixCCompiler):
except DistutilsExecError, msg:
raise CompileError, msg
def link(self, target_desc, objects, output_filename, output_dir=None,
libraries=None, library_dirs=None, runtime_library_dirs=None,
export_symbols=None, debug=0, extra_preargs=None,
extra_postargs=None, build_temp=None, target_lang=None):
"""Link the objects."""
def link (self,
target_desc,
objects,
output_filename,
output_dir=None,
libraries=None,
library_dirs=None,
runtime_library_dirs=None,
export_symbols=None,
debug=0,
extra_preargs=None,
extra_postargs=None,
build_temp=None,
target_lang=None):
# use separate copies, so we can modify the lists
extra_preargs = copy.copy(extra_preargs or [])
libraries = copy.copy(libraries or [])
@ -235,44 +244,64 @@ class CygwinCCompiler(UnixCCompiler):
if not debug:
extra_preargs.append("-s")
UnixCCompiler.link(self, target_desc, objects, output_filename,
output_dir, libraries, library_dirs,
UnixCCompiler.link(self,
target_desc,
objects,
output_filename,
output_dir,
libraries,
library_dirs,
runtime_library_dirs,
None, # export_symbols, we do this in our def-file
debug, extra_preargs, extra_postargs, build_temp,
debug,
extra_preargs,
extra_postargs,
build_temp,
target_lang)
# link ()
# -- Miscellaneous methods -----------------------------------------
def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
"""Adds supports for rc and res files."""
if output_dir is None:
output_dir = ''
# overwrite the one from CCompiler to support rc and res-files
def object_filenames (self,
source_filenames,
strip_dir=0,
output_dir=''):
if output_dir is None: output_dir = ''
obj_names = []
for src_name in source_filenames:
# use normcase to make sure '.rc' is really '.rc' and not '.RC'
base, ext = os.path.splitext(os.path.normcase(src_name))
(base, ext) = os.path.splitext (os.path.normcase(src_name))
if ext not in (self.src_extensions + ['.rc','.res']):
raise UnknownFileError, \
"unknown file type '%s' (from '%s')" % (ext, src_name)
"unknown file type '%s' (from '%s')" % \
(ext, src_name)
if strip_dir:
base = os.path.basename (base)
if ext in ('.res', '.rc'):
if ext == '.res' or ext == '.rc':
# these need to be compiled to object files
obj_names.append (os.path.join(output_dir,
base + ext + self.obj_extension))
obj_names.append (os.path.join (output_dir,
base + ext + self.obj_extension))
else:
obj_names.append (os.path.join(output_dir,
base + self.obj_extension))
obj_names.append (os.path.join (output_dir,
base + self.obj_extension))
return obj_names
# object_filenames ()
# class CygwinCCompiler
# the same as cygwin plus some additional parameters
class Mingw32CCompiler(CygwinCCompiler):
""" Handles the Mingw32 port of the GNU C compiler to Windows.
"""
class Mingw32CCompiler (CygwinCCompiler):
compiler_type = 'mingw32'
def __init__(self, verbose=0, dry_run=0, force=0):
def __init__ (self,
verbose=0,
dry_run=0,
force=0):
CygwinCCompiler.__init__ (self, verbose, dry_run, force)
@ -308,6 +337,10 @@ class Mingw32CCompiler(CygwinCCompiler):
# with MSVC 7.0 or later.
self.dll_libraries = get_msvcr()
# __init__ ()
# class Mingw32CCompiler
# Because these compilers aren't configured in Python's pyconfig.h file by
# default, we should at least warn the user if he is using a unmodified
# version.
@ -317,16 +350,16 @@ CONFIG_H_NOTOK = "not ok"
CONFIG_H_UNCERTAIN = "uncertain"
def check_config_h():
"""Check if the current Python installation appears amenable to building
extensions with GCC.
Returns a tuple (status, details), where 'status' is one of the following
constants:
- CONFIG_H_OK: all is well, go ahead and compile
- CONFIG_H_NOTOK: doesn't look good
- CONFIG_H_UNCERTAIN: not sure -- unable to read pyconfig.h
"""Check if the current Python installation (specifically, pyconfig.h)
appears amenable to building extensions with GCC. Returns a tuple
(status, details), where 'status' is one of the following constants:
CONFIG_H_OK
all is well, go ahead and compile
CONFIG_H_NOTOK
doesn't look good
CONFIG_H_UNCERTAIN
not sure -- unable to read pyconfig.h
'details' is a human-readable string explaining the situation.
Note there are two ways to conclude "OK": either 'sys.version' contains
@ -337,45 +370,78 @@ def check_config_h():
# XXX since this function also checks sys.version, it's not strictly a
# "pyconfig.h" check -- should probably be renamed...
_sysconfig = __import__('sysconfig')
from distutils import sysconfig
import string
# if sys.version contains GCC then python was compiled with
# GCC, and the pyconfig.h file should be OK
if string.find(sys.version,"GCC") >= 0:
return (CONFIG_H_OK, "sys.version mentions 'GCC'")
# if sys.version contains GCC then python was compiled with GCC, and the
# pyconfig.h file should be OK
if "GCC" in sys.version:
return CONFIG_H_OK, "sys.version mentions 'GCC'"
# let's see if __GNUC__ is mentioned in python.h
fn = _sysconfig.get_config_h_filename()
fn = sysconfig.get_config_h_filename()
try:
with open(fn) as config_h:
if "__GNUC__" in config_h.read():
return CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn
else:
return CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn
# It would probably better to read single lines to search.
# But we do this only once, and it is fast enough
f = open(fn)
s = f.read()
f.close()
except IOError, exc:
# if we can't read this file, we cannot say it is wrong
# the compiler will complain later about this file as missing
return (CONFIG_H_UNCERTAIN,
"couldn't read '%s': %s" % (fn, exc.strerror))
class _Deprecated_SRE_Pattern(object):
def __init__(self, pattern):
self.pattern = pattern
else:
# "pyconfig.h" contains an "#ifdef __GNUC__" or something similar
if string.find(s,"__GNUC__") >= 0:
return (CONFIG_H_OK, "'%s' mentions '__GNUC__'" % fn)
else:
return (CONFIG_H_NOTOK, "'%s' does not mention '__GNUC__'" % fn)
def __getattr__(self, name):
if name in ('findall', 'finditer', 'match', 'scanner', 'search',
'split', 'sub', 'subn'):
warn("'distutils.cygwinccompiler.RE_VERSION' is deprecated "
"and will be removed in the next version", DeprecationWarning)
return getattr(self.pattern, name)
RE_VERSION = _Deprecated_SRE_Pattern(re.compile('(\d+\.\d+(\.\d+)*)'))
def get_versions():
""" Try to find out the versions of gcc, ld and dllwrap.
If not possible it returns None for it.
If not possible it returns None for it.
"""
warn("'distutils.cygwinccompiler.get_versions' is deprecated "
"use 'distutils.util.get_compiler_versions' instead",
DeprecationWarning)
from distutils.version import LooseVersion
from distutils.spawn import find_executable
import re
return get_compiler_versions()
gcc_exe = find_executable('gcc')
if gcc_exe:
out = os.popen(gcc_exe + ' -dumpversion','r')
out_string = out.read()
out.close()
result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
if result:
gcc_version = LooseVersion(result.group(1))
else:
gcc_version = None
else:
gcc_version = None
ld_exe = find_executable('ld')
if ld_exe:
out = os.popen(ld_exe + ' -v','r')
out_string = out.read()
out.close()
result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
if result:
ld_version = LooseVersion(result.group(1))
else:
ld_version = None
else:
ld_version = None
dllwrap_exe = find_executable('dllwrap')
if dllwrap_exe:
out = os.popen(dllwrap_exe + ' --version','r')
out_string = out.read()
out.close()
result = re.search(' (\d+\.\d+(\.\d+)*)',out_string)
if result:
dllwrap_version = LooseVersion(result.group(1))
else:
dllwrap_version = None
else:
dllwrap_version = None
return (gcc_version, ld_version, dllwrap_version)

View File

@ -21,13 +21,12 @@ handles the EMX port of the GNU C compiler to OS/2.
__revision__ = "$Id$"
import os, sys, copy
from warnings import warn
import os,sys,copy
from distutils.ccompiler import gen_preprocess_options, gen_lib_options
from distutils.unixccompiler import UnixCCompiler
from distutils.file_util import write_file
from distutils.errors import DistutilsExecError, CompileError, UnknownFileError
from distutils.util import get_compiler_versions
from distutils import log
class EMXCCompiler (UnixCCompiler):
@ -56,8 +55,8 @@ class EMXCCompiler (UnixCCompiler):
("Reason: %s." % details) +
"Compiling may fail because of undefined preprocessor macros.")
gcc_version, ld_version, dllwrap_version = get_compiler_versions()
self.gcc_version, self.ld_version = gcc_version, ld_version
(self.gcc_version, self.ld_version) = \
get_versions()
self.debug_print(self.compiler_type + ": gcc %s, ld %s\n" %
(self.gcc_version,
self.ld_version) )
@ -294,11 +293,23 @@ def get_versions():
""" Try to find out the versions of gcc and ld.
If not possible it returns None for it.
"""
warn("'distutils.emxccompiler.get_versions' is deprecated "
"use 'distutils.util.get_compiler_versions' instead",
DeprecationWarning)
from distutils.version import StrictVersion
from distutils.spawn import find_executable
import re
gcc_exe = find_executable('gcc')
if gcc_exe:
out = os.popen(gcc_exe + ' -dumpversion','r')
out_string = out.read()
out.close()
result = re.search('(\d+\.\d+\.\d+)',out_string)
if result:
gcc_version = StrictVersion(result.group(1))
else:
gcc_version = None
else:
gcc_version = None
# EMX ld has no way of reporting version number, and we use GCC
# anyway - so we can link OMF DLLs
gcc_version, ld_version, dllwrap_version = get_compiler_versions()
return gcc_version, None
ld_version = None
return (gcc_version, ld_version)

View File

@ -5,8 +5,13 @@ modules in setup scripts."""
__revision__ = "$Id$"
import os
import warnings
import os, string, sys
from types import *
try:
import warnings
except ImportError:
warnings = None
# This class is really only used by the "build_ext" command, so it might
# make sense to put it in distutils.command.build_ext. However, that
@ -78,9 +83,6 @@ class Extension:
language : string
extension language (i.e. "c", "c++", "objc"). Will be detected
from the source extensions if not provided.
optional : boolean
specifies that a build failure in the extension should not abort the
build process, but simply not install the failing extension.
"""
# When adding arguments to this constructor, be sure to update
@ -99,14 +101,12 @@ class Extension:
swig_opts = None,
depends=None,
language=None,
optional=None,
**kw # To catch unknown keywords
):
if not isinstance(name, str):
raise AssertionError("'name' must be a string")
if not (isinstance(sources, list) and
all(isinstance(v, str) for v in sources)):
raise AssertionError("'sources' must be a list of strings")
assert type(name) is StringType, "'name' must be a string"
assert (type(sources) is ListType and
map(type, sources) == [StringType]*len(sources)), \
"'sources' must be a list of strings"
self.name = name
self.sources = sources
@ -123,28 +123,27 @@ class Extension:
self.swig_opts = swig_opts or []
self.depends = depends or []
self.language = language
self.optional = optional
# If there are unknown keyword options, warn about them
if len(kw) > 0:
options = [repr(option) for option in kw]
options = ', '.join(sorted(options))
msg = "Unknown Extension options: %s" % options
warnings.warn(msg)
if len(kw):
L = kw.keys() ; L.sort()
L = map(repr, L)
msg = "Unknown Extension options: " + string.join(L, ', ')
if warnings is not None:
warnings.warn(msg)
else:
sys.stderr.write(msg + '\n')
# class Extension
def read_setup_file(filename):
"""Reads a Setup file and returns Extension instances."""
warnings.warn('distutils.extensions.read_setup_file is deprecated. '
'It will be removed in the next Python release.')
_sysconfig = __import__('sysconfig')
from distutils.sysconfig import (expand_makefile_vars,
_variable_rx)
def read_setup_file (filename):
from distutils.sysconfig import \
parse_makefile, expand_makefile_vars, _variable_rx
from distutils.text_file import TextFile
from distutils.util import split_quoted
# First pass over the file to gather "VAR = VALUE" assignments.
vars = _sysconfig._parse_makefile(filename)
vars = parse_makefile(filename)
# Second pass to gobble up the real content: lines of the form
# <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...]
@ -164,11 +163,10 @@ def read_setup_file(filename):
file.warn("'%s' lines not handled yet" % line)
continue
with warnings.catch_warnings():
warnings.simplefilter("ignore")
line = expand_makefile_vars(line, vars)
#print "original line: " + line
line = expand_makefile_vars(line, vars)
words = split_quoted(line)
#print "expanded line: " + line
# NB. this parses a slightly different syntax than the old
# makesetup script: here, there must be exactly one extension per
@ -197,7 +195,7 @@ def read_setup_file(filename):
elif switch == "-I":
ext.include_dirs.append(value)
elif switch == "-D":
equals = value.find("=")
equals = string.find(value, "=")
if equals == -1: # bare "-DFOO" -- no value
ext.define_macros.append((value, None))
else: # "-DFOO=blah"
@ -234,4 +232,15 @@ def read_setup_file(filename):
extensions.append(ext)
#print "module:", module
#print "source files:", source_files
#print "cpp args:", cpp_args
#print "lib args:", library_args
#extensions[module] = { 'sources': source_files,
# 'cpp_args': cpp_args,
# 'lib_args': library_args }
return extensions
# read_setup_file ()

View File

@ -7,51 +7,59 @@ available.
Written by: Fred L. Drake, Jr.
Email: <fdrake@acm.org>
**This module has been moved out of Distutils and will be removed from
Python in the next version (3.3)**
"""
__revision__ = "$Id$"
import os
import re
from warnings import warn
import string
import sys
# importing sysconfig from Lib
# to avoid this module to shadow it
_sysconfig = __import__('sysconfig')
from distutils.errors import DistutilsPlatformError
# names defined here to keep backward compatibility
# for APIs that were relocated
get_python_version = _sysconfig.get_python_version
get_config_h_filename = _sysconfig.get_config_h_filename
parse_config_h = _sysconfig.parse_config_h
get_config_vars = _sysconfig.get_config_vars
get_config_var = _sysconfig.get_config_var
from distutils.ccompiler import customize_compiler
# These are needed in a couple of spots, so just compute them once.
PREFIX = os.path.normpath(sys.prefix)
EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
_DEPRECATION_MSG = ("distutils.sysconfig.%s is deprecated. "
"Use the APIs provided by the sysconfig module instead")
def _get_project_base():
return _sysconfig._PROJECT_BASE
project_base = _get_project_base()
class _DeprecatedBool(int):
def __nonzero__(self):
warn(_DEPRECATION_MSG % 'get_python_version', DeprecationWarning)
return super(_DeprecatedBool, self).__nonzero__()
# Path to the base directory of the project. On Windows the binary may
# live in project/PCBuild9. If we're dealing with an x64 Windows build,
# it'll live in project/PCbuild/amd64.
project_base = os.path.dirname(os.path.abspath(sys.executable))
if os.name == "nt" and "pcbuild" in project_base[-8:].lower():
project_base = os.path.abspath(os.path.join(project_base, os.path.pardir))
# PC/VS7.1
if os.name == "nt" and "\\pc\\v" in project_base[-10:].lower():
project_base = os.path.abspath(os.path.join(project_base, os.path.pardir,
os.path.pardir))
# PC/AMD64
if os.name == "nt" and "\\pcbuild\\amd64" in project_base[-14:].lower():
project_base = os.path.abspath(os.path.join(project_base, os.path.pardir,
os.path.pardir))
# python_build: (Boolean) if true, we're either building Python or
# building an extension with an un-installed Python, so we use
# different (hard-wired) directories.
# Setup.local is available for Makefile builds including VPATH builds,
# Setup.dist is available on Windows
def _python_build():
return _DeprecatedBool(_sysconfig.is_python_build())
for fn in ("Setup.dist", "Setup.local"):
if os.path.isfile(os.path.join(project_base, "Modules", fn)):
return True
return False
python_build = _python_build()
def get_python_inc(plat_specific=0, prefix=None):
"""This function is deprecated.
Return the directory containing installed Python header files.
def get_python_version():
"""Return a string containing the major and minor Python version,
leaving off the patchlevel. Sample return values could be '1.5'
or '2.2'.
"""
return sys.version[:3]
def get_python_inc(plat_specific=0, prefix=None):
"""Return the directory containing installed Python header files.
If 'plat_specific' is false (the default), this is the path to the
non-platform-specific header files, i.e. Python.h and so on;
@ -61,22 +69,36 @@ def get_python_inc(plat_specific=0, prefix=None):
If 'prefix' is supplied, use it instead of sys.prefix or
sys.exec_prefix -- i.e., ignore 'plat_specific'.
"""
warn(_DEPRECATION_MSG % 'get_python_inc', DeprecationWarning)
get_path = _sysconfig.get_path
if prefix is not None:
vars = {'base': prefix}
return get_path('include', vars=vars)
if not plat_specific:
return get_path('include')
if prefix is None:
prefix = plat_specific and EXEC_PREFIX or PREFIX
if os.name == "posix":
if python_build:
base = os.path.dirname(os.path.abspath(sys.executable))
if plat_specific:
inc_dir = base
else:
inc_dir = os.path.join(base, "Include")
if not os.path.exists(inc_dir):
inc_dir = os.path.join(os.path.dirname(base), "Include")
return inc_dir
return os.path.join(prefix, "include", "python" + get_python_version())
elif os.name == "nt":
return os.path.join(prefix, "include")
elif os.name == "mac":
if plat_specific:
return os.path.join(prefix, "Mac", "Include")
else:
return os.path.join(prefix, "Include")
elif os.name == "os2":
return os.path.join(prefix, "Include")
else:
return get_path('platinclude')
raise DistutilsPlatformError(
"I don't know where Python installs its C header files "
"on platform '%s'" % os.name)
def get_python_lib(plat_specific=False, standard_lib=False, prefix=None):
"""This function is deprecated.
Return the directory containing the Python library (standard or
def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
"""Return the directory containing the Python library (standard or
site additions).
If 'plat_specific' is true, return the directory containing
@ -89,33 +111,146 @@ def get_python_lib(plat_specific=False, standard_lib=False, prefix=None):
If 'prefix' is supplied, use it instead of sys.prefix or
sys.exec_prefix -- i.e., ignore 'plat_specific'.
"""
warn(_DEPRECATION_MSG % 'get_python_lib', DeprecationWarning)
vars = {}
get_path = _sysconfig.get_path
if prefix is not None:
if plat_specific:
vars['platbase'] = prefix
else:
vars['base'] = prefix
if prefix is None:
prefix = plat_specific and EXEC_PREFIX or PREFIX
if standard_lib:
if plat_specific:
return get_path('platstdlib', vars=vars)
if os.name == "posix":
libpython = os.path.join(prefix,
"lib", "python" + get_python_version())
if standard_lib:
return libpython
else:
return get_path('stdlib', vars=vars)
return os.path.join(libpython, "site-packages")
elif os.name == "nt":
if standard_lib:
return os.path.join(prefix, "Lib")
else:
if get_python_version() < "2.2":
return prefix
else:
return os.path.join(prefix, "Lib", "site-packages")
elif os.name == "mac":
if plat_specific:
if standard_lib:
return os.path.join(prefix, "Lib", "lib-dynload")
else:
return os.path.join(prefix, "Lib", "site-packages")
else:
if standard_lib:
return os.path.join(prefix, "Lib")
else:
return os.path.join(prefix, "Lib", "site-packages")
elif os.name == "os2":
if standard_lib:
return os.path.join(prefix, "Lib")
else:
return os.path.join(prefix, "Lib", "site-packages")
else:
if plat_specific:
return get_path('platlib', vars=vars)
raise DistutilsPlatformError(
"I don't know where Python installs its library "
"on platform '%s'" % os.name)
def customize_compiler(compiler):
"""Do any platform-specific customization of a CCompiler instance.
Mainly needed on Unix, so we can plug in the information that
varies across Unices and is stored in Python's Makefile.
"""
if compiler.compiler_type == "unix":
(cc, cxx, opt, cflags, ccshared, ldshared, so_ext) = \
get_config_vars('CC', 'CXX', 'OPT', 'CFLAGS',
'CCSHARED', 'LDSHARED', 'SO')
if 'CC' in os.environ:
cc = os.environ['CC']
if 'CXX' in os.environ:
cxx = os.environ['CXX']
if 'LDSHARED' in os.environ:
ldshared = os.environ['LDSHARED']
if 'CPP' in os.environ:
cpp = os.environ['CPP']
else:
return get_path('purelib', vars=vars)
cpp = cc + " -E" # not always
if 'LDFLAGS' in os.environ:
ldshared = ldshared + ' ' + os.environ['LDFLAGS']
if 'CFLAGS' in os.environ:
cflags = opt + ' ' + os.environ['CFLAGS']
ldshared = ldshared + ' ' + os.environ['CFLAGS']
if 'CPPFLAGS' in os.environ:
cpp = cpp + ' ' + os.environ['CPPFLAGS']
cflags = cflags + ' ' + os.environ['CPPFLAGS']
ldshared = ldshared + ' ' + os.environ['CPPFLAGS']
cc_cmd = cc + ' ' + cflags
compiler.set_executables(
preprocessor=cpp,
compiler=cc_cmd,
compiler_so=cc_cmd + ' ' + ccshared,
compiler_cxx=cxx,
linker_so=ldshared,
linker_exe=cc)
compiler.shared_lib_extension = so_ext
def get_config_h_filename():
"""Return full pathname of installed pyconfig.h file."""
if python_build:
if os.name == "nt":
inc_dir = os.path.join(project_base, "PC")
else:
inc_dir = project_base
else:
inc_dir = get_python_inc(plat_specific=1)
if get_python_version() < '2.2':
config_h = 'config.h'
else:
# The name of the config.h file changed in 2.2
config_h = 'pyconfig.h'
return os.path.join(inc_dir, config_h)
def get_makefile_filename():
"""This function is deprecated.
"""Return full pathname of installed Makefile from the Python build."""
if python_build:
return os.path.join(os.path.dirname(sys.executable), "Makefile")
lib_dir = get_python_lib(plat_specific=1, standard_lib=1)
return os.path.join(lib_dir, "config", "Makefile")
Return full pathname of installed Makefile from the Python build.
def parse_config_h(fp, g=None):
"""Parse a config.h-style file.
A dictionary containing name/value pairs is returned. If an
optional dictionary is passed in as the second argument, it is
used instead of a new dictionary.
"""
warn(_DEPRECATION_MSG % 'get_makefile_filename', DeprecationWarning)
return _sysconfig._get_makefile_filename()
if g is None:
g = {}
define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n")
undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n")
#
while 1:
line = fp.readline()
if not line:
break
m = define_rx.match(line)
if m:
n, v = m.group(1, 2)
try: v = int(v)
except ValueError: pass
g[n] = v
else:
m = undef_rx.match(line)
if m:
g[m.group(1)] = 0
return g
# Regexes needed for parsing Makefile (and similar syntaxes,
# like old-style Setup files).
@ -124,29 +259,91 @@ _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)")
_findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}")
def parse_makefile(fn, g=None):
"""This function is deprecated.
Parse a Makefile-style file.
"""Parse a Makefile-style file.
A dictionary containing name/value pairs is returned. If an
optional dictionary is passed in as the second argument, it is
used instead of a new dictionary.
"""
warn(_DEPRECATION_MSG % 'parse_makefile', DeprecationWarning)
return _sysconfig._parse_makefile(fn, g)
from distutils.text_file import TextFile
fp = TextFile(fn, strip_comments=1, skip_blanks=1, join_lines=1)
if g is None:
g = {}
done = {}
notdone = {}
while 1:
line = fp.readline()
if line is None: # eof
break
m = _variable_rx.match(line)
if m:
n, v = m.group(1, 2)
v = v.strip()
# `$$' is a literal `$' in make
tmpv = v.replace('$$', '')
if "$" in tmpv:
notdone[n] = v
else:
try:
v = int(v)
except ValueError:
# insert literal `$'
done[n] = v.replace('$$', '$')
else:
done[n] = v
# do variable interpolation here
while notdone:
for name in notdone.keys():
value = notdone[name]
m = _findvar1_rx.search(value) or _findvar2_rx.search(value)
if m:
n = m.group(1)
found = True
if n in done:
item = str(done[n])
elif n in notdone:
# get it on a subsequent round
found = False
elif n in os.environ:
# do it like make: fall back to environment
item = os.environ[n]
else:
done[n] = item = ""
if found:
after = value[m.end():]
value = value[:m.start()] + item + after
if "$" in after:
notdone[name] = value
else:
try: value = int(value)
except ValueError:
done[name] = value.strip()
else:
done[name] = value
del notdone[name]
else:
# bogus variable reference; just drop it since we can't deal
del notdone[name]
fp.close()
# save the results in the global dictionary
g.update(done)
return g
def expand_makefile_vars(s, vars):
"""This function is deprecated.
Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
"""Expand Makefile-style variables -- "${foo}" or "$(foo)" -- in
'string' according to 'vars' (a dictionary mapping variable names to
values). Variables not present in 'vars' are silently expanded to the
empty string. The variable values in 'vars' should not contain further
variable expansions; if 'vars' is the output of 'parse_makefile()',
you're fine. Returns a variable-expanded version of 's'.
"""
warn('this function will be removed in then next version of Python',
DeprecationWarning)
# This algorithm does multiple expansion, so if vars['foo'] contains
# "${bar}", it will expand ${foo} to ${bar}, and then expand
@ -162,3 +359,247 @@ def expand_makefile_vars(s, vars):
else:
break
return s
_config_vars = None
def _init_posix():
"""Initialize the module as appropriate for POSIX systems."""
g = {}
# load the installed Makefile:
try:
filename = get_makefile_filename()
parse_makefile(filename, g)
except IOError, msg:
my_msg = "invalid Python installation: unable to open %s" % filename
if hasattr(msg, "strerror"):
my_msg = my_msg + " (%s)" % msg.strerror
raise DistutilsPlatformError(my_msg)
# load the installed pyconfig.h:
try:
filename = get_config_h_filename()
parse_config_h(file(filename), g)
except IOError, msg:
my_msg = "invalid Python installation: unable to open %s" % filename
if hasattr(msg, "strerror"):
my_msg = my_msg + " (%s)" % msg.strerror
raise DistutilsPlatformError(my_msg)
# On MacOSX we need to check the setting of the environment variable
# MACOSX_DEPLOYMENT_TARGET: configure bases some choices on it so
# it needs to be compatible.
# If it isn't set we set it to the configure-time value
if sys.platform == 'darwin' and 'MACOSX_DEPLOYMENT_TARGET' in g:
cfg_target = g['MACOSX_DEPLOYMENT_TARGET']
cur_target = os.getenv('MACOSX_DEPLOYMENT_TARGET', '')
if cur_target == '':
cur_target = cfg_target
os.putenv('MACOSX_DEPLOYMENT_TARGET', cfg_target)
elif map(int, cfg_target.split('.')) > map(int, cur_target.split('.')):
my_msg = ('$MACOSX_DEPLOYMENT_TARGET mismatch: now "%s" but "%s" during configure'
% (cur_target, cfg_target))
raise DistutilsPlatformError(my_msg)
# On AIX, there are wrong paths to the linker scripts in the Makefile
# -- these paths are relative to the Python source, but when installed
# the scripts are in another directory.
if python_build:
g['LDSHARED'] = g['BLDSHARED']
elif get_python_version() < '2.1':
# The following two branches are for 1.5.2 compatibility.
if sys.platform == 'aix4': # what about AIX 3.x ?
# Linker script is in the config directory, not in Modules as the
# Makefile says.
python_lib = get_python_lib(standard_lib=1)
ld_so_aix = os.path.join(python_lib, 'config', 'ld_so_aix')
python_exp = os.path.join(python_lib, 'config', 'python.exp')
g['LDSHARED'] = "%s %s -bI:%s" % (ld_so_aix, g['CC'], python_exp)
elif sys.platform == 'beos':
# Linker script is in the config directory. In the Makefile it is
# relative to the srcdir, which after installation no longer makes
# sense.
python_lib = get_python_lib(standard_lib=1)
linkerscript_path = string.split(g['LDSHARED'])[0]
linkerscript_name = os.path.basename(linkerscript_path)
linkerscript = os.path.join(python_lib, 'config',
linkerscript_name)
# XXX this isn't the right place to do this: adding the Python
# library to the link, if needed, should be in the "build_ext"
# command. (It's also needed for non-MS compilers on Windows, and
# it's taken care of for them by the 'build_ext.get_libraries()'
# method.)
g['LDSHARED'] = ("%s -L%s/lib -lpython%s" %
(linkerscript, PREFIX, get_python_version()))
global _config_vars
_config_vars = g
def _init_nt():
"""Initialize the module as appropriate for NT"""
g = {}
# set basic install directories
g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
# XXX hmmm.. a normal install puts include files here
g['INCLUDEPY'] = get_python_inc(plat_specific=0)
g['SO'] = '.pyd'
g['EXE'] = ".exe"
g['VERSION'] = get_python_version().replace(".", "")
g['BINDIR'] = os.path.dirname(os.path.abspath(sys.executable))
global _config_vars
_config_vars = g
def _init_mac():
"""Initialize the module as appropriate for Macintosh systems"""
g = {}
# set basic install directories
g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
# XXX hmmm.. a normal install puts include files here
g['INCLUDEPY'] = get_python_inc(plat_specific=0)
import MacOS
if not hasattr(MacOS, 'runtimemodel'):
g['SO'] = '.ppc.slb'
else:
g['SO'] = '.%s.slb' % MacOS.runtimemodel
# XXX are these used anywhere?
g['install_lib'] = os.path.join(EXEC_PREFIX, "Lib")
g['install_platlib'] = os.path.join(EXEC_PREFIX, "Mac", "Lib")
# These are used by the extension module build
g['srcdir'] = ':'
global _config_vars
_config_vars = g
def _init_os2():
"""Initialize the module as appropriate for OS/2"""
g = {}
# set basic install directories
g['LIBDEST'] = get_python_lib(plat_specific=0, standard_lib=1)
g['BINLIBDEST'] = get_python_lib(plat_specific=1, standard_lib=1)
# XXX hmmm.. a normal install puts include files here
g['INCLUDEPY'] = get_python_inc(plat_specific=0)
g['SO'] = '.pyd'
g['EXE'] = ".exe"
global _config_vars
_config_vars = g
def get_config_vars(*args):
"""With no arguments, return a dictionary of all configuration
variables relevant for the current platform. Generally this includes
everything needed to build extensions and install both pure modules and
extensions. On Unix, this means every variable defined in Python's
installed Makefile; on Windows and Mac OS it's a much smaller set.
With arguments, return a list of values that result from looking up
each argument in the configuration variable dictionary.
"""
global _config_vars
if _config_vars is None:
func = globals().get("_init_" + os.name)
if func:
func()
else:
_config_vars = {}
# Normalized versions of prefix and exec_prefix are handy to have;
# in fact, these are the standard versions used most places in the
# Distutils.
_config_vars['prefix'] = PREFIX
_config_vars['exec_prefix'] = EXEC_PREFIX
if sys.platform == 'darwin':
kernel_version = os.uname()[2] # Kernel version (8.4.3)
major_version = int(kernel_version.split('.')[0])
if major_version < 8:
# On Mac OS X before 10.4, check if -arch and -isysroot
# are in CFLAGS or LDFLAGS and remove them if they are.
# This is needed when building extensions on a 10.3 system
# using a universal build of python.
for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
# a number of derived variables. These need to be
# patched up as well.
'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
flags = _config_vars[key]
flags = re.sub('-arch\s+\w+\s', ' ', flags)
flags = re.sub('-isysroot [^ \t]*', ' ', flags)
_config_vars[key] = flags
else:
# Allow the user to override the architecture flags using
# an environment variable.
# NOTE: This name was introduced by Apple in OSX 10.5 and
# is used by several scripting languages distributed with
# that OS release.
if 'ARCHFLAGS' in os.environ:
arch = os.environ['ARCHFLAGS']
for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
# a number of derived variables. These need to be
# patched up as well.
'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
flags = _config_vars[key]
flags = re.sub('-arch\s+\w+\s', ' ', flags)
flags = flags + ' ' + arch
_config_vars[key] = flags
# If we're on OSX 10.5 or later and the user tries to
# compiles an extension using an SDK that is not present
# on the current machine it is better to not use an SDK
# than to fail.
#
# The major usecase for this is users using a Python.org
# binary installer on OSX 10.6: that installer uses
# the 10.4u SDK, but that SDK is not installed by default
# when you install Xcode.
#
m = re.search('-isysroot\s+(\S+)', _config_vars['CFLAGS'])
if m is not None:
sdk = m.group(1)
if not os.path.exists(sdk):
for key in ('LDFLAGS', 'BASECFLAGS', 'LDSHARED',
# a number of derived variables. These need to be
# patched up as well.
'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
flags = _config_vars[key]
flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags)
_config_vars[key] = flags
if args:
vals = []
for name in args:
vals.append(_config_vars.get(name))
return vals
else:
return _config_vars
def get_config_var(name):
"""Return the value of a single variable using the dictionary
returned by 'get_config_vars()'. Equivalent to
get_config_vars().get(name)
"""
return get_config_vars().get(name)

View File

@ -1,111 +0,0 @@
"""Tests for distutils.cygwinccompiler."""
import unittest
import sys
import os
import warnings
import sysconfig
from test.test_support import check_warnings, run_unittest
from test.test_support import captured_stdout
from distutils import cygwinccompiler
from distutils.cygwinccompiler import (CygwinCCompiler, check_config_h,
CONFIG_H_OK, CONFIG_H_NOTOK,
CONFIG_H_UNCERTAIN, get_versions,
get_msvcr, RE_VERSION)
from distutils.util import get_compiler_versions
from distutils.tests import support
class CygwinCCompilerTestCase(support.TempdirManager,
unittest.TestCase):
def setUp(self):
super(CygwinCCompilerTestCase, self).setUp()
self.version = sys.version
self.python_h = os.path.join(self.mkdtemp(), 'python.h')
self.old_get_config_h_filename = sysconfig.get_config_h_filename
sysconfig.get_config_h_filename = self._get_config_h_filename
def tearDown(self):
sys.version = self.version
sysconfig.get_config_h_filename = self.old_get_config_h_filename
super(CygwinCCompilerTestCase, self).tearDown()
def _get_config_h_filename(self):
return self.python_h
def test_check_config_h(self):
# check_config_h looks for "GCC" in sys.version first
# returns CONFIG_H_OK if found
sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) \n[GCC '
'4.0.1 (Apple Computer, Inc. build 5370)]')
self.assertEquals(check_config_h()[0], CONFIG_H_OK)
# then it tries to see if it can find "__GNUC__" in pyconfig.h
sys.version = 'something without the *CC word'
# if the file doesn't exist it returns CONFIG_H_UNCERTAIN
self.assertEquals(check_config_h()[0], CONFIG_H_UNCERTAIN)
# if it exists but does not contain __GNUC__, it returns CONFIG_H_NOTOK
self.write_file(self.python_h, 'xxx')
self.assertEquals(check_config_h()[0], CONFIG_H_NOTOK)
# and CONFIG_H_OK if __GNUC__ is found
self.write_file(self.python_h, 'xxx __GNUC__ xxx')
self.assertEquals(check_config_h()[0], CONFIG_H_OK)
def test_get_msvcr(self):
# none
sys.version = ('2.6.1 (r261:67515, Dec 6 2008, 16:42:21) '
'\n[GCC 4.0.1 (Apple Computer, Inc. build 5370)]')
self.assertEquals(get_msvcr(), None)
# MSVC 7.0
sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) '
'[MSC v.1300 32 bits (Intel)]')
self.assertEquals(get_msvcr(), ['msvcr70'])
# MSVC 7.1
sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) '
'[MSC v.1310 32 bits (Intel)]')
self.assertEquals(get_msvcr(), ['msvcr71'])
# VS2005 / MSVC 8.0
sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) '
'[MSC v.1400 32 bits (Intel)]')
self.assertEquals(get_msvcr(), ['msvcr80'])
# VS2008 / MSVC 9.0
sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) '
'[MSC v.1500 32 bits (Intel)]')
self.assertEquals(get_msvcr(), ['msvcr90'])
# unknown
sys.version = ('2.5.1 (r251:54863, Apr 18 2007, 08:51:08) '
'[MSC v.1999 32 bits (Intel)]')
self.assertRaises(ValueError, get_msvcr)
def test_get_version_deprecated(self):
with check_warnings() as w:
warnings.simplefilter("always")
# make sure get_compiler_versions and get_versions
# returns the same thing
self.assertEquals(get_compiler_versions(), get_versions())
# make sure using get_version() generated a warning
self.assertEquals(len(w.warnings), 1)
# make sure any usage of RE_VERSION will also
# generate a warning, but till works
version = RE_VERSION.search('1.2').group(1)
self.assertEquals(version, '1.2')
self.assertEquals(len(w.warnings), 2)
def test_suite():
return unittest.makeSuite(CygwinCCompilerTestCase)
if __name__ == '__main__':
run_unittest(test_suite())

View File

@ -1,33 +0,0 @@
"""Tests for distutils.emxccompiler."""
import unittest
import sys
import os
import warnings
from test.test_support import check_warnings, run_unittest
from test.test_support import captured_stdout
from distutils.emxccompiler import get_versions
from distutils.util import get_compiler_versions
from distutils.tests import support
class EmxCCompilerTestCase(support.TempdirManager,
unittest.TestCase):
def test_get_version_deprecated(self):
with check_warnings() as w:
warnings.simplefilter("always")
# make sure get_compiler_versions and get_versions
# returns the same gcc
gcc, ld, dllwrap = get_compiler_versions()
emx_gcc, emx_ld = get_versions()
self.assertEquals(gcc, emx_gcc)
# make sure using get_version() generated a warning
self.assertEquals(len(w.warnings), 1)
def test_suite():
return unittest.makeSuite(EmxCCompilerTestCase)
if __name__ == '__main__':
run_unittest(test_suite())

View File

@ -1,78 +0,0 @@
"""Tests for distutils.extension."""
import os
import sys
import unittest
import warnings
from test.test_support import check_warnings
from distutils.extension import read_setup_file, Extension
from distutils.tests.support import capture_warnings
class ExtensionTestCase(unittest.TestCase):
@capture_warnings
def test_read_setup_file(self):
# trying to read a Setup file
# (sample extracted from the PyGame project)
setup = os.path.join(os.path.dirname(__file__), 'Setup.sample')
exts = read_setup_file(setup)
names = [ext.name for ext in exts]
names.sort()
# here are the extensions read_setup_file should have created
# out of the file
wanted = ['_arraysurfarray', '_camera', '_numericsndarray',
'_numericsurfarray', 'base', 'bufferproxy', 'cdrom',
'color', 'constants', 'display', 'draw', 'event',
'fastevent', 'font', 'gfxdraw', 'image', 'imageext',
'joystick', 'key', 'mask', 'mixer', 'mixer_music',
'mouse', 'movie', 'overlay', 'pixelarray', 'pypm',
'rect', 'rwobject', 'scrap', 'surface', 'surflock',
'time', 'transform']
self.assertEquals(names, wanted)
@unittest.skipIf(sys.flags.optimize >= 2,
"Assertions are omitted with -O2 and above")
def test_extension_init_assertions(self):
# The first argument, which is the name, must be a string.
self.assertRaises(AssertionError, Extension, 1, [])
# the second argument, which is the list of files, must
# be a list of strings
self.assertRaises(AssertionError, Extension, 'name', 'file')
self.assertRaises(AssertionError, Extension, 'name', ['file', 1])
def test_extension_init(self):
ext = Extension('name', [])
self.assertEquals(ext.name, 'name')
ext = Extension('name', ['file1', 'file2'])
self.assertEquals(ext.sources, ['file1', 'file2'])
# others arguments have defaults
for attr in ('include_dirs', 'define_macros', 'undef_macros',
'library_dirs', 'libraries', 'runtime_library_dirs',
'extra_objects', 'extra_compile_args', 'extra_link_args',
'export_symbols', 'swig_opts', 'depends'):
self.assertEquals(getattr(ext, attr), [])
self.assertEquals(ext.language, None)
self.assertEquals(ext.optional, None)
# if there are unknown keyword options, warn about them
with check_warnings() as w:
warnings.simplefilter('always')
ext = Extension('name', ['file1', 'file2'], chic=True)
self.assertEquals(len(w.warnings), 1)
self.assertEquals(str(w.warnings[0].message),
"Unknown Extension options: 'chic'")
def test_suite():
return unittest.makeSuite(ExtensionTestCase)
if __name__ == "__main__":
unittest.main(defaultTest="test_suite")

View File

@ -1,27 +1,15 @@
"""Tests for distutils.command.install."""
import os
import os.path
import sys
import unittest
import site
import sysconfig
from sysconfig import (get_scheme_names, _CONFIG_VARS, _INSTALL_SCHEMES,
get_config_var, get_path)
from test.test_support import captured_stdout
from distutils.command.install import install
from distutils.command import install as install_module
from distutils.core import Distribution
from distutils.errors import DistutilsOptionError
from distutils.tests import support
class InstallTestCase(support.TempdirManager,
support.EnvironGuard,
support.LoggingSilencer,
unittest.TestCase):
class InstallTestCase(support.TempdirManager, unittest.TestCase):
def test_home_installation_scheme(self):
# This ensure two things:
@ -38,23 +26,9 @@ class InstallTestCase(support.TempdirManager,
build_lib=os.path.join(builddir, "lib"),
)
posix_prefix = _INSTALL_SCHEMES['posix_prefix']
old_posix_prefix = posix_prefix['platinclude']
posix_prefix['platinclude'] = \
'{platbase}/include/python{py_version_short}'
posix_home = _INSTALL_SCHEMES['posix_home']
old_posix_home = posix_home['platinclude']
posix_home['platinclude'] = '{base}/include/python'
try:
cmd = install(dist)
cmd.home = destination
cmd.ensure_finalized()
finally:
posix_home['platinclude'] = old_posix_home
posix_prefix['platinclude'] = old_posix_prefix
cmd = install(dist)
cmd.home = destination
cmd.ensure_finalized()
self.assertEqual(cmd.install_base, destination)
self.assertEqual(cmd.install_platbase, destination)
@ -73,143 +47,6 @@ class InstallTestCase(support.TempdirManager,
check_path(cmd.install_scripts, os.path.join(destination, "bin"))
check_path(cmd.install_data, destination)
def test_user_site(self):
# site.USER_SITE was introduced in 2.6
if sys.version < '2.6':
return
# preparing the environement for the test
self.old_user_base = get_config_var('userbase')
self.old_user_site = get_path('purelib', '%s_user' % os.name)
self.tmpdir = self.mkdtemp()
self.user_base = os.path.join(self.tmpdir, 'B')
self.user_site = os.path.join(self.tmpdir, 'S')
_CONFIG_VARS['userbase'] = self.user_base
scheme = _INSTALL_SCHEMES['%s_user' % os.name]
scheme['purelib'] = self.user_site
def _expanduser(path):
if path[0] == '~':
path = os.path.normpath(self.tmpdir) + path[1:]
return path
self.old_expand = os.path.expanduser
os.path.expanduser = _expanduser
try:
# this is the actual test
self._test_user_site()
finally:
_CONFIG_VARS['userbase'] = self.old_user_base
scheme['purelib'] = self.old_user_site
os.path.expanduser = self.old_expand
def _test_user_site(self):
schemes = get_scheme_names()
for key in ('nt_user', 'posix_user', 'os2_home'):
self.assertTrue(key in schemes)
dist = Distribution({'name': 'xx'})
cmd = install(dist)
# making sure the user option is there
options = [name for name, short, lable in
cmd.user_options]
self.assertTrue('user' in options)
# setting a value
cmd.user = 1
# user base and site shouldn't be created yet
self.assertTrue(not os.path.exists(self.user_base))
self.assertTrue(not os.path.exists(self.user_site))
# let's run finalize
cmd.ensure_finalized()
# now they should
self.assertTrue(os.path.exists(self.user_base))
self.assertTrue(os.path.exists(self.user_site))
self.assertTrue('userbase' in cmd.config_vars)
self.assertTrue('usersite' in cmd.config_vars)
def test_handle_extra_path(self):
dist = Distribution({'name': 'xx', 'extra_path': 'path,dirs'})
cmd = install(dist)
# two elements
cmd.handle_extra_path()
self.assertEquals(cmd.extra_path, ['path', 'dirs'])
self.assertEquals(cmd.extra_dirs, 'dirs')
self.assertEquals(cmd.path_file, 'path')
# one element
cmd.extra_path = ['path']
cmd.handle_extra_path()
self.assertEquals(cmd.extra_path, ['path'])
self.assertEquals(cmd.extra_dirs, 'path')
self.assertEquals(cmd.path_file, 'path')
# none
dist.extra_path = cmd.extra_path = None
cmd.handle_extra_path()
self.assertEquals(cmd.extra_path, None)
self.assertEquals(cmd.extra_dirs, '')
self.assertEquals(cmd.path_file, None)
# three elements (no way !)
cmd.extra_path = 'path,dirs,again'
self.assertRaises(DistutilsOptionError, cmd.handle_extra_path)
def test_finalize_options(self):
dist = Distribution({'name': 'xx'})
cmd = install(dist)
# must supply either prefix/exec-prefix/home or
# install-base/install-platbase -- not both
cmd.prefix = 'prefix'
cmd.install_base = 'base'
self.assertRaises(DistutilsOptionError, cmd.finalize_options)
# must supply either home or prefix/exec-prefix -- not both
cmd.install_base = None
cmd.home = 'home'
self.assertRaises(DistutilsOptionError, cmd.finalize_options)
# can't combine user with with prefix/exec_prefix/home or
# install_(plat)base
cmd.prefix = None
cmd.user = 'user'
self.assertRaises(DistutilsOptionError, cmd.finalize_options)
def test_record(self):
install_dir = self.mkdtemp()
pkgdir, dist = self.create_dist()
dist = Distribution()
cmd = install(dist)
dist.command_obj['install'] = cmd
cmd.root = install_dir
cmd.record = os.path.join(pkgdir, 'RECORD')
cmd.ensure_finalized()
cmd.run()
# let's check the RECORD file was created with one
# line (the egg info file)
with open(cmd.record) as f:
self.assertEquals(len(f.readlines()), 1)
def _test_debug_mode(self):
# this covers the code called when DEBUG is set
old_logs_len = len(self.logs)
install_module.DEBUG = True
try:
with captured_stdout() as stdout:
self.test_record()
finally:
install_module.DEBUG = False
self.assertTrue(len(self.logs) > old_logs_len)
def test_suite():
return unittest.makeSuite(InstallTestCase)

View File

@ -1,8 +1,8 @@
"""Tests for distutils.unixccompiler."""
import sys
import unittest
import sysconfig
from distutils import sysconfig
from distutils.unixccompiler import UnixCCompiler
class UnixCCompilerTestCase(unittest.TestCase):
@ -70,7 +70,7 @@ class UnixCCompilerTestCase(unittest.TestCase):
elif v == 'GNULD':
return 'yes'
sysconfig.get_config_var = gcv
self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo')
self.assertEqual(self.cc.rpath_foo(), '-Wl,-R/foo')
# GCC non-GNULD
sys.platform = 'bar'
@ -91,7 +91,7 @@ class UnixCCompilerTestCase(unittest.TestCase):
elif v == 'GNULD':
return 'yes'
sysconfig.get_config_var = gcv
self.assertEqual(self.cc.rpath_foo(), '-Wl,--enable-new-dtags,-R/foo')
self.assertEqual(self.cc.rpath_foo(), '-Wl,-R/foo')
# non-GCC GNULD
@ -119,7 +119,7 @@ class UnixCCompilerTestCase(unittest.TestCase):
def gcv(v):
return 'xxx'
sysconfig.get_config_var = gcv
self.assertEqual(self.cc.rpath_foo(), '-blibpath:/foo')
self.assertEqual(self.cc.rpath_foo(), '-R/foo')
def test_suite():

View File

@ -1,267 +1,11 @@
"""Tests for distutils.util."""
import os
import sys
import unittest
from copy import copy
from StringIO import StringIO
import subprocess
from sysconfig import get_config_vars, get_platform
from distutils.errors import DistutilsPlatformError, DistutilsByteCompileError
from distutils.util import (convert_path, change_root,
check_environ, split_quoted, strtobool,
rfc822_escape, get_compiler_versions,
_find_exe_version, _MAC_OS_X_LD_VERSION,
byte_compile)
from distutils import util
from distutils.tests import support
from distutils.version import LooseVersion
from distutils.util import byte_compile
class FakePopen(object):
test_class = None
def __init__(self, cmd, shell, stdout, stderr):
self.cmd = cmd.split()[0]
exes = self.test_class._exes
if self.cmd not in exes:
# we don't want to call the system, returning an empty
# output so it doesn't match
self.stdout = StringIO()
self.stderr = StringIO()
else:
self.stdout = StringIO(exes[self.cmd])
self.stderr = StringIO()
class UtilTestCase(support.EnvironGuard, unittest.TestCase):
def setUp(self):
super(UtilTestCase, self).setUp()
# saving the environment
self.name = os.name
self.platform = sys.platform
self.version = sys.version
self.sep = os.sep
self.join = os.path.join
self.isabs = os.path.isabs
self.splitdrive = os.path.splitdrive
#self._config_vars = copy(sysconfig._config_vars)
# patching os.uname
if hasattr(os, 'uname'):
self.uname = os.uname
self._uname = os.uname()
else:
self.uname = None
self._uname = None
os.uname = self._get_uname
# patching POpen
self.old_find_executable = util.find_executable
util.find_executable = self._find_executable
self._exes = {}
self.old_popen = subprocess.Popen
self.old_stdout = sys.stdout
self.old_stderr = sys.stderr
FakePopen.test_class = self
subprocess.Popen = FakePopen
def tearDown(self):
# getting back the environment
os.name = self.name
sys.platform = self.platform
sys.version = self.version
os.sep = self.sep
os.path.join = self.join
os.path.isabs = self.isabs
os.path.splitdrive = self.splitdrive
if self.uname is not None:
os.uname = self.uname
else:
del os.uname
#sysconfig._config_vars = copy(self._config_vars)
util.find_executable = self.old_find_executable
subprocess.Popen = self.old_popen
sys.old_stdout = self.old_stdout
sys.old_stderr = self.old_stderr
super(UtilTestCase, self).tearDown()
def _set_uname(self, uname):
self._uname = uname
def _get_uname(self):
return self._uname
def test_get_platform(self):
platform = util.get_platform()
self.assertEquals(platform, get_platform())
util.set_platform('MyOwnPlatform')
self.assertEquals('MyOwnPlatform', util.get_platform())
util.set_platform(platform)
def test_convert_path(self):
# linux/mac
os.sep = '/'
def _join(path):
return '/'.join(path)
os.path.join = _join
self.assertEquals(convert_path('/home/to/my/stuff'),
'/home/to/my/stuff')
# win
os.sep = '\\'
def _join(*path):
return '\\'.join(path)
os.path.join = _join
self.assertRaises(ValueError, convert_path, '/home/to/my/stuff')
self.assertRaises(ValueError, convert_path, 'home/to/my/stuff/')
self.assertEquals(convert_path('home/to/my/stuff'),
'home\\to\\my\\stuff')
self.assertEquals(convert_path('.'),
os.curdir)
def test_change_root(self):
# linux/mac
os.name = 'posix'
def _isabs(path):
return path[0] == '/'
os.path.isabs = _isabs
def _join(*path):
return '/'.join(path)
os.path.join = _join
self.assertEquals(change_root('/root', '/old/its/here'),
'/root/old/its/here')
self.assertEquals(change_root('/root', 'its/here'),
'/root/its/here')
# windows
os.name = 'nt'
def _isabs(path):
return path.startswith('c:\\')
os.path.isabs = _isabs
def _splitdrive(path):
if path.startswith('c:'):
return ('', path.replace('c:', ''))
return ('', path)
os.path.splitdrive = _splitdrive
def _join(*path):
return '\\'.join(path)
os.path.join = _join
self.assertEquals(change_root('c:\\root', 'c:\\old\\its\\here'),
'c:\\root\\old\\its\\here')
self.assertEquals(change_root('c:\\root', 'its\\here'),
'c:\\root\\its\\here')
# BugsBunny os (it's a great os)
os.name = 'BugsBunny'
self.assertRaises(DistutilsPlatformError,
change_root, 'c:\\root', 'its\\here')
# XXX platforms to be covered: os2, mac
def test_check_environ(self):
util._environ_checked = 0
if 'HOME' in os.environ:
del os.environ['HOME']
# posix without HOME
if os.name == 'posix': # this test won't run on windows
check_environ()
import pwd
self.assertEquals(os.environ['HOME'], pwd.getpwuid(os.getuid())[5])
else:
check_environ()
self.assertEquals(os.environ['PLAT'], get_platform())
self.assertEquals(util._environ_checked, 1)
def test_split_quoted(self):
self.assertEquals(split_quoted('""one"" "two" \'three\' \\four'),
['one', 'two', 'three', 'four'])
def test_strtobool(self):
yes = ('y', 'Y', 'yes', 'True', 't', 'true', 'True', 'On', 'on', '1')
no = ('n', 'no', 'f', 'false', 'off', '0', 'Off', 'No', 'N')
for y in yes:
self.assertTrue(strtobool(y))
for n in no:
self.assertTrue(not strtobool(n))
def test_rfc822_escape(self):
header = 'I am a\npoor\nlonesome\nheader\n'
res = rfc822_escape(header)
wanted = ('I am a%(8s)spoor%(8s)slonesome%(8s)s'
'header%(8s)s') % {'8s': '\n'+8*' '}
self.assertEquals(res, wanted)
def test_find_exe_version(self):
# the ld version scheme under MAC OS is:
# ^@(#)PROGRAM:ld PROJECT:ld64-VERSION
#
# where VERSION is a 2-digit number for major
# revisions. For instance under Leopard, it's
# currently 77
#
# Dots are used when branching is done.
#
# The SnowLeopard ld64 is currently 95.2.12
for output, version in (('@(#)PROGRAM:ld PROJECT:ld64-77', '77'),
('@(#)PROGRAM:ld PROJECT:ld64-95.2.12',
'95.2.12')):
result = _MAC_OS_X_LD_VERSION.search(output)
self.assertEquals(result.group(1), version)
def _find_executable(self, name):
if name in self._exes:
return name
return None
def test_get_compiler_versions(self):
# get_versions calls distutils.spawn.find_executable on
# 'gcc', 'ld' and 'dllwrap'
self.assertEquals(get_compiler_versions(), (None, None, None))
# Let's fake we have 'gcc' and it returns '3.4.5'
self._exes['gcc'] = 'gcc (GCC) 3.4.5 (mingw special)\nFSF'
res = get_compiler_versions()
self.assertEquals(str(res[0]), '3.4.5')
# and let's see what happens when the version
# doesn't match the regular expression
# (\d+\.\d+(\.\d+)*)
self._exes['gcc'] = 'very strange output'
res = get_compiler_versions()
self.assertEquals(res[0], None)
# same thing for ld
if sys.platform != 'darwin':
self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
res = get_compiler_versions()
self.assertEquals(str(res[1]), '2.17.50')
self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
res = get_compiler_versions()
self.assertEquals(res[1], None)
else:
self._exes['ld'] = 'GNU ld version 2.17.50 20060824'
res = get_compiler_versions()
self.assertEquals(res[1], None)
self._exes['ld'] = '@(#)PROGRAM:ld PROJECT:ld64-77'
res = get_compiler_versions()
self.assertEquals(str(res[1]), '77')
# and dllwrap
self._exes['dllwrap'] = 'GNU dllwrap 2.17.50 20060824\nFSF'
res = get_compiler_versions()
self.assertEquals(str(res[2]), '2.17.50')
self._exes['dllwrap'] = 'Cheese Wrap'
res = get_compiler_versions()
self.assertEquals(res[2], None)
class UtilTestCase(unittest.TestCase):
def test_dont_write_bytecode(self):
# makes sure byte_compile raise a DistutilsError

View File

@ -18,6 +18,7 @@ __revision__ = "$Id$"
import os, sys
from types import StringType, NoneType
from distutils import sysconfig
from distutils.dep_util import newer
from distutils.ccompiler import \
CCompiler, gen_preprocess_options, gen_lib_options
@ -25,7 +26,6 @@ from distutils.errors import \
DistutilsExecError, CompileError, LibError, LinkError
from distutils import log
# XXX Things not currently handled:
# * optimization/debug/warning flags; we just use whatever's in Python's
# Makefile and live with it. Is this adequate? If not, we might
@ -75,7 +75,7 @@ def _darwin_compiler_fixup(compiler_so, cc_args):
if 'ARCHFLAGS' in os.environ and not stripArch:
# User specified different -arch flags in the environ,
# see also the sysconfig
# see also distutils.sysconfig
compiler_so = compiler_so + os.environ['ARCHFLAGS'].split()
if stripSysroot:
@ -276,16 +276,13 @@ class UnixCCompiler(CCompiler):
# Linkers on different platforms need different options to
# specify that directories need to be added to the list of
# directories searched for dependencies when a dynamic library
# is sought. GCC on GNU systems (Linux, FreeBSD, ...) has to
# be told to pass the -R option through to the linker, whereas
# other compilers and gcc on other systems just know this.
# is sought. GCC has to be told to pass the -R option through
# to the linker, whereas other compilers just know this.
# Other compilers may need something slightly different. At
# this time, there's no way to determine this information from
# the configuration data stored in the Python installation, so
# we use this hack.
_sysconfig = __import__('sysconfig')
compiler = os.path.basename(_sysconfig.get_config_var("CC"))
compiler = os.path.basename(sysconfig.get_config_var("CC"))
if sys.platform[:6] == "darwin":
# MacOSX's linker doesn't understand the -R flag at all
return "-L" + dir
@ -296,22 +293,8 @@ class UnixCCompiler(CCompiler):
elif sys.platform[:7] == "irix646" or sys.platform[:6] == "osf1V5":
return ["-rpath", dir]
elif self._is_gcc(compiler):
# gcc on non-GNU systems does not need -Wl, but can
# use it anyway. Since distutils has always passed in
# -Wl whenever gcc was used in the past it is probably
# safest to keep doing so.
if _sysconfig.get_config_var("GNULD") == "yes":
# GNU ld needs an extra option to get a RUNPATH
# instead of just an RPATH.
return "-Wl,--enable-new-dtags,-R" + dir
else:
return "-Wl,-R" + dir
elif sys.platform[:3] == "aix":
return "-blibpath:" + dir
return "-Wl,-R" + dir
else:
# No idea how --enable-new-dtags would be passed on to
# ld if this system was using GNU ld. Don't know if a
# system like this even exists.
return "-R" + dir
def library_option(self, lib):

View File

@ -7,40 +7,184 @@ one of the other *util.py modules.
__revision__ = "$Id$"
import sys, os, string, re
from distutils.errors import DistutilsPlatformError
from distutils.dep_util import newer
from distutils.spawn import spawn, find_executable
from distutils.spawn import spawn
from distutils import log
from distutils.version import LooseVersion
from distutils.errors import DistutilsByteCompileError
_sysconfig = __import__('sysconfig')
_PLATFORM = None
def get_platform ():
"""Return a string that identifies the current platform. This is used
mainly to distinguish platform-specific build directories and
platform-specific built distributions. Typically includes the OS name
and version and the architecture (as supplied by 'os.uname()'),
although the exact information included depends on the OS; eg. for IRIX
the architecture isn't particularly important (IRIX only runs on SGI
hardware), but for Linux the kernel version isn't particularly
important.
def get_platform():
"""Return a string that identifies the current platform.
Examples of returned values:
linux-i586
linux-alpha (?)
solaris-2.6-sun4u
irix-5.3
irix64-6.2
By default, will return the value returned by sysconfig.get_platform(),
but it can be changed by calling set_platform().
Windows will return one of:
win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc)
win-ia64 (64bit Windows on Itanium)
win32 (all others - specifically, sys.platform is returned)
For other non-POSIX platforms, currently just returns 'sys.platform'.
"""
global _PLATFORM
if _PLATFORM is None:
_PLATFORM = _sysconfig.get_platform()
return _PLATFORM
if os.name == 'nt':
# sniff sys.version for architecture.
prefix = " bit ("
i = string.find(sys.version, prefix)
if i == -1:
return sys.platform
j = string.find(sys.version, ")", i)
look = sys.version[i+len(prefix):j].lower()
if look=='amd64':
return 'win-amd64'
if look=='itanium':
return 'win-ia64'
return sys.platform
def set_platform(identifier):
"""Sets the platform string identifier returned by get_platform().
if os.name != "posix" or not hasattr(os, 'uname'):
# XXX what about the architecture? NT is Intel or Alpha,
# Mac OS is M68k or PPC, etc.
return sys.platform
Note that this change doesn't impact the value returned by
sysconfig.get_platform() and is local to Distutils
"""
global _PLATFORM
_PLATFORM = identifier
# Try to distinguish various flavours of Unix
def convert_path(pathname):
"""Return 'pathname' as a name that will work on the native filesystem.
(osname, host, release, version, machine) = os.uname()
# Convert the OS name to lowercase, remove '/' characters
# (to accommodate BSD/OS), and translate spaces (for "Power Macintosh")
osname = string.lower(osname)
osname = string.replace(osname, '/', '')
machine = string.replace(machine, ' ', '_')
machine = string.replace(machine, '/', '-')
if osname[:5] == "linux":
# At least on Linux/Intel, 'machine' is the processor --
# i386, etc.
# XXX what about Alpha, SPARC, etc?
return "%s-%s" % (osname, machine)
elif osname[:5] == "sunos":
if release[0] >= "5": # SunOS 5 == Solaris 2
osname = "solaris"
release = "%d.%s" % (int(release[0]) - 3, release[2:])
# fall through to standard osname-release-machine representation
elif osname[:4] == "irix": # could be "irix64"!
return "%s-%s" % (osname, release)
elif osname[:3] == "aix":
return "%s-%s.%s" % (osname, version, release)
elif osname[:6] == "cygwin":
osname = "cygwin"
rel_re = re.compile (r'[\d.]+')
m = rel_re.match(release)
if m:
release = m.group()
elif osname[:6] == "darwin":
#
# For our purposes, we'll assume that the system version from
# distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
# to. This makes the compatibility story a bit more sane because the
# machine is going to compile and link as if it were
# MACOSX_DEPLOYMENT_TARGET.
from distutils.sysconfig import get_config_vars
cfgvars = get_config_vars()
macver = os.environ.get('MACOSX_DEPLOYMENT_TARGET')
if not macver:
macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET')
if 1:
# Always calculate the release of the running machine,
# needed to determine if we can build fat binaries or not.
macrelease = macver
# Get the system version. Reading this plist is a documented
# way to get the system version (see the documentation for
# the Gestalt Manager)
try:
f = open('/System/Library/CoreServices/SystemVersion.plist')
except IOError:
# We're on a plain darwin box, fall back to the default
# behaviour.
pass
else:
m = re.search(
r'<key>ProductUserVisibleVersion</key>\s*' +
r'<string>(.*?)</string>', f.read())
f.close()
if m is not None:
macrelease = '.'.join(m.group(1).split('.')[:2])
# else: fall back to the default behaviour
if not macver:
macver = macrelease
if macver:
from distutils.sysconfig import get_config_vars
release = macver
osname = "macosx"
if (macrelease + '.') >= '10.4.' and \
'-arch' in get_config_vars().get('CFLAGS', '').strip():
# The universal build will build fat binaries, but not on
# systems before 10.4
#
# Try to detect 4-way universal builds, those have machine-type
# 'universal' instead of 'fat'.
machine = 'fat'
cflags = get_config_vars().get('CFLAGS')
archs = re.findall('-arch\s+(\S+)', cflags)
archs.sort()
archs = tuple(archs)
if len(archs) == 1:
machine = archs[0]
elif archs == ('i386', 'ppc'):
machine = 'fat'
elif archs == ('i386', 'x86_64'):
machine = 'intel'
elif archs == ('i386', 'ppc', 'x86_64'):
machine = 'fat3'
elif archs == ('ppc64', 'x86_64'):
machine = 'fat64'
elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
machine = 'universal'
else:
raise ValueError(
"Don't know machine value for archs=%r"%(archs,))
elif machine == 'i386':
# On OSX the machine type returned by uname is always the
# 32-bit variant, even if the executable architecture is
# the 64-bit variant
if sys.maxint >= 2**32:
machine = 'x86_64'
elif machine in ('PowerPC', 'Power_Macintosh'):
# Pick a sane name for the PPC architecture.
machine = 'ppc'
# See 'i386' case
if sys.maxint >= 2**32:
machine = 'ppc64'
return "%s-%s-%s" % (osname, release, machine)
# get_platform ()
def convert_path (pathname):
"""Return 'pathname' as a name that will work on the native filesystem,
i.e. split it on '/' and put it back together again using the current
directory separator. Needed because filenames in the setup script are
always supplied in Unix style, and have to be converted to the local
@ -53,23 +197,23 @@ def convert_path(pathname):
if not pathname:
return pathname
if pathname[0] == '/':
raise ValueError("path '%s' cannot be absolute" % pathname)
raise ValueError, "path '%s' cannot be absolute" % pathname
if pathname[-1] == '/':
raise ValueError("path '%s' cannot end with '/'" % pathname)
raise ValueError, "path '%s' cannot end with '/'" % pathname
paths = pathname.split('/')
paths = string.split(pathname, '/')
while '.' in paths:
paths.remove('.')
if not paths:
return os.curdir
return os.path.join(*paths)
return apply(os.path.join, paths)
# convert_path ()
def change_root(new_root, pathname):
"""Return 'pathname' with 'new_root' prepended.
If 'pathname' is relative, this is equivalent to
"os.path.join(new_root,pathname)".
def change_root (new_root, pathname):
"""Return 'pathname' with 'new_root' prepended. If 'pathname' is
relative, this is equivalent to "os.path.join(new_root,pathname)".
Otherwise, it requires making 'pathname' relative and then joining the
two, which is tricky on DOS/Windows and Mac OS.
"""
@ -96,20 +240,19 @@ def change_root(new_root, pathname):
return os.path.join(new_root, pathname)
else:
# Chop off volume name from start of path
elements = pathname.split(":", 1)
elements = string.split(pathname, ":", 1)
pathname = ":" + elements[1]
return os.path.join(new_root, pathname)
else:
raise DistutilsPlatformError("nothing known about "
"platform '%s'" % os.name)
raise DistutilsPlatformError, \
"nothing known about platform '%s'" % os.name
_environ_checked = 0
def check_environ():
"""Ensure that 'os.environ' has all the environment variables needed.
We guarantee that users can use in config files, command-line options,
def check_environ ():
"""Ensure that 'os.environ' has all the environment variables we
guarantee that users can use in config files, command-line options,
etc. Currently this includes:
HOME - user's home directory (Unix only)
PLAT - description of the current platform, including hardware
@ -124,14 +267,14 @@ def check_environ():
os.environ['HOME'] = pwd.getpwuid(os.getuid())[5]
if 'PLAT' not in os.environ:
os.environ['PLAT'] = _sysconfig.get_platform()
os.environ['PLAT'] = get_platform()
_environ_checked = 1
def subst_vars(s, local_vars):
"""Perform shell/Perl-style variable substitution on 'string'.
Every occurrence of '$' followed by a name is considered a variable, and
def subst_vars (s, local_vars):
"""Perform shell/Perl-style variable substitution on 'string'. Every
occurrence of '$' followed by a name is considered a variable, and
variable is substituted by the value found in the 'local_vars'
dictionary, or in 'os.environ' if it's not in 'local_vars'.
'os.environ' is first checked/augmented to guarantee that it contains
@ -149,13 +292,14 @@ def subst_vars(s, local_vars):
try:
return re.sub(r'\$([a-zA-Z_][a-zA-Z_0-9]*)', _subst, s)
except KeyError, var:
raise ValueError("invalid variable '$%s'" % var)
raise ValueError, "invalid variable '$%s'" % var
def grok_environment_error(exc, prefix="error: "):
"""Generate a useful error message from an EnvironmentError.
# subst_vars ()
This will generate an IOError or an OSError exception object.
Handles Python 1.5.1 and 1.5.2 styles, and
def grok_environment_error (exc, prefix="error: "):
"""Generate a useful error message from an EnvironmentError (IOError or
OSError) exception object. Handles Python 1.5.1 and 1.5.2 styles, and
does what it can to deal with exception objects that don't have a
filename (which happens when the error is due to a two-file operation,
such as 'rename()' or 'link()'. Returns the error message as a string
@ -174,20 +318,18 @@ def grok_environment_error(exc, prefix="error: "):
return error
# Needed by 'split_quoted()'
_wordchars_re = _squote_re = _dquote_re = None
def _init_regex():
global _wordchars_re, _squote_re, _dquote_re
_wordchars_re = re.compile(r'[^\\\'\"%s ]*' % string.whitespace)
_squote_re = re.compile(r"'(?:[^'\\]|\\.)*'")
_dquote_re = re.compile(r'"(?:[^"\\]|\\.)*"')
def split_quoted(s):
def split_quoted (s):
"""Split a string up according to Unix shell-like rules for quotes and
backslashes.
In short: words are delimited by spaces, as long as those
backslashes. In short: words are delimited by spaces, as long as those
spaces are not escaped by a backslash, or inside a quoted string.
Single and double quotes are equivalent, and the quote characters can
be backslash-escaped. The backslash is stripped from any two-character
@ -195,12 +337,13 @@ def split_quoted(s):
characters are stripped from any quoted string. Returns a list of
words.
"""
# This is a nice algorithm for splitting up a single string, since it
# doesn't require character-by-character examination. It was a little
# bit of a brain-bender to get it working right, though...
if _wordchars_re is None: _init_regex()
s = s.strip()
s = string.strip(s)
words = []
pos = 0
@ -213,7 +356,7 @@ def split_quoted(s):
if s[end] in string.whitespace: # unescaped, unquoted whitespace: now
words.append(s[:end]) # we definitely have a word delimiter
s = s[end:].lstrip()
s = string.lstrip(s[end:])
pos = 0
elif s[end] == '\\': # preserve whatever is being escaped;
@ -227,11 +370,12 @@ def split_quoted(s):
elif s[end] == '"': # slurp doubly-quoted string
m = _dquote_re.match(s, end)
else:
raise RuntimeError("this can't happen "
"(bad char '%c')" % s[end])
raise RuntimeError, \
"this can't happen (bad char '%c')" % s[end]
if m is None:
raise ValueError("bad string (mismatched %s quotes?)" % s[end])
raise ValueError, \
"bad string (mismatched %s quotes?)" % s[end]
(beg, end) = m.span()
s = s[:beg] + s[beg+1:end-1] + s[end:]
@ -243,12 +387,13 @@ def split_quoted(s):
return words
# split_quoted ()
def execute(func, args, msg=None, verbose=0, dry_run=0):
"""Perform some action that affects the outside world.
eg. by writing to the filesystem). Such actions are special because
they are disabled by the 'dry_run' flag. This method takes care of all
def execute (func, args, msg=None, verbose=0, dry_run=0):
"""Perform some action that affects the outside world (eg. by
writing to the filesystem). Such actions are special because they
are disabled by the 'dry_run' flag. This method takes care of all
that bureaucracy for you; all you have to do is supply the
function to call and an argument tuple for it (to embody the
"external action" being performed), and an optional message to
@ -261,17 +406,17 @@ def execute(func, args, msg=None, verbose=0, dry_run=0):
log.info(msg)
if not dry_run:
func(*args)
apply(func, args)
def strtobool(val):
def strtobool (val):
"""Convert a string representation of truth to true (1) or false (0).
True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
'val' is anything else.
"""
val = val.lower()
val = string.lower(val)
if val in ('y', 'yes', 't', 'true', 'on', '1'):
return 1
elif val in ('n', 'no', 'f', 'false', 'off', '0'):
@ -280,13 +425,15 @@ def strtobool(val):
raise ValueError, "invalid truth value %r" % (val,)
def byte_compile(py_files, optimize=0, force=0, prefix=None, base_dir=None,
verbose=1, dry_run=0, direct=None):
def byte_compile (py_files,
optimize=0, force=0,
prefix=None, base_dir=None,
verbose=1, dry_run=0,
direct=None):
"""Byte-compile a collection of Python source files to either .pyc
or .pyo files in the same directory.
'py_files' is a list of files to compile; any files that don't end in
".py" are silently skipped. 'optimize' must be one of the following:
or .pyo files in the same directory. 'py_files' is a list of files
to compile; any files that don't end in ".py" are silently skipped.
'optimize' must be one of the following:
0 - don't optimize (generate .pyc)
1 - normal optimization (like "python -O")
2 - extra optimization (like "python -OO")
@ -363,7 +510,7 @@ files = [
#if prefix:
# prefix = os.path.abspath(prefix)
script.write(",\n".join(map(repr, py_files)) + "]\n")
script.write(string.join(map(repr, py_files), ",\n") + "]\n")
script.write("""
byte_compile(files, optimize=%r, force=%r,
prefix=%r, base_dir=%r,
@ -402,8 +549,9 @@ byte_compile(files, optimize=%r, force=%r,
dfile = file
if prefix:
if file[:len(prefix)] != prefix:
raise ValueError("invalid prefix: filename %r doesn't "
"start with %r" % (file, prefix))
raise ValueError, \
("invalid prefix: filename %r doesn't start with %r"
% (file, prefix))
dfile = dfile[len(prefix):]
if base_dir:
dfile = os.path.join(base_dir, dfile)
@ -418,61 +566,12 @@ byte_compile(files, optimize=%r, force=%r,
log.debug("skipping byte-compilation of %s to %s",
file, cfile_base)
# byte_compile ()
def rfc822_escape(header):
def rfc822_escape (header):
"""Return a version of the string escaped for inclusion in an
RFC-822 header, by ensuring there are 8 spaces space after each newline.
"""
lines = header.split('\n')
sep = '\n' + 8 * ' '
return sep.join(lines)
_RE_VERSION = re.compile('(\d+\.\d+(\.\d+)*)')
_MAC_OS_X_LD_VERSION = re.compile('^@\(#\)PROGRAM:ld PROJECT:ld64-((\d+)(\.\d+)*)')
def _find_ld_version():
"""Finds the ld version. The version scheme differs under Mac OSX."""
if sys.platform == 'darwin':
return _find_exe_version('ld -v', _MAC_OS_X_LD_VERSION)
else:
return _find_exe_version('ld -v')
def _find_exe_version(cmd, pattern=_RE_VERSION):
"""Find the version of an executable by running `cmd` in the shell.
`pattern` is a compiled regular expression. If not provided, default
to _RE_VERSION. If the command is not found, or the output does not
match the mattern, returns None.
"""
from subprocess import Popen, PIPE
executable = cmd.split()[0]
if find_executable(executable) is None:
return None
pipe = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)
try:
stdout, stderr = pipe.stdout.read(), pipe.stderr.read()
finally:
pipe.stdout.close()
pipe.stderr.close()
# some commands like ld under MacOS X, will give the
# output in the stderr, rather than stdout.
if stdout != '':
out_string = stdout
else:
out_string = stderr
result = pattern.search(out_string)
if result is None:
return None
return LooseVersion(result.group(1))
def get_compiler_versions():
"""Returns a tuple providing the versions of gcc, ld and dllwrap
For each command, if a command is not found, None is returned.
Otherwise a LooseVersion instance is returned.
"""
gcc = _find_exe_version('gcc -dumpversion')
ld = _find_ld_version()
dllwrap = _find_exe_version('dllwrap --version')
return gcc, ld, dllwrap
lines = string.split(header, '\n')
header = string.join(lines, '\n' + 8*' ')
return header