Commit 9351875b authored by Mark Hammond's avatar Mark Hammond

Issue #2513: enable 64bit cross compilation on windows.

parent bbe02c7a
......@@ -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.
......
......@@ -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
......@@ -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
......@@ -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
......
......@@ -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
......
......@@ -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():
......
......@@ -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, "
......
......@@ -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
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment