Latest distutils

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23252 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Robin Dunn
2003-08-27 00:20:37 +00:00
parent 21870a5d8d
commit e55c4dd1b1
13 changed files with 302 additions and 186 deletions

View File

@@ -1,18 +1,9 @@
This is a copy of the Distutils package from Python (currently version
2.3a2.) This newer copy of distutils is used for all versions of
2.3.) This newer copy of distutils is used for all versions of
Python to avoid some problems in the older versions that show up in
wxPython builds and to avoid having to make some ugly hacks in local
modules to work around them.
There is one little 1-line customization (hack) in msvccompiler.py
that allows the CFLAGS to be given on the RC.EXE command line. This
is required so the wx.rc files can be found when it is #included. I've
submitted this patch to the Python project so if it gets into the main
Distutils distribution I can remove this code. (However, the newer
version of distutils should still always be used, at least on Windows,
so it will need to wait until there it a Distutils distribution that
can be installed on the older Pythons.)
I have not yet applied any patches specifically for MSCV 7 yet. So
far it appears that if you have the PATH setup properly (like I
usually do) that distutils works as is.

View File

@@ -883,6 +883,51 @@ class CCompiler:
"""
raise NotImplementedError
def has_function(self, funcname,
includes=None,
include_dirs=None,
libraries=None,
library_dirs=None):
"""Return a boolean indicating whether funcname is supported on
the current platform. The optional arguments can be used to
augment the compilation environment.
"""
# this can't be included at module scope because it tries to
# import math which might not be available at that point - maybe
# the necessary logic should just be inlined?
import tempfile
if includes is None:
includes = []
if include_dirs is None:
include_dirs = []
if libraries is None:
libraries = []
if library_dirs is None:
library_dirs = []
fd, fname = tempfile.mkstemp(".c", funcname, text=True)
f = os.fdopen(fd, "w")
for incl in includes:
f.write("""#include "%s"\n""" % incl)
f.write("""\
main (int argc, char **argv) {
%s();
}
""" % funcname)
f.close()
try:
objects = self.compile([fname], include_dirs=include_dirs)
except CompileError:
return False
try:
self.link_executable(objects, "a.out",
libraries=libraries,
library_dirs=library_dirs)
except (LinkError, TypeError):
return False
return True
def find_library_file (self, dirs, lib, debug=0):
"""Search the specified list of directories for a static or shared
library file 'lib' and return the full path to that file. If
@@ -932,6 +977,8 @@ class CCompiler:
obj_names = []
for src_name in source_filenames:
base, ext = os.path.splitext(src_name)
base = os.path.splitdrive(base)[1] # Chop off the drive
base = base[os.path.isabs(base):] # If abs, chop off leading /
if ext not in self.src_extensions:
raise UnknownFileError, \
"unknown file type '%s' (from '%s')" % (ext, src_name)

View File

@@ -191,7 +191,7 @@ class Command:
"""If the current verbosity level is of greater than or equal to
'level' print 'msg' to stdout.
"""
log.debug(msg)
log.log(level, msg)
def debug_print (self, msg):
"""Print 'msg' to stdout if the global DEBUG (taken from the

View File

@@ -19,6 +19,7 @@ __all__ = ['build',
'install_scripts',
'install_data',
'sdist',
'register',
'bdist',
'bdist_dumb',
'bdist_rpm',

View File

@@ -100,7 +100,7 @@ class bdist_wininst (Command):
if not self.skip_build:
self.run_command('build')
install = self.reinitialize_command('install')
install = self.reinitialize_command('install', reinit_subcommands=1)
install.root = self.bdist_dir
install.skip_build = self.skip_build
install.warn_dir = 0

View File

@@ -86,25 +86,11 @@ class build_py (Command):
# Two options control which modules will be installed: 'packages'
# and 'py_modules'. The former lets us work with whole packages, not
# specifying individual modules at all; the latter is for
# specifying modules one-at-a-time. Currently they are mutually
# exclusive: you can define one or the other (or neither), but not
# both. It remains to be seen how limiting this is.
# specifying modules one-at-a-time.
# Dispose of the two "unusual" cases first: no pure Python modules
# at all (no problem, just return silently), and over-specified
# 'packages' and 'py_modules' options.
if not self.py_modules and not self.packages:
return
if self.py_modules and self.packages:
raise DistutilsOptionError, \
"build_py: supplying both 'packages' and 'py_modules' " + \
"options is not allowed"
# Now we're down to two cases: 'py_modules' only and 'packages' only.
if self.py_modules:
self.build_modules()
else:
if self.packages:
self.build_packages()
self.byte_compile(self.get_outputs(include_bytecode=0))
@@ -276,10 +262,10 @@ class build_py (Command):
(package, module, module_file), just like 'find_modules()' and
'find_package_modules()' do."""
modules = []
if self.py_modules:
modules = self.find_modules()
else:
modules = []
modules.extend(self.find_modules())
if self.packages:
for package in self.packages:
package_dir = self.get_package_dir(package)
m = self.find_package_modules(package, package_dir)

View File

@@ -15,7 +15,7 @@ from distutils.util import convert_path
from distutils import log
# check if Python is called on the first line with this expression
first_line_re = re.compile(r'^#!.*python[0-9.]*(\s+.*)?$')
first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$')
class build_scripts (Command):
@@ -96,7 +96,7 @@ class build_scripts (Command):
(os.path.normpath(sys.executable),
post_interp))
else:
outf.write("#!%s%s" %
outf.write("#!%s%s\n" %
(os.path.join(
sysconfig.get_config_var("BINDIR"),
"python" + sysconfig.get_config_var("EXE")),

View File

@@ -15,15 +15,13 @@ from distutils.errors import *
class register(Command):
description = "register the distribution with the repository"
description = ("register the distribution with the Python package index")
DEFAULT_REPOSITORY = 'http://www.python.org/pypi'
user_options = [
('repository=', 'r',
"url of repository [default: %s]"%DEFAULT_REPOSITORY),
('verify', None,
'verify the package metadata for correctness'),
('list-classifiers', None,
'list the valid Trove classifiers'),
('show-response', None,
@@ -33,7 +31,6 @@ class register(Command):
def initialize_options(self):
self.repository = None
self.verify = 0
self.show_response = 0
self.list_classifiers = 0
@@ -43,7 +40,7 @@ class register(Command):
def run(self):
self.check_metadata()
if self.verify:
if self.dry_run:
self.verify_metadata()
elif self.list_classifiers:
self.classifiers()

View File

@@ -40,6 +40,10 @@ cygwin in no-cygwin mode).
# this is windows standard and there are normally not the necessary symbols
# in the dlls.
# *** only the version of June 2000 shows these problems
# * cygwin gcc 3.2/ld 2.13.90 works
# (ld supports -shared)
# * mingw gcc 3.2/ld 2.13 works
# (ld supports -shared)
# This module should be kept compatible with Python 1.5.2.
@@ -83,7 +87,7 @@ class CygwinCCompiler (UnixCCompiler):
self.ld_version,
self.dllwrap_version) )
# ld_version >= "2.10.90" should also be able to use
# ld_version >= "2.10.90" and < "2.13" should also be able to use
# gcc -mdll instead of dllwrap
# Older dllwraps had own version numbers, newer ones use the
# same as the rest of binutils ( also ld )
@@ -93,13 +97,20 @@ class CygwinCCompiler (UnixCCompiler):
else:
self.linker_dll = "dllwrap"
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
if self.ld_version >= "2.13":
shared_option = "-shared"
else:
shared_option = "-mdll -static"
# Hard-code GCC because that's what this is all about.
# XXX optimization, warnings etc. should be customizable.
self.set_executables(compiler='gcc -mcygwin -O -Wall',
compiler_so='gcc -mcygwin -mdll -O -Wall',
linker_exe='gcc -mcygwin',
linker_so=('%s -mcygwin -mdll -static' %
self.linker_dll))
linker_so=('%s -mcygwin %s' %
(self.linker_dll, shared_option)))
# cygwin and mingw32 need different sets of libraries
if self.gcc_version == "2.91.57":
@@ -268,6 +279,13 @@ class Mingw32CCompiler (CygwinCCompiler):
CygwinCCompiler.__init__ (self, verbose, dry_run, force)
# ld_version >= "2.13" support -shared so use it instead of
# -mdll -static
if self.ld_version >= "2.13":
shared_option = "-shared"
else:
shared_option = "-mdll -static"
# A real mingw32 doesn't need to specify a different entry point,
# but cygwin 2.91.57 in no-cygwin-mode needs it.
if self.gcc_version <= "2.91.57":
@@ -278,8 +296,9 @@ class Mingw32CCompiler (CygwinCCompiler):
self.set_executables(compiler='gcc -mno-cygwin -O -Wall',
compiler_so='gcc -mno-cygwin -mdll -O -Wall',
linker_exe='gcc -mno-cygwin',
linker_so='%s -mno-cygwin -mdll -static %s'
% (self.linker_dll, entry_point))
linker_so='%s -mno-cygwin %s %s'
% (self.linker_dll, shared_option,
entry_point))
# Maybe we should also append -mthreads, but then the finished
# dlls need another dll (mingwm10.dll see Mingw32 docs)
# (-mthreads: Support thread-safe exception handling on `Mingw32')
@@ -363,7 +382,7 @@ def get_versions():
out = os.popen(gcc_exe + ' -dumpversion','r')
out_string = out.read()
out.close()
result = re.search('(\d+\.\d+\.\d+)',out_string)
result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
if result:
gcc_version = StrictVersion(result.group(1))
else:
@@ -375,7 +394,7 @@ def get_versions():
out = os.popen(ld_exe + ' -v','r')
out_string = out.read()
out.close()
result = re.search('(\d+\.\d+\.\d+)',out_string)
result = re.search('(\d+\.\d+(\.\d+)*)',out_string)
if result:
ld_version = StrictVersion(result.group(1))
else:
@@ -387,7 +406,7 @@ def get_versions():
out = os.popen(dllwrap_exe + ' --version','r')
out_string = out.read()
out.close()
result = re.search(' (\d+\.\d+\.\d+)',out_string)
result = re.search(' (\d+\.\d+(\.\d+)*)',out_string)
if result:
dllwrap_version = StrictVersion(result.group(1))
else:

View File

@@ -205,6 +205,15 @@ class Distribution:
for (opt, val) in cmd_options.items():
opt_dict[opt] = ("setup script", val)
if attrs.has_key('licence'):
attrs['license'] = attrs['licence']
del attrs['licence']
msg = "'licence' distribution option is deprecated; use 'license'"
if warnings is not None:
warnings.warn(msg)
else:
sys.stderr.write(msg + "\n")
# Now work on the rest of the attributes. Any attribute that's
# not already defined is invalid!
for (key,val) in attrs.items():
@@ -966,7 +975,7 @@ class DistributionMetadata:
"maintainer", "maintainer_email", "url",
"license", "description", "long_description",
"keywords", "platforms", "fullname", "contact",
"contact_email", "licence", "classifiers",
"contact_email", "license", "classifiers",
"download_url")
def __init__ (self):

View File

@@ -53,9 +53,9 @@ def set_threshold(level):
_global_log.threshold = level
def set_verbosity(v):
if v == 0:
if v <= 0:
set_threshold(WARN)
if v == 1:
elif v == 1:
set_threshold(INFO)
if v == 2:
elif v >= 2:
set_threshold(DEBUG)

View File

@@ -1,7 +1,8 @@
"""distutils.msvccompiler
Contains MSVCCompiler, an implementation of the abstract CCompiler class
for the Microsoft Visual Studio."""
for the Microsoft Visual Studio.
"""
# Written by Perry Stoll
# hacked by Robin Becker and Thomas Heller to do a better job of
@@ -12,7 +13,6 @@ for the Microsoft Visual Studio."""
__revision__ = "$Id$"
import sys, os, string
from types import *
from distutils.errors import \
DistutilsExecError, DistutilsPlatformError, \
CompileError, LibError, LinkError
@@ -45,129 +45,128 @@ except ImportError:
RegError = win32api.error
except ImportError:
log.info("Warning: Can't read registry to find the "
"necessary compiler setting\n"
"Make sure that Python modules _winreg, "
"win32api or win32con are installed.")
pass
if _can_read_reg:
HKEY_CLASSES_ROOT = hkey_mod.HKEY_CLASSES_ROOT
HKEY_LOCAL_MACHINE = hkey_mod.HKEY_LOCAL_MACHINE
HKEY_CURRENT_USER = hkey_mod.HKEY_CURRENT_USER
HKEY_USERS = hkey_mod.HKEY_USERS
HKEYS = (hkey_mod.HKEY_USERS,
hkey_mod.HKEY_CURRENT_USER,
hkey_mod.HKEY_LOCAL_MACHINE,
hkey_mod.HKEY_CLASSES_ROOT)
def read_keys(base, key):
"""Return list of registry keys."""
def get_devstudio_versions ():
"""Get list of devstudio versions from the Windows registry. Return a
list of strings containing version numbers; the list will be
empty if we were unable to access the registry (eg. couldn't import
a registry-access module) or the appropriate registry keys weren't
found."""
if not _can_read_reg:
return []
K = 'Software\\Microsoft\\Devstudio'
try:
handle = RegOpenKeyEx(base, key)
except RegError:
return None
L = []
for base in (HKEY_CLASSES_ROOT,
HKEY_LOCAL_MACHINE,
HKEY_CURRENT_USER,
HKEY_USERS):
i = 0
while 1:
try:
k = RegOpenKeyEx(base,K)
i = 0
while 1:
try:
p = RegEnumKey(k,i)
if p[0] in '123456789' and p not in L:
L.append(p)
except RegError:
break
i = i + 1
k = RegEnumKey(handle, i)
except RegError:
pass
L.sort()
L.reverse()
break
L.append(k)
i = i + 1
return L
# get_devstudio_versions ()
def read_values(base, key):
"""Return dict of registry keys and values.
def get_msvc_paths (path, version='6.0', platform='x86'):
"""Get a list of devstudio directories (include, lib or path). Return
a list of strings; will be empty list if unable to access the
registry or appropriate registry keys not found."""
if not _can_read_reg:
return []
L = []
if path=='lib':
path= 'Library'
path = string.upper(path + ' Dirs')
K = ('Software\\Microsoft\\Devstudio\\%s\\' +
'Build System\\Components\\Platforms\\Win32 (%s)\\Directories') % \
(version,platform)
for base in (HKEY_CLASSES_ROOT,
HKEY_LOCAL_MACHINE,
HKEY_CURRENT_USER,
HKEY_USERS):
All names are converted to lowercase.
"""
try:
handle = RegOpenKeyEx(base, key)
except RegError:
return None
d = {}
i = 0
while 1:
try:
k = RegOpenKeyEx(base,K)
i = 0
while 1:
try:
(p,v,t) = RegEnumValue(k,i)
if string.upper(p) == path:
V = string.split(v,';')
for v in V:
if hasattr(v, "encode"):
try:
v = v.encode("mbcs")
except UnicodeError:
pass
if v == '' or v in L: continue
L.append(v)
break
i = i + 1
except RegError:
break
name, value, type = RegEnumValue(handle, i)
except RegError:
break
name = name.lower()
d[convert_mbcs(name)] = convert_mbcs(value)
i = i + 1
return d
def convert_mbcs(s):
enc = getattr(s, "encode", None)
if enc is not None:
try:
s = enc("mbcs")
except UnicodeError:
pass
return L
return s
# get_msvc_paths()
class MacroExpander:
def __init__(self, version):
self.macros = {}
self.load_macros(version)
def find_exe (exe, version_number):
"""Try to find an MSVC executable program 'exe' (from version
'version_number' of MSVC) in several places: first, one of the MSVC
program search paths from the registry; next, the directories in the
PATH environment variable. If any of those work, return an absolute
path that is known to exist. If none of them work, just return the
original program name, 'exe'."""
def set_macro(self, macro, path, key):
for base in HKEYS:
d = read_values(base, path)
if d:
self.macros["$(%s)" % macro] = d[key]
break
def load_macros(self, version):
vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
net = r"Software\Microsoft\.NETFramework"
self.set_macro("FrameworkDir", net, "installroot")
if version > 7.0:
self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
else:
self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
for p in get_msvc_paths ('path', version_number):
fn = os.path.join (os.path.abspath(p), exe)
if os.path.isfile(fn):
return fn
p = r"Software\Microsoft\NET Framework Setup\Product"
for base in HKEYS:
try:
h = RegOpenKeyEx(base, p)
except RegError:
continue
key = RegEnumKey(h, 0)
d = read_values(base, r"%s\%s" % (p, key))
self.macros["$(FrameworkVersion)"] = d["version"]
# didn't find it; try existing path
for p in string.split (os.environ['Path'],';'):
fn = os.path.join(os.path.abspath(p),exe)
if os.path.isfile(fn):
return fn
def sub(self, s):
for k, v in self.macros.items():
s = string.replace(s, k, v)
return s
return exe # last desperate hope
def get_build_version():
"""Return the version of MSVC that was used to build Python.
For Python 2.3 and up, the version number is included in
sys.version. For earlier versions, assume the compiler is MSVC 6.
"""
def set_path_env_var (name, version_number):
"""Set environment variable 'name' to an MSVC path type value obtained
from 'get_msvc_paths()'. This is equivalent to a SET command prior
to execution of spawned commands."""
p = get_msvc_paths (name, version_number)
if p:
os.environ[name] = string.join (p,';')
prefix = "MSC v."
i = string.find(sys.version, prefix)
if i == -1:
return 6
i = i + len(prefix)
s, rest = sys.version[i:].split(" ", 1)
majorVersion = int(s[:-2]) - 6
minorVersion = int(s[2:3]) / 10.0
# I don't think paths are affected by minor version in version 6
if majorVersion == 6:
minorVersion = 0
if majorVersion >= 6:
return majorVersion + minorVersion
# else we don't know what version of the compiler this is
return None
class MSVCCompiler (CCompiler) :
"""Concrete class that implements an interface to Microsoft Visual C++,
@@ -199,39 +198,37 @@ class MSVCCompiler (CCompiler) :
static_lib_format = 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):
CCompiler.__init__ (self, verbose, dry_run, force)
versions = get_devstudio_versions ()
if versions:
version = versions[0] # highest version
self.cc = find_exe("cl.exe", version)
self.linker = find_exe("link.exe", version)
self.lib = find_exe("lib.exe", version)
self.rc = find_exe("rc.exe", version) # resource compiler
self.mc = find_exe("mc.exe", version) # message compiler
set_path_env_var ('lib', version)
set_path_env_var ('include', version)
path=get_msvc_paths('path', version)
try:
for p in string.split(os.environ['path'],';'):
path.append(p)
except KeyError:
pass
os.environ['path'] = string.join(path,';')
self.__version = get_build_version()
if self.__version >= 7:
self.__root = r"Software\Microsoft\VisualStudio"
self.__macros = MacroExpander(self.__version)
else:
# devstudio not found in the registry
self.cc = "cl.exe"
self.linker = "link.exe"
self.lib = "lib.exe"
self.rc = "rc.exe"
self.mc = "mc.exe"
self.__root = r"Software\Microsoft\Devstudio"
self.__paths = self.get_msvc_paths("path")
if len (self.__paths) == 0:
raise DistutilsPlatformError, \
("Python was built with version %s of Visual Studio, "
"and extensions need to be built with the same "
"version of the compiler, but it isn't installed." % self.__version)
self.cc = self.find_exe("cl.exe")
self.linker = self.find_exe("link.exe")
self.lib = self.find_exe("lib.exe")
self.rc = self.find_exe("rc.exe") # resource compiler
self.mc = self.find_exe("mc.exe") # message compiler
self.set_path_env_var('lib')
self.set_path_env_var('include')
# extend the MSVC path with the current path
try:
for p in string.split(os.environ['path'], ';'):
self.__paths.append(p)
except KeyError:
pass
os.environ['path'] = string.join(self.__paths, ';')
self.preprocess_options = None
self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
@@ -500,4 +497,69 @@ class MSVCCompiler (CCompiler) :
# find_library_file ()
# class MSVCCompiler
# Helper methods for using the MSVC registry settings
def find_exe(self, exe):
"""Return path to an MSVC executable program.
Tries to find the program in several places: first, one of the
MSVC program search paths from the registry; next, the directories
in the PATH environment variable. If any of those work, return an
absolute path that is known to exist. If none of them work, just
return the original program name, 'exe'.
"""
for p in self.__paths:
fn = os.path.join(os.path.abspath(p), exe)
if os.path.isfile(fn):
return fn
# didn't find it; try existing path
for p in string.split(os.environ['Path'],';'):
fn = os.path.join(os.path.abspath(p),exe)
if os.path.isfile(fn):
return fn
return exe
def get_msvc_paths(self, path, platform='x86'):
"""Get a list of devstudio directories (include, lib or path).
Return a list of strings. The list will be empty if unable to
access the registry or appropriate registry keys not found.
"""
if not _can_read_reg:
return []
path = path + " dirs"
if self.__version >= 7:
key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
% (self.__root, self.__version))
else:
key = (r"%s\6.0\Build System\Components\Platforms"
r"\Win32 (%s)\Directories" % (self.__root, platform))
for base in HKEYS:
d = read_values(base, key)
if d:
if self.__version >= 7:
return string.split(self.__macros.sub(d[path]), ";")
else:
return string.split(d[path], ";")
return []
def set_path_env_var(self, name):
"""Set environment variable 'name' to an MSVC path type value.
This is equivalent to a SET command prior to execution of spawned
commands.
"""
if name == "lib":
p = self.get_msvc_paths("library")
else:
p = self.get_msvc_paths(name)
if p:
os.environ[name] = string.join(p, ';')

View File

@@ -77,6 +77,8 @@ class UnixCCompiler(CCompiler):
shared_lib_extension = ".so"
dylib_lib_extension = ".dylib"
static_lib_format = shared_lib_format = dylib_lib_format = "lib%s%s"
if sys.platform == "cygwin":
exe_extension = ".exe"
def preprocess(self, source,
output_file=None, macros=None, include_dirs=None,
@@ -201,8 +203,10 @@ class UnixCCompiler(CCompiler):
if sys.platform[:6] == "darwin":
# MacOSX's linker doesn't understand the -R flag at all
return "-L" + dir
elif sys.platform[:5] == "hp-ux":
return "+s -L" + dir
elif compiler[:3] == "gcc" or compiler[:3] == "g++":
return "-Wl,-R" + dir
return "-Wl,-R" + dir
else:
return "-R" + dir