diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index 420d7f171dc..8248089fec0 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -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 diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index fb17b4f6ea9..44c76926ea6 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -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 diff --git a/Lib/distutils/cygwinccompiler.py b/Lib/distutils/cygwinccompiler.py index 2a61bd5ad71..2dabc0f0feb 100644 --- a/Lib/distutils/cygwinccompiler.py +++ b/Lib/distutils/cygwinccompiler.py @@ -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) diff --git a/Lib/distutils/emxccompiler.py b/Lib/distutils/emxccompiler.py index f2f77e52d1e..f52e63232db 100644 --- a/Lib/distutils/emxccompiler.py +++ b/Lib/distutils/emxccompiler.py @@ -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) diff --git a/Lib/distutils/extension.py b/Lib/distutils/extension.py index 244b1e78ec3..440d128cdc6 100644 --- a/Lib/distutils/extension.py +++ b/Lib/distutils/extension.py @@ -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 # ... [ ...] [ ...] [ ...] @@ -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 () diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index a247bc2cd74..54ccec49531 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -7,51 +7,59 @@ available. Written by: Fred L. Drake, Jr. Email: - -**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) diff --git a/Lib/distutils/tests/test_cygwinccompiler.py b/Lib/distutils/tests/test_cygwinccompiler.py deleted file mode 100644 index e97ac666a65..00000000000 --- a/Lib/distutils/tests/test_cygwinccompiler.py +++ /dev/null @@ -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()) diff --git a/Lib/distutils/tests/test_emxccompiler.py b/Lib/distutils/tests/test_emxccompiler.py deleted file mode 100644 index d5e07dcede7..00000000000 --- a/Lib/distutils/tests/test_emxccompiler.py +++ /dev/null @@ -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()) diff --git a/Lib/distutils/tests/test_extension.py b/Lib/distutils/tests/test_extension.py deleted file mode 100755 index 0b5dfb826ff..00000000000 --- a/Lib/distutils/tests/test_extension.py +++ /dev/null @@ -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") diff --git a/Lib/distutils/tests/test_install.py b/Lib/distutils/tests/test_install.py index 8e3e942f021..c834b91b38f 100644 --- a/Lib/distutils/tests/test_install.py +++ b/Lib/distutils/tests/test_install.py @@ -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) diff --git a/Lib/distutils/tests/test_unixccompiler.py b/Lib/distutils/tests/test_unixccompiler.py index 6976dd55f8f..3f233e28239 100644 --- a/Lib/distutils/tests/test_unixccompiler.py +++ b/Lib/distutils/tests/test_unixccompiler.py @@ -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(): diff --git a/Lib/distutils/tests/test_util.py b/Lib/distutils/tests/test_util.py index 348b42be03f..981ad000da5 100644 --- a/Lib/distutils/tests/test_util.py +++ b/Lib/distutils/tests/test_util.py @@ -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 diff --git a/Lib/distutils/unixccompiler.py b/Lib/distutils/unixccompiler.py index 8fe1a6a13ac..783d4dca843 100644 --- a/Lib/distutils/unixccompiler.py +++ b/Lib/distutils/unixccompiler.py @@ -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): diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index fbd3a672438..36ac7213865 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -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'ProductUserVisibleVersion\s*' + + r'(.*?)', 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