Index: PCbuild/bdist_wininst.vcproj
===================================================================
--- PCbuild/bdist_wininst.vcproj (revision 61926)
+++ PCbuild/bdist_wininst.vcproj (working copy)
@@ -1,7 +1,7 @@
+
@@ -104,6 +107,96 @@
Name="VCPostBuildEventTool"
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: PC/example_nt/setup.py
===================================================================
--- PC/example_nt/setup.py (revision 0)
+++ PC/example_nt/setup.py (revision 0)
@@ -0,0 +1,22 @@
+# This is an example of a distutils 'setup' script for the example_nt
+# sample. This provides a simpler way of building your extension
+# and means you can avoid keeping MSVC solution files etc in source-control.
+# It also means it should magically build with all compilers supported by
+# python.
+
+# USAGE: you probably want 'setup.py install' - but execute 'setup.py --help'
+# for all the details.
+
+# NOTE: This is *not* a sample for distutils - it is just the smallest
+# script that can build this. See distutils docs for more info.
+
+from distutils.core import setup, Extension
+
+example_mod = Extension('example', sources = ['example.c'])
+
+
+setup(name = "example",
+ version = "1.0",
+ description = "A sample extension module",
+ ext_modules = [example_mod],
+)
Property changes on: PC\example_nt\setup.py
___________________________________________________________________
Name: svn:eol-style
+ native
Index: PC/example_nt/readme.txt
===================================================================
--- PC/example_nt/readme.txt (revision 61926)
+++ PC/example_nt/readme.txt (working copy)
@@ -2,13 +2,35 @@
=======================================
This directory contains everything needed (except for the Python
-distribution!) to build a Python extension module using Microsoft VC++
-("Developer Studio") version 7.1. It has been tested with VC++ 7.1 on
-Python 2.4. You can also use earlier versions of VC to build Python
-extensions, but the sample VC project file (example.dsw in this directory)
-is in VC 7.1 format. Notice that you need to use the same compiler version
-that was used to build Python itself.
+distribution!) to build a Python extension module using Microsoft VC++.
+Notice that you need to use the same compiler version that was used to build
+Python itself.
+The simplest way to build this example is to use the distutils script
+'setup.py'. To do this, simply execute:
+
+ % python setup.py install
+
+after everything builds and installs, you can test it:
+
+ % python -c "import example; example.foo()"
+ Hello, world
+
+See setup.py for more details. alternatively, see below for instructions on
+how to build inside the Visual Studio environment.
+
+Visual Studio Build Instructions
+================================
+
+These are instructions how to build an extension using Visual C++. The
+instructions and project files have not been updated to the latest VC
+version. In general, it is recommended you use the 'setup.py' instructions
+above.
+
+It has been tested with VC++ 7.1 on Python 2.4. You can also use earlier
+versions of VC to build Python extensions, but the sample VC project file
+(example.dsw in this directory) is in VC 7.1 format.
+
COPY THIS DIRECTORY!
--------------------
This "example_nt" directory is a subdirectory of the PC directory, in order
Index: Doc/distutils/builtdist.rst
===================================================================
--- Doc/distutils/builtdist.rst (revision 61926)
+++ Doc/distutils/builtdist.rst (working copy)
@@ -329,7 +329,33 @@
The installer file will be written to the "distribution directory" --- normally
:file:`dist/`, but customizable with the :option:`--dist-dir` option.
+.. _cross-compile-windows:
+Cross-compiling on Windows
+=====================
+
+Starting with Python 2.6, distutils is capable of cross-compiling between
+Windows platforms. In practice, this means that with the correct tools
+installed, you can use a 32bit version of Windows to create 64bit extensions
+and vice-versa.
+
+To build for an alternate platform, specify the :option:`--plat-name` option
+to the build command. Valid values are currently 'win32', 'win-amd64' and
+'win-ia64'. For example, on a 32bit version of Windows, you could execute::
+
+ python setup.py build --plat-name=win-amd64
+
+to build a 64bit version of your extension. The Windows Installers also
+support this option, so the command::
+
+ python setup.py build --plat-name=win-amd64 bdist_wininst
+
+would create a 64bit installation executable on your 32bit version of Windows.
+
+Note that by default, Visual Studio 2008 does not install 64bit compilers or
+tools. You may need to reexecute the Visual Studio setup process and select
+these tools.
+
.. _postinstallation-script:
The Postinstallation script
Index: Lib/distutils/msvc9compiler.py
===================================================================
--- Lib/distutils/msvc9compiler.py (revision 61926)
+++ Lib/distutils/msvc9compiler.py (working copy)
@@ -22,6 +22,7 @@
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 @@
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 @@
# 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 @@
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 @@
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 @@
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,10 +331,25 @@
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, "
"and extensions need to be built with the same "
Index: Lib/distutils/msvccompiler.py
===================================================================
--- Lib/distutils/msvccompiler.py (revision 61926)
+++ Lib/distutils/msvccompiler.py (working copy)
@@ -656,5 +656,5 @@
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
Index: Lib/distutils/util.py
===================================================================
--- Lib/distutils/util.py (revision 61926)
+++ Lib/distutils/util.py (working copy)
@@ -30,7 +30,7 @@
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 @@
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
Index: Lib/distutils/command/build.py
===================================================================
--- Lib/distutils/command/build.py (revision 61926)
+++ Lib/distutils/command/build.py (working copy)
@@ -8,6 +8,7 @@
import sys, os
from distutils.core import Command
+from distutils.errors import DistutilsOptionError
from distutils.util import get_platform
@@ -34,6 +35,9 @@
"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,14 +65,26 @@
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
# process for C modules
Index: Lib/distutils/command/bdist.py
===================================================================
--- Lib/distutils/command/bdist.py (revision 61926)
+++ Lib/distutils/command/bdist.py (working copy)
@@ -97,7 +97,10 @@
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 @@
# finalize_options()
-
def run (self):
# Figure out which sub-commands we need to run.
Index: Lib/distutils/command/install.py
===================================================================
--- Lib/distutils/command/install.py (revision 61926)
+++ Lib/distutils/command/install.py (working copy)
@@ -16,6 +16,7 @@
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 @@
# 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():
Index: Lib/distutils/command/bdist_msi.py
===================================================================
--- Lib/distutils/command/bdist_msi.py (revision 61926)
+++ Lib/distutils/command/bdist_msi.py (working copy)
@@ -9,11 +9,11 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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
Index: Lib/distutils/command/build_ext.py
===================================================================
--- Lib/distutils/command/build_ext.py (revision 61926)
+++ Lib/distutils/command/build_ext.py (working copy)
@@ -15,6 +15,7 @@
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 @@
"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 @@
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 @@
('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 @@
# 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 @@
# 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 @@
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
Index: Lib/distutils/command/bdist_wininst.py
===================================================================
--- Lib/distutils/command/bdist_wininst.py (revision 61926)
+++ Lib/distutils/command/bdist_wininst.py (working copy)
@@ -21,6 +21,9 @@
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 @@
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 @@
" 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 @@
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 @@
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 @@
# 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 @@
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 @@
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