diff options
author | Mark Hammond <mhammond@skippinet.com.au> | 2008-04-07 01:53:39 (GMT) |
---|---|---|
committer | Mark Hammond <mhammond@skippinet.com.au> | 2008-04-07 01:53:39 (GMT) |
commit | 495cf99aaf40fb1c0859e528d5b2c52018fba09f (patch) | |
tree | 7eccc4215be221e4f5aae27a487e69d8057c2465 /Lib | |
parent | aa63d0d4af3db832b390ac74517af5eb799540e5 (diff) | |
download | cpython-495cf99aaf40fb1c0859e528d5b2c52018fba09f.zip cpython-495cf99aaf40fb1c0859e528d5b2c52018fba09f.tar.gz cpython-495cf99aaf40fb1c0859e528d5b2c52018fba09f.tar.bz2 |
Issue #2513: enable 64bit cross compilation on windows.
Diffstat (limited to 'Lib')
-rw-r--r-- | Lib/distutils/command/bdist.py | 6 | ||||
-rw-r--r-- | Lib/distutils/command/bdist_msi.py | 20 | ||||
-rw-r--r-- | Lib/distutils/command/bdist_wininst.py | 28 | ||||
-rw-r--r-- | Lib/distutils/command/build.py | 18 | ||||
-rw-r--r-- | Lib/distutils/command/build_ext.py | 30 | ||||
-rw-r--r-- | Lib/distutils/command/install.py | 9 | ||||
-rw-r--r-- | Lib/distutils/command/wininst-9.0-amd64.exe | bin | 0 -> 76288 bytes | |||
-rw-r--r-- | Lib/distutils/msvc9compiler.py | 72 | ||||
-rw-r--r-- | Lib/distutils/msvccompiler.py | 2 | ||||
-rw-r--r-- | Lib/distutils/util.py | 4 |
10 files changed, 135 insertions, 54 deletions
diff --git a/Lib/distutils/command/bdist.py b/Lib/distutils/command/bdist.py index d6897d2..ca3da74 100644 --- a/Lib/distutils/command/bdist.py +++ b/Lib/distutils/command/bdist.py @@ -97,7 +97,10 @@ class bdist (Command): def finalize_options (self): # have to finalize 'plat_name' before 'bdist_base' if self.plat_name is None: - self.plat_name = get_platform() + if self.skip_build: + self.plat_name = get_platform() + else: + self.plat_name = self.get_finalized_command('build').plat_name # 'bdist_base' -- parent of per-built-distribution-format # temporary directories (eg. we'll probably have @@ -121,7 +124,6 @@ class bdist (Command): # finalize_options() - def run (self): # Figure out which sub-commands we need to run. diff --git a/Lib/distutils/command/bdist_msi.py b/Lib/distutils/command/bdist_msi.py index a401452..f94d957 100644 --- a/Lib/distutils/command/bdist_msi.py +++ b/Lib/distutils/command/bdist_msi.py @@ -9,11 +9,11 @@ Implements the bdist_msi command. import sys, os from distutils.core import Command -from distutils.util import get_platform from distutils.dir_util import remove_tree from distutils.sysconfig import get_python_version from distutils.version import StrictVersion from distutils.errors import DistutilsOptionError +from distutils.util import get_platform from distutils import log import msilib from msilib import schema, sequence, text @@ -87,6 +87,9 @@ class bdist_msi (Command): user_options = [('bdist-dir=', None, "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), ('keep-temp', 'k', "keep the pseudo-installation tree around after " + "creating the distribution archive"), @@ -116,6 +119,7 @@ class bdist_msi (Command): def initialize_options (self): self.bdist_dir = None + self.plat_name = None self.keep_temp = 0 self.no_target_compile = 0 self.no_target_optimize = 0 @@ -139,7 +143,10 @@ class bdist_msi (Command): else: self.target_version = short_version - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + self.set_undefined_options('bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ) if self.pre_install_script: raise DistutilsOptionError, "the pre-install-script feature is not yet implemented" @@ -181,7 +188,7 @@ class bdist_msi (Command): if not target_version: assert self.skip_build, "Should have already checked this" target_version = sys.version[0:3] - plat_specifier = ".%s-%s" % (get_platform(), target_version) + plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) @@ -633,8 +640,7 @@ class bdist_msi (Command): def get_installer_filename(self, fullname): # Factored out to allow overriding in subclasses - plat = get_platform() - installer_name = os.path.join(self.dist_dir, - "%s.%s-py%s.msi" % - (fullname, plat, self.target_version)) + base_name = "%s.%s-py%s.msi" % (fullname, self.plat_name, + self.target_version) + installer_name = os.path.join(self.dist_dir, base_name) return installer_name diff --git a/Lib/distutils/command/bdist_wininst.py b/Lib/distutils/command/bdist_wininst.py index b0691fb..02542af 100644 --- a/Lib/distutils/command/bdist_wininst.py +++ b/Lib/distutils/command/bdist_wininst.py @@ -21,6 +21,9 @@ class bdist_wininst (Command): user_options = [('bdist-dir=', None, "temporary directory for creating the distribution"), + ('plat-name=', 'p', + "platform name to embed in generated filenames " + "(default: %s)" % get_platform()), ('keep-temp', 'k', "keep the pseudo-installation tree around after " + "creating the distribution archive"), @@ -54,6 +57,7 @@ class bdist_wininst (Command): def initialize_options (self): self.bdist_dir = None + self.plat_name = None self.keep_temp = 0 self.no_target_compile = 0 self.no_target_optimize = 0 @@ -82,7 +86,10 @@ class bdist_wininst (Command): " option must be specified" % (short_version,) self.target_version = short_version - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + self.set_undefined_options('bdist', + ('dist_dir', 'dist_dir'), + ('plat_name', 'plat_name'), + ) if self.install_script: for script in self.distribution.scripts: @@ -110,6 +117,7 @@ class bdist_wininst (Command): install.root = self.bdist_dir install.skip_build = self.skip_build install.warn_dir = 0 + install.plat_name = self.plat_name install_lib = self.reinitialize_command('install_lib') # we do not want to include pyc or pyo files @@ -127,7 +135,7 @@ class bdist_wininst (Command): if not target_version: assert self.skip_build, "Should have already checked this" target_version = sys.version[0:3] - plat_specifier = ".%s-%s" % (get_platform(), target_version) + plat_specifier = ".%s-%s" % (self.plat_name, target_version) build = self.get_finalized_command('build') build.build_lib = os.path.join(build.build_base, 'lib' + plat_specifier) @@ -285,11 +293,11 @@ class bdist_wininst (Command): # if we create an installer for a specific python version, # it's better to include this in the name installer_name = os.path.join(self.dist_dir, - "%s.win32-py%s.exe" % - (fullname, self.target_version)) + "%s.%s-py%s.exe" % + (fullname, self.plat_name, self.target_version)) else: installer_name = os.path.join(self.dist_dir, - "%s.win32.exe" % fullname) + "%s.%s.exe" % (fullname, self.plat_name)) return installer_name # get_installer_filename() @@ -312,9 +320,9 @@ class bdist_wininst (Command): bv = get_build_version() else: if self.target_version < "2.4": - bv = "6" + bv = 6.0 else: - bv = "7.1" + bv = 7.1 else: # for current version - use authoritative check. bv = get_build_version() @@ -323,6 +331,10 @@ class bdist_wininst (Command): directory = os.path.dirname(__file__) # we must use a wininst-x.y.exe built with the same C compiler # used for python. XXX What about mingw, borland, and so on? - filename = os.path.join(directory, "wininst-%.1f.exe" % bv) + if self.plat_name == 'win32': + sfix = '' + else: + sfix = self.plat_name[3:] # strip 'win' - leaves eg '-amd64' + filename = os.path.join(directory, "wininst-%.1f%s.exe" % (bv, sfix)) return open(filename, "rb").read() # class bdist_wininst diff --git a/Lib/distutils/command/build.py b/Lib/distutils/command/build.py index bca031f..7462e93 100644 --- a/Lib/distutils/command/build.py +++ b/Lib/distutils/command/build.py @@ -8,6 +8,7 @@ __revision__ = "$Id$" import sys, os from distutils.core import Command +from distutils.errors import DistutilsOptionError from distutils.util import get_platform @@ -34,6 +35,9 @@ class build (Command): "build directory for scripts"), ('build-temp=', 't', "temporary build directory"), + ('plat-name=', 'p', + "platform name to build for, if supported " + "(default: %s)" % get_platform()), ('compiler=', 'c', "specify the compiler type"), ('debug', 'g', @@ -61,13 +65,25 @@ class build (Command): self.build_temp = None self.build_scripts = None self.compiler = None + self.plat_name = None self.debug = None self.force = 0 self.executable = None def finalize_options (self): - plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) + if self.plat_name is None: + self.plat_name = get_platform() + else: + # plat-name only supported for windows (other platforms are + # supported via ./configure flags, if at all). Avoid misleading + # other platforms. + if os.name != 'nt': + raise DistutilsOptionError( + "--plat-name only supported on Windows (try " + "using './configure --help' on your platform)") + + plat_specifier = ".%s-%s" % (self.plat_name, sys.version[0:3]) # Make it so Python 2.x and Python 2.x with --with-pydebug don't # share the same build directories. Doing so confuses the build diff --git a/Lib/distutils/command/build_ext.py b/Lib/distutils/command/build_ext.py index 3042fe0..bf5ad7e 100644 --- a/Lib/distutils/command/build_ext.py +++ b/Lib/distutils/command/build_ext.py @@ -15,6 +15,7 @@ from distutils.errors import * from distutils.sysconfig import customize_compiler, get_python_version from distutils.dep_util import newer_group from distutils.extension import Extension +from distutils.util import get_platform from distutils import log if os.name == 'nt': @@ -60,6 +61,9 @@ class build_ext (Command): "directory for compiled extension modules"), ('build-temp=', 't', "directory for temporary files (build by-products)"), + ('plat-name=', 'p', + "platform name to cross-compile for, if supported " + "(default: %s)" % get_platform()), ('inplace', 'i', "ignore build-lib and put compiled extensions into the source " + "directory alongside your pure Python modules"), @@ -101,6 +105,7 @@ class build_ext (Command): def initialize_options (self): self.extensions = None self.build_lib = None + self.plat_name = None self.build_temp = None self.inplace = 0 self.package = None @@ -127,7 +132,9 @@ class build_ext (Command): ('build_temp', 'build_temp'), ('compiler', 'compiler'), ('debug', 'debug'), - ('force', 'force')) + ('force', 'force'), + ('plat_name', 'plat_name'), + ) if self.package is None: self.package = self.distribution.ext_package @@ -171,6 +178,9 @@ class build_ext (Command): # for Release and Debug builds. # also Python's library directory must be appended to library_dirs if os.name == 'nt': + # the 'libs' directory is for binary installs - we assume that + # must be the *native* platform. But we don't really support + # cross-compiling via a binary install anyway, so we let it go. self.library_dirs.append(os.path.join(sys.exec_prefix, 'libs')) if self.debug: self.build_temp = os.path.join(self.build_temp, "Debug") @@ -181,8 +191,17 @@ class build_ext (Command): # this allows distutils on windows to work in the source tree self.include_dirs.append(os.path.join(sys.exec_prefix, 'PC')) if MSVC_VERSION == 9: - self.library_dirs.append(os.path.join(sys.exec_prefix, - 'PCbuild')) + # Use the .lib files for the correct architecture + if self.plat_name == 'win32': + suffix = '' + else: + # win-amd64 or win-ia64 + suffix = self.plat_name[4:] + new_lib = os.path.join(sys.exec_prefix, 'PCbuild') + if suffix: + new_lib = os.path.join(new_lib, suffix) + self.library_dirs.append(new_lib) + elif MSVC_VERSION == 8: self.library_dirs.append(os.path.join(sys.exec_prefix, 'PC', 'VS8.0', 'win32release')) @@ -275,6 +294,11 @@ class build_ext (Command): 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.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 diff --git a/Lib/distutils/command/install.py b/Lib/distutils/command/install.py index 0d39b91..33a1212 100644 --- a/Lib/distutils/command/install.py +++ b/Lib/distutils/command/install.py @@ -16,6 +16,7 @@ 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, subst_vars, change_root +from distutils.util import get_platform from distutils.errors import DistutilsOptionError if sys.version < "2.2": @@ -503,6 +504,14 @@ class install (Command): # Obviously have to build before we can install if not self.skip_build: self.run_command('build') + # If we built for any other platform, we can't install. + build_plat = self.distribution.get_command_obj('build').plat_name + # check warn_dir - it is a clue that the 'install' is happening + # internally, and not to sys.path, so we don't check the platform + # matches what we are running. + if self.warn_dir and build_plat != get_platform(): + raise DistutilsPlatformError("Can't install when " + "cross-compiling") # Run all sub-commands (at least those that need to be run) for cmd_name in self.get_sub_commands(): diff --git a/Lib/distutils/command/wininst-9.0-amd64.exe b/Lib/distutils/command/wininst-9.0-amd64.exe Binary files differnew file mode 100644 index 0000000..c99ede4 --- /dev/null +++ b/Lib/distutils/command/wininst-9.0-amd64.exe diff --git a/Lib/distutils/msvc9compiler.py b/Lib/distutils/msvc9compiler.py index 828d7fb..8b1cf9a 100644 --- a/Lib/distutils/msvc9compiler.py +++ b/Lib/distutils/msvc9compiler.py @@ -22,6 +22,7 @@ from distutils.errors import (DistutilsExecError, DistutilsPlatformError, from distutils.ccompiler import (CCompiler, gen_preprocess_options, gen_lib_options) from distutils import log +from distutils.util import get_platform import _winreg @@ -38,13 +39,15 @@ HKEYS = (_winreg.HKEY_USERS, VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f" WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows" NET_BASE = r"Software\Microsoft\.NETFramework" -ARCHS = {'DEFAULT' : 'x86', - 'intel' : 'x86', 'x86' : 'x86', - 'amd64' : 'x64', 'x64' : 'x64', - 'itanium' : 'ia64', 'ia64' : 'ia64', - } -# The globals VERSION, ARCH, MACROS and VC_ENV are defined later +# A map keyed by get_platform() return values to values accepted by +# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is +# the param to cross-compile on x86 targetting amd64.) +PLAT_TO_VCVARS = { + 'win32' : 'x86', + 'win-amd64' : 'amd64', + 'win-ia64' : 'ia64', +} class Reg: """Helper class to read values from the registry @@ -176,23 +179,6 @@ def get_build_version(): # else we don't know what version of the compiler this is return None -def get_build_architecture(): - """Return the processor architecture. - - Possible results are "x86" or "amd64". - """ - prefix = " bit (" - i = sys.version.find(prefix) - if i == -1: - return "x86" - j = sys.version.find(")", i) - sysarch = sys.version[i+len(prefix):j].lower() - arch = ARCHS.get(sysarch, None) - if arch is None: - return ARCHS['DEFAULT'] - else: - return arch - def normalize_and_reduce_paths(paths): """Return a list of normalized paths with duplicates removed. @@ -251,6 +237,7 @@ def query_vcvarsall(version, arch="x86"): if vcvarsall is None: raise IOError("Unable to find vcvarsall.bat") + log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version) popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch), stdout=subprocess.PIPE, stderr=subprocess.PIPE) @@ -281,9 +268,7 @@ def query_vcvarsall(version, arch="x86"): VERSION = get_build_version() if VERSION < 8.0: raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION) -ARCH = get_build_architecture() # MACROS = MacroExpander(VERSION) -VC_ENV = query_vcvarsall(VERSION, ARCH) class MSVCCompiler(CCompiler) : """Concrete class that implements an interface to Microsoft Visual C++, @@ -318,13 +303,25 @@ class MSVCCompiler(CCompiler) : def __init__(self, verbose=0, dry_run=0, force=0): CCompiler.__init__ (self, verbose, dry_run, force) self.__version = VERSION - self.__arch = ARCH self.__root = r"Software\Microsoft\VisualStudio" # self.__macros = MACROS self.__path = [] + # target platform (.plat_name is consistent with 'bdist') + self.plat_name = None + self.__arch = None # deprecated name self.initialized = False - def initialize(self): + def initialize(self, plat_name=None): + # multi-init means we would need to check platform same each time... + assert not self.initialized, "don't init multiple times" + if plat_name is None: + plat_name = get_platform() + # sanity check for platforms to prevent obscure errors later. + ok_plats = 'win32', 'win-amd64', 'win-ia64' + if plat_name not in ok_plats: + raise DistutilsPlatformError("--plat-name must be one of %s" % + (ok_plats,)) + if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"): # Assume that the SDK set up everything alright; don't try to be # smarter @@ -334,9 +331,24 @@ class MSVCCompiler(CCompiler) : self.rc = "rc.exe" self.mc = "mc.exe" else: - self.__paths = VC_ENV['path'].split(os.pathsep) - os.environ['lib'] = VC_ENV['lib'] - os.environ['include'] = VC_ENV['include'] + # On x86, 'vcvars32.bat amd64' creates an env that doesn't work; + # to cross compile, you use 'x86_amd64'. + # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross + # compile use 'x86' (ie, it runs the x86 compiler directly) + # No idea how itanium handles this, if at all. + if plat_name == get_platform() or plat_name == 'win32': + # native build or cross-compile to win32 + plat_spec = PLAT_TO_VCVARS[plat_name] + else: + # cross compile from win32 -> some 64bit + plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \ + PLAT_TO_VCVARS[plat_name] + + vc_env = query_vcvarsall(VERSION, plat_spec) + + self.__paths = vc_env['path'].split(os.pathsep) + os.environ['lib'] = vc_env['lib'] + os.environ['include'] = vc_env['include'] if len(self.__paths) == 0: raise DistutilsPlatformError("Python was built with %s, " diff --git a/Lib/distutils/msvccompiler.py b/Lib/distutils/msvccompiler.py index f3acb53..30a9fc6 100644 --- a/Lib/distutils/msvccompiler.py +++ b/Lib/distutils/msvccompiler.py @@ -656,5 +656,5 @@ if get_build_version() >= 8.0: log.debug("Importing new compiler from distutils.msvc9compiler") OldMSVCCompiler = MSVCCompiler from distutils.msvc9compiler import MSVCCompiler - from distutils.msvc9compiler import get_build_architecture + # get_build_architecture not really relevant now we support cross-compile from distutils.msvc9compiler import MacroExpander diff --git a/Lib/distutils/util.py b/Lib/distutils/util.py index deb9a0a..69d90cf 100644 --- a/Lib/distutils/util.py +++ b/Lib/distutils/util.py @@ -30,7 +30,7 @@ def get_platform (): irix64-6.2 Windows will return one of: - win-x86_64 (64bit Windows on x86_64 (AMD64)) + 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) @@ -45,7 +45,7 @@ def get_platform (): j = string.find(sys.version, ")", i) look = sys.version[i+len(prefix):j].lower() if look=='amd64': - return 'win-x86_64' + return 'win-amd64' if look=='itanium': return 'win-ia64' return sys.platform |