+++ /dev/null
-"""distutils.msvc9compiler\r
-\r
-Contains MSVCCompiler, an implementation of the abstract CCompiler class\r
-for the Microsoft Visual Studio 2008.\r
-\r
-The module is compatible with VS 2005 and VS 2008. You can find legacy support\r
-for older versions of VS in distutils.msvccompiler.\r
-"""\r
-\r
-# Written by Perry Stoll\r
-# hacked by Robin Becker and Thomas Heller to do a better job of\r
-# finding DevStudio (through the registry)\r
-# ported to VS2005 and VS 2008 by Christian Heimes\r
-\r
-__revision__ = "$Id$"\r
-\r
-import os\r
-import subprocess\r
-import sys\r
-import re\r
-\r
-from distutils.errors import (DistutilsExecError, DistutilsPlatformError,\r
- CompileError, LibError, LinkError)\r
-from distutils.ccompiler import CCompiler, gen_lib_options\r
-from distutils import log\r
-from distutils.util import get_platform\r
-\r
-import _winreg\r
-\r
-RegOpenKeyEx = _winreg.OpenKeyEx\r
-RegEnumKey = _winreg.EnumKey\r
-RegEnumValue = _winreg.EnumValue\r
-RegError = _winreg.error\r
-\r
-HKEYS = (_winreg.HKEY_USERS,\r
- _winreg.HKEY_CURRENT_USER,\r
- _winreg.HKEY_LOCAL_MACHINE,\r
- _winreg.HKEY_CLASSES_ROOT)\r
-\r
-NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)\r
-if NATIVE_WIN64:\r
- # Visual C++ is a 32-bit application, so we need to look in\r
- # the corresponding registry branch, if we're running a\r
- # 64-bit Python on Win64\r
- VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"\r
- VSEXPRESS_BASE = r"Software\Wow6432Node\Microsoft\VCExpress\%0.1f"\r
- WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"\r
- NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework"\r
-else:\r
- VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"\r
- VSEXPRESS_BASE = r"Software\Microsoft\VCExpress\%0.1f"\r
- WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"\r
- NET_BASE = r"Software\Microsoft\.NETFramework"\r
-\r
-# A map keyed by get_platform() return values to values accepted by\r
-# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is\r
-# the param to cross-compile on x86 targetting amd64.)\r
-PLAT_TO_VCVARS = {\r
- 'win32' : 'x86',\r
- 'win-amd64' : 'amd64',\r
- 'win-ia64' : 'ia64',\r
-}\r
-\r
-class Reg:\r
- """Helper class to read values from the registry\r
- """\r
-\r
- def get_value(cls, path, key):\r
- for base in HKEYS:\r
- d = cls.read_values(base, path)\r
- if d and key in d:\r
- return d[key]\r
- raise KeyError(key)\r
- get_value = classmethod(get_value)\r
-\r
- def read_keys(cls, base, key):\r
- """Return list of registry keys."""\r
- try:\r
- handle = RegOpenKeyEx(base, key)\r
- except RegError:\r
- return None\r
- L = []\r
- i = 0\r
- while True:\r
- try:\r
- k = RegEnumKey(handle, i)\r
- except RegError:\r
- break\r
- L.append(k)\r
- i += 1\r
- return L\r
- read_keys = classmethod(read_keys)\r
-\r
- def read_values(cls, base, key):\r
- """Return dict of registry keys and values.\r
-\r
- All names are converted to lowercase.\r
- """\r
- try:\r
- handle = RegOpenKeyEx(base, key)\r
- except RegError:\r
- return None\r
- d = {}\r
- i = 0\r
- while True:\r
- try:\r
- name, value, type = RegEnumValue(handle, i)\r
- except RegError:\r
- break\r
- name = name.lower()\r
- d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)\r
- i += 1\r
- return d\r
- read_values = classmethod(read_values)\r
-\r
- def convert_mbcs(s):\r
- dec = getattr(s, "decode", None)\r
- if dec is not None:\r
- try:\r
- s = dec("mbcs")\r
- except UnicodeError:\r
- pass\r
- return s\r
- convert_mbcs = staticmethod(convert_mbcs)\r
-\r
-class MacroExpander:\r
-\r
- def __init__(self, version):\r
- self.macros = {}\r
- self.vsbase = VS_BASE % version\r
- self.load_macros(version)\r
-\r
- def set_macro(self, macro, path, key):\r
- self.macros["$(%s)" % macro] = Reg.get_value(path, key)\r
-\r
- def load_macros(self, version):\r
- self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")\r
- self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")\r
- self.set_macro("FrameworkDir", NET_BASE, "installroot")\r
- try:\r
- if version >= 8.0:\r
- self.set_macro("FrameworkSDKDir", NET_BASE,\r
- "sdkinstallrootv2.0")\r
- else:\r
- raise KeyError("sdkinstallrootv2.0")\r
- except KeyError:\r
- raise DistutilsPlatformError(\r
- """Python was built with Visual Studio 2008;\r
-extensions must be built with a compiler than can generate compatible binaries.\r
-Visual Studio 2008 was not found on this system. If you have Cygwin installed,\r
-you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")\r
-\r
- if version >= 9.0:\r
- self.set_macro("FrameworkVersion", self.vsbase, "clr version")\r
- self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")\r
- else:\r
- p = r"Software\Microsoft\NET Framework Setup\Product"\r
- for base in HKEYS:\r
- try:\r
- h = RegOpenKeyEx(base, p)\r
- except RegError:\r
- continue\r
- key = RegEnumKey(h, 0)\r
- d = Reg.get_value(base, r"%s\%s" % (p, key))\r
- self.macros["$(FrameworkVersion)"] = d["version"]\r
-\r
- def sub(self, s):\r
- for k, v in self.macros.items():\r
- s = s.replace(k, v)\r
- return s\r
-\r
-def get_build_version():\r
- """Return the version of MSVC that was used to build Python.\r
-\r
- For Python 2.3 and up, the version number is included in\r
- sys.version. For earlier versions, assume the compiler is MSVC 6.\r
- """\r
- prefix = "MSC v."\r
- i = sys.version.find(prefix)\r
- if i == -1:\r
- return 6\r
- i = i + len(prefix)\r
- s, rest = sys.version[i:].split(" ", 1)\r
- majorVersion = int(s[:-2]) - 6\r
- minorVersion = int(s[2:3]) / 10.0\r
- # I don't think paths are affected by minor version in version 6\r
- if majorVersion == 6:\r
- minorVersion = 0\r
- if majorVersion >= 6:\r
- return majorVersion + minorVersion\r
- # else we don't know what version of the compiler this is\r
- return None\r
-\r
-def normalize_and_reduce_paths(paths):\r
- """Return a list of normalized paths with duplicates removed.\r
-\r
- The current order of paths is maintained.\r
- """\r
- # Paths are normalized so things like: /a and /a/ aren't both preserved.\r
- reduced_paths = []\r
- for p in paths:\r
- np = os.path.normpath(p)\r
- # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.\r
- if np not in reduced_paths:\r
- reduced_paths.append(np)\r
- return reduced_paths\r
-\r
-def removeDuplicates(variable):\r
- """Remove duplicate values of an environment variable.\r
- """\r
- oldList = variable.split(os.pathsep)\r
- newList = []\r
- for i in oldList:\r
- if i not in newList:\r
- newList.append(i)\r
- newVariable = os.pathsep.join(newList)\r
- return newVariable\r
-\r
-def find_vcvarsall(version):\r
- """Find the vcvarsall.bat file\r
-\r
- At first it tries to find the productdir of VS 2008 in the registry. If\r
- that fails it falls back to the VS90COMNTOOLS env var.\r
- """\r
- vsbase = VS_BASE % version\r
- try:\r
- productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,\r
- "productdir")\r
- except KeyError:\r
- productdir = None\r
-\r
- # trying Express edition\r
- if productdir is None:\r
- vsbase = VSEXPRESS_BASE % version\r
- try:\r
- productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,\r
- "productdir")\r
- except KeyError:\r
- productdir = None\r
- log.debug("Unable to find productdir in registry")\r
-\r
- if not productdir or not os.path.isdir(productdir):\r
- toolskey = "VS%0.f0COMNTOOLS" % version\r
- toolsdir = os.environ.get(toolskey, None)\r
-\r
- if toolsdir and os.path.isdir(toolsdir):\r
- productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")\r
- productdir = os.path.abspath(productdir)\r
- if not os.path.isdir(productdir):\r
- log.debug("%s is not a valid directory" % productdir)\r
- return None\r
- else:\r
- log.debug("Env var %s is not set or invalid" % toolskey)\r
- if not productdir:\r
- log.debug("No productdir found")\r
- return None\r
- vcvarsall = os.path.join(productdir, "vcvarsall.bat")\r
- if os.path.isfile(vcvarsall):\r
- return vcvarsall\r
- log.debug("Unable to find vcvarsall.bat")\r
- return None\r
-\r
-def query_vcvarsall(version, arch="x86"):\r
- """Launch vcvarsall.bat and read the settings from its environment\r
- """\r
- vcvarsall = find_vcvarsall(version)\r
- interesting = set(("include", "lib", "libpath", "path"))\r
- result = {}\r
-\r
- if vcvarsall is None:\r
- raise DistutilsPlatformError("Unable to find vcvarsall.bat")\r
- log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)\r
- popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),\r
- stdout=subprocess.PIPE,\r
- stderr=subprocess.PIPE)\r
- try:\r
- stdout, stderr = popen.communicate()\r
- if popen.wait() != 0:\r
- raise DistutilsPlatformError(stderr.decode("mbcs"))\r
-\r
- stdout = stdout.decode("mbcs")\r
- for line in stdout.split("\n"):\r
- line = Reg.convert_mbcs(line)\r
- if '=' not in line:\r
- continue\r
- line = line.strip()\r
- key, value = line.split('=', 1)\r
- key = key.lower()\r
- if key in interesting:\r
- if value.endswith(os.pathsep):\r
- value = value[:-1]\r
- result[key] = removeDuplicates(value)\r
-\r
- finally:\r
- popen.stdout.close()\r
- popen.stderr.close()\r
-\r
- if len(result) != len(interesting):\r
- raise ValueError(str(list(result.keys())))\r
-\r
- return result\r
-\r
-# More globals\r
-VERSION = get_build_version()\r
-if VERSION < 8.0:\r
- raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)\r
-# MACROS = MacroExpander(VERSION)\r
-\r
-class MSVCCompiler(CCompiler) :\r
- """Concrete class that implements an interface to Microsoft Visual C++,\r
- as defined by the CCompiler abstract class."""\r
-\r
- compiler_type = 'msvc'\r
-\r
- # Just set this so CCompiler's constructor doesn't barf. We currently\r
- # don't use the 'set_executables()' bureaucracy provided by CCompiler,\r
- # as it really isn't necessary for this sort of single-compiler class.\r
- # Would be nice to have a consistent interface with UnixCCompiler,\r
- # though, so it's worth thinking about.\r
- executables = {}\r
-\r
- # Private class data (need to distinguish C from C++ source for compiler)\r
- _c_extensions = ['.c']\r
- _cpp_extensions = ['.cc', '.cpp', '.cxx']\r
- _rc_extensions = ['.rc']\r
- _mc_extensions = ['.mc']\r
-\r
- # Needed for the filename generation methods provided by the\r
- # base class, CCompiler.\r
- src_extensions = (_c_extensions + _cpp_extensions +\r
- _rc_extensions + _mc_extensions)\r
- res_extension = '.res'\r
- obj_extension = '.obj'\r
- static_lib_extension = '.lib'\r
- shared_lib_extension = '.dll'\r
- static_lib_format = shared_lib_format = '%s%s'\r
- exe_extension = '.exe'\r
-\r
- def __init__(self, verbose=0, dry_run=0, force=0):\r
- CCompiler.__init__ (self, verbose, dry_run, force)\r
- self.__version = VERSION\r
- self.__root = r"Software\Microsoft\VisualStudio"\r
- # self.__macros = MACROS\r
- self.__paths = []\r
- # target platform (.plat_name is consistent with 'bdist')\r
- self.plat_name = None\r
- self.__arch = None # deprecated name\r
- self.initialized = False\r
-\r
- def initialize(self, plat_name=None):\r
- # multi-init means we would need to check platform same each time...\r
- assert not self.initialized, "don't init multiple times"\r
- if plat_name is None:\r
- plat_name = get_platform()\r
- # sanity check for platforms to prevent obscure errors later.\r
- ok_plats = 'win32', 'win-amd64', 'win-ia64'\r
- if plat_name not in ok_plats:\r
- raise DistutilsPlatformError("--plat-name must be one of %s" %\r
- (ok_plats,))\r
-\r
- if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):\r
- # Assume that the SDK set up everything alright; don't try to be\r
- # smarter\r
- self.cc = "cl.exe"\r
- self.linker = "link.exe"\r
- self.lib = "lib.exe"\r
- self.rc = "rc.exe"\r
- self.mc = "mc.exe"\r
- else:\r
- # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;\r
- # to cross compile, you use 'x86_amd64'.\r
- # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross\r
- # compile use 'x86' (ie, it runs the x86 compiler directly)\r
- # No idea how itanium handles this, if at all.\r
- if plat_name == get_platform() or plat_name == 'win32':\r
- # native build or cross-compile to win32\r
- plat_spec = PLAT_TO_VCVARS[plat_name]\r
- else:\r
- # cross compile from win32 -> some 64bit\r
- plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \\r
- PLAT_TO_VCVARS[plat_name]\r
-\r
- vc_env = query_vcvarsall(VERSION, plat_spec)\r
-\r
- # take care to only use strings in the environment.\r
- self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)\r
- os.environ['lib'] = vc_env['lib'].encode('mbcs')\r
- os.environ['include'] = vc_env['include'].encode('mbcs')\r
-\r
- if len(self.__paths) == 0:\r
- raise DistutilsPlatformError("Python was built with %s, "\r
- "and extensions need to be built with the same "\r
- "version of the compiler, but it isn't installed."\r
- % self.__product)\r
-\r
- self.cc = self.find_exe("cl.exe")\r
- self.linker = self.find_exe("link.exe")\r
- self.lib = self.find_exe("lib.exe")\r
- self.rc = self.find_exe("rc.exe") # resource compiler\r
- self.mc = self.find_exe("mc.exe") # message compiler\r
- #self.set_path_env_var('lib')\r
- #self.set_path_env_var('include')\r
-\r
- # extend the MSVC path with the current path\r
- try:\r
- for p in os.environ['path'].split(';'):\r
- self.__paths.append(p)\r
- except KeyError:\r
- pass\r
- self.__paths = normalize_and_reduce_paths(self.__paths)\r
- os.environ['path'] = ";".join(self.__paths)\r
-\r
- self.preprocess_options = None\r
- if self.__arch == "x86":\r
- self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',\r
- '/DNDEBUG']\r
- self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',\r
- '/Z7', '/D_DEBUG']\r
- else:\r
- # Win64\r
- self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,\r
- '/DNDEBUG']\r
- self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',\r
- '/Z7', '/D_DEBUG']\r
-\r
- self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']\r
- if self.__version >= 7:\r
- self.ldflags_shared_debug = [\r
- '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'\r
- ]\r
- self.ldflags_static = [ '/nologo']\r
-\r
- self.initialized = True\r
-\r
- # -- Worker methods ------------------------------------------------\r
-\r
- def object_filenames(self,\r
- source_filenames,\r
- strip_dir=0,\r
- output_dir=''):\r
- # Copied from ccompiler.py, extended to return .res as 'object'-file\r
- # for .rc input file\r
- if output_dir is None: output_dir = ''\r
- obj_names = []\r
- for src_name in source_filenames:\r
- (base, ext) = os.path.splitext (src_name)\r
- base = os.path.splitdrive(base)[1] # Chop off the drive\r
- base = base[os.path.isabs(base):] # If abs, chop off leading /\r
- if ext not in self.src_extensions:\r
- # Better to raise an exception instead of silently continuing\r
- # and later complain about sources and targets having\r
- # different lengths\r
- raise CompileError ("Don't know how to compile %s" % src_name)\r
- if strip_dir:\r
- base = os.path.basename (base)\r
- if ext in self._rc_extensions:\r
- obj_names.append (os.path.join (output_dir,\r
- base + self.res_extension))\r
- elif ext in self._mc_extensions:\r
- obj_names.append (os.path.join (output_dir,\r
- base + self.res_extension))\r
- else:\r
- obj_names.append (os.path.join (output_dir,\r
- base + self.obj_extension))\r
- return obj_names\r
-\r
-\r
- def compile(self, sources,\r
- output_dir=None, macros=None, include_dirs=None, debug=0,\r
- extra_preargs=None, extra_postargs=None, depends=None):\r
-\r
- if not self.initialized:\r
- self.initialize()\r
- compile_info = self._setup_compile(output_dir, macros, include_dirs,\r
- sources, depends, extra_postargs)\r
- macros, objects, extra_postargs, pp_opts, build = compile_info\r
-\r
- compile_opts = extra_preargs or []\r
- compile_opts.append ('/c')\r
- if debug:\r
- compile_opts.extend(self.compile_options_debug)\r
- else:\r
- compile_opts.extend(self.compile_options)\r
-\r
- for obj in objects:\r
- try:\r
- src, ext = build[obj]\r
- except KeyError:\r
- continue\r
- if debug:\r
- # pass the full pathname to MSVC in debug mode,\r
- # this allows the debugger to find the source file\r
- # without asking the user to browse for it\r
- src = os.path.abspath(src)\r
-\r
- if ext in self._c_extensions:\r
- input_opt = "/Tc" + src\r
- elif ext in self._cpp_extensions:\r
- input_opt = "/Tp" + src\r
- elif ext in self._rc_extensions:\r
- # compile .RC to .RES file\r
- input_opt = src\r
- output_opt = "/fo" + obj\r
- try:\r
- self.spawn([self.rc] + pp_opts +\r
- [output_opt] + [input_opt])\r
- except DistutilsExecError, msg:\r
- raise CompileError(msg)\r
- continue\r
- elif ext in self._mc_extensions:\r
- # Compile .MC to .RC file to .RES file.\r
- # * '-h dir' specifies the directory for the\r
- # generated include file\r
- # * '-r dir' specifies the target directory of the\r
- # generated RC file and the binary message resource\r
- # it includes\r
- #\r
- # For now (since there are no options to change this),\r
- # we use the source-directory for the include file and\r
- # the build directory for the RC file and message\r
- # resources. This works at least for win32all.\r
- h_dir = os.path.dirname(src)\r
- rc_dir = os.path.dirname(obj)\r
- try:\r
- # first compile .MC to .RC and .H file\r
- self.spawn([self.mc] +\r
- ['-h', h_dir, '-r', rc_dir] + [src])\r
- base, _ = os.path.splitext (os.path.basename (src))\r
- rc_file = os.path.join (rc_dir, base + '.rc')\r
- # then compile .RC to .RES file\r
- self.spawn([self.rc] +\r
- ["/fo" + obj] + [rc_file])\r
-\r
- except DistutilsExecError, msg:\r
- raise CompileError(msg)\r
- continue\r
- else:\r
- # how to handle this file?\r
- raise CompileError("Don't know how to compile %s to %s"\r
- % (src, obj))\r
-\r
- output_opt = "/Fo" + obj\r
- try:\r
- self.spawn([self.cc] + compile_opts + pp_opts +\r
- [input_opt, output_opt] +\r
- extra_postargs)\r
- except DistutilsExecError, msg:\r
- raise CompileError(msg)\r
-\r
- return objects\r
-\r
-\r
- def create_static_lib(self,\r
- objects,\r
- output_libname,\r
- output_dir=None,\r
- debug=0,\r
- target_lang=None):\r
-\r
- if not self.initialized:\r
- self.initialize()\r
- (objects, output_dir) = self._fix_object_args(objects, output_dir)\r
- output_filename = self.library_filename(output_libname,\r
- output_dir=output_dir)\r
-\r
- if self._need_link(objects, output_filename):\r
- lib_args = objects + ['/OUT:' + output_filename]\r
- if debug:\r
- pass # XXX what goes here?\r
- try:\r
- self.spawn([self.lib] + lib_args)\r
- except DistutilsExecError, msg:\r
- raise LibError(msg)\r
- else:\r
- log.debug("skipping %s (up-to-date)", output_filename)\r
-\r
-\r
- def link(self,\r
- target_desc,\r
- objects,\r
- output_filename,\r
- output_dir=None,\r
- libraries=None,\r
- library_dirs=None,\r
- runtime_library_dirs=None,\r
- export_symbols=None,\r
- debug=0,\r
- extra_preargs=None,\r
- extra_postargs=None,\r
- build_temp=None,\r
- target_lang=None):\r
-\r
- if not self.initialized:\r
- self.initialize()\r
- (objects, output_dir) = self._fix_object_args(objects, output_dir)\r
- fixed_args = self._fix_lib_args(libraries, library_dirs,\r
- runtime_library_dirs)\r
- (libraries, library_dirs, runtime_library_dirs) = fixed_args\r
-\r
- if runtime_library_dirs:\r
- self.warn ("I don't know what to do with 'runtime_library_dirs': "\r
- + str (runtime_library_dirs))\r
-\r
- lib_opts = gen_lib_options(self,\r
- library_dirs, runtime_library_dirs,\r
- libraries)\r
- if output_dir is not None:\r
- output_filename = os.path.join(output_dir, output_filename)\r
-\r
- if self._need_link(objects, output_filename):\r
- if target_desc == CCompiler.EXECUTABLE:\r
- if debug:\r
- ldflags = self.ldflags_shared_debug[1:]\r
- else:\r
- ldflags = self.ldflags_shared[1:]\r
- else:\r
- if debug:\r
- ldflags = self.ldflags_shared_debug\r
- else:\r
- ldflags = self.ldflags_shared\r
-\r
- export_opts = []\r
- for sym in (export_symbols or []):\r
- export_opts.append("/EXPORT:" + sym)\r
-\r
- ld_args = (ldflags + lib_opts + export_opts +\r
- objects + ['/OUT:' + output_filename])\r
-\r
- # The MSVC linker generates .lib and .exp files, which cannot be\r
- # suppressed by any linker switches. The .lib files may even be\r
- # needed! Make sure they are generated in the temporary build\r
- # directory. Since they have different names for debug and release\r
- # builds, they can go into the same directory.\r
- build_temp = os.path.dirname(objects[0])\r
- if export_symbols is not None:\r
- (dll_name, dll_ext) = os.path.splitext(\r
- os.path.basename(output_filename))\r
- implib_file = os.path.join(\r
- build_temp,\r
- self.library_filename(dll_name))\r
- ld_args.append ('/IMPLIB:' + implib_file)\r
-\r
- # Embedded manifests are recommended - see MSDN article titled\r
- # "How to: Embed a Manifest Inside a C/C++ Application"\r
- # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)\r
- # Ask the linker to generate the manifest in the temp dir, so\r
- # we can embed it later.\r
- temp_manifest = os.path.join(\r
- build_temp,\r
- os.path.basename(output_filename) + ".manifest")\r
- ld_args.append('/MANIFESTFILE:' + temp_manifest)\r
-\r
- if extra_preargs:\r
- ld_args[:0] = extra_preargs\r
- if extra_postargs:\r
- ld_args.extend(extra_postargs)\r
-\r
- self.mkpath(os.path.dirname(output_filename))\r
- try:\r
- self.spawn([self.linker] + ld_args)\r
- except DistutilsExecError, msg:\r
- raise LinkError(msg)\r
-\r
- # embed the manifest\r
- # XXX - this is somewhat fragile - if mt.exe fails, distutils\r
- # will still consider the DLL up-to-date, but it will not have a\r
- # manifest. Maybe we should link to a temp file? OTOH, that\r
- # implies a build environment error that shouldn't go undetected.\r
- if target_desc == CCompiler.EXECUTABLE:\r
- mfid = 1\r
- else:\r
- mfid = 2\r
- self._remove_visual_c_ref(temp_manifest)\r
- out_arg = '-outputresource:%s;%s' % (output_filename, mfid)\r
- try:\r
- self.spawn(['mt.exe', '-nologo', '-manifest',\r
- temp_manifest, out_arg])\r
- except DistutilsExecError, msg:\r
- raise LinkError(msg)\r
- else:\r
- log.debug("skipping %s (up-to-date)", output_filename)\r
-\r
- def _remove_visual_c_ref(self, manifest_file):\r
- try:\r
- # Remove references to the Visual C runtime, so they will\r
- # fall through to the Visual C dependency of Python.exe.\r
- # This way, when installed for a restricted user (e.g.\r
- # runtimes are not in WinSxS folder, but in Python's own\r
- # folder), the runtimes do not need to be in every folder\r
- # with .pyd's.\r
- manifest_f = open(manifest_file)\r
- try:\r
- manifest_buf = manifest_f.read()\r
- finally:\r
- manifest_f.close()\r
- pattern = re.compile(\r
- r"""<assemblyIdentity.*?name=("|')Microsoft\."""\\r
- r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",\r
- re.DOTALL)\r
- manifest_buf = re.sub(pattern, "", manifest_buf)\r
- pattern = "<dependentAssembly>\s*</dependentAssembly>"\r
- manifest_buf = re.sub(pattern, "", manifest_buf)\r
- manifest_f = open(manifest_file, 'w')\r
- try:\r
- manifest_f.write(manifest_buf)\r
- finally:\r
- manifest_f.close()\r
- except IOError:\r
- pass\r
-\r
- # -- Miscellaneous methods -----------------------------------------\r
- # These are all used by the 'gen_lib_options() function, in\r
- # ccompiler.py.\r
-\r
- def library_dir_option(self, dir):\r
- return "/LIBPATH:" + dir\r
-\r
- def runtime_library_dir_option(self, dir):\r
- raise DistutilsPlatformError(\r
- "don't know how to set runtime library search path for MSVC++")\r
-\r
- def library_option(self, lib):\r
- return self.library_filename(lib)\r
-\r
-\r
- def find_library_file(self, dirs, lib, debug=0):\r
- # Prefer a debugging library if found (and requested), but deal\r
- # with it if we don't have one.\r
- if debug:\r
- try_names = [lib + "_d", lib]\r
- else:\r
- try_names = [lib]\r
- for dir in dirs:\r
- for name in try_names:\r
- libfile = os.path.join(dir, self.library_filename (name))\r
- if os.path.exists(libfile):\r
- return libfile\r
- else:\r
- # Oops, didn't find it in *any* of 'dirs'\r
- return None\r
-\r
- # Helper methods for using the MSVC registry settings\r
-\r
- def find_exe(self, exe):\r
- """Return path to an MSVC executable program.\r
-\r
- Tries to find the program in several places: first, one of the\r
- MSVC program search paths from the registry; next, the directories\r
- in the PATH environment variable. If any of those work, return an\r
- absolute path that is known to exist. If none of them work, just\r
- return the original program name, 'exe'.\r
- """\r
- for p in self.__paths:\r
- fn = os.path.join(os.path.abspath(p), exe)\r
- if os.path.isfile(fn):\r
- return fn\r
-\r
- # didn't find it; try existing path\r
- for p in os.environ['Path'].split(';'):\r
- fn = os.path.join(os.path.abspath(p),exe)\r
- if os.path.isfile(fn):\r
- return fn\r
-\r
- return exe\r