]> git.proxmox.com Git - mirror_edk2.git/blame - AppPkg/Applications/Python/Python-2.7.2/Lib/distutils/msvc9compiler.py
AppPkg/Applications/Python: Add Python 2.7.2 sources since the release of Python...
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / distutils / msvc9compiler.py
CommitLineData
4710c53d 1"""distutils.msvc9compiler\r
2\r
3Contains MSVCCompiler, an implementation of the abstract CCompiler class\r
4for the Microsoft Visual Studio 2008.\r
5\r
6The module is compatible with VS 2005 and VS 2008. You can find legacy support\r
7for older versions of VS in distutils.msvccompiler.\r
8"""\r
9\r
10# Written by Perry Stoll\r
11# hacked by Robin Becker and Thomas Heller to do a better job of\r
12# finding DevStudio (through the registry)\r
13# ported to VS2005 and VS 2008 by Christian Heimes\r
14\r
15__revision__ = "$Id$"\r
16\r
17import os\r
18import subprocess\r
19import sys\r
20import re\r
21\r
22from distutils.errors import (DistutilsExecError, DistutilsPlatformError,\r
23 CompileError, LibError, LinkError)\r
24from distutils.ccompiler import CCompiler, gen_lib_options\r
25from distutils import log\r
26from distutils.util import get_platform\r
27\r
28import _winreg\r
29\r
30RegOpenKeyEx = _winreg.OpenKeyEx\r
31RegEnumKey = _winreg.EnumKey\r
32RegEnumValue = _winreg.EnumValue\r
33RegError = _winreg.error\r
34\r
35HKEYS = (_winreg.HKEY_USERS,\r
36 _winreg.HKEY_CURRENT_USER,\r
37 _winreg.HKEY_LOCAL_MACHINE,\r
38 _winreg.HKEY_CLASSES_ROOT)\r
39\r
40NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)\r
41if NATIVE_WIN64:\r
42 # Visual C++ is a 32-bit application, so we need to look in\r
43 # the corresponding registry branch, if we're running a\r
44 # 64-bit Python on Win64\r
45 VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"\r
46 VSEXPRESS_BASE = r"Software\Wow6432Node\Microsoft\VCExpress\%0.1f"\r
47 WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"\r
48 NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework"\r
49else:\r
50 VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"\r
51 VSEXPRESS_BASE = r"Software\Microsoft\VCExpress\%0.1f"\r
52 WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"\r
53 NET_BASE = r"Software\Microsoft\.NETFramework"\r
54\r
55# A map keyed by get_platform() return values to values accepted by\r
56# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is\r
57# the param to cross-compile on x86 targetting amd64.)\r
58PLAT_TO_VCVARS = {\r
59 'win32' : 'x86',\r
60 'win-amd64' : 'amd64',\r
61 'win-ia64' : 'ia64',\r
62}\r
63\r
64class Reg:\r
65 """Helper class to read values from the registry\r
66 """\r
67\r
68 def get_value(cls, path, key):\r
69 for base in HKEYS:\r
70 d = cls.read_values(base, path)\r
71 if d and key in d:\r
72 return d[key]\r
73 raise KeyError(key)\r
74 get_value = classmethod(get_value)\r
75\r
76 def read_keys(cls, base, key):\r
77 """Return list of registry keys."""\r
78 try:\r
79 handle = RegOpenKeyEx(base, key)\r
80 except RegError:\r
81 return None\r
82 L = []\r
83 i = 0\r
84 while True:\r
85 try:\r
86 k = RegEnumKey(handle, i)\r
87 except RegError:\r
88 break\r
89 L.append(k)\r
90 i += 1\r
91 return L\r
92 read_keys = classmethod(read_keys)\r
93\r
94 def read_values(cls, base, key):\r
95 """Return dict of registry keys and values.\r
96\r
97 All names are converted to lowercase.\r
98 """\r
99 try:\r
100 handle = RegOpenKeyEx(base, key)\r
101 except RegError:\r
102 return None\r
103 d = {}\r
104 i = 0\r
105 while True:\r
106 try:\r
107 name, value, type = RegEnumValue(handle, i)\r
108 except RegError:\r
109 break\r
110 name = name.lower()\r
111 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)\r
112 i += 1\r
113 return d\r
114 read_values = classmethod(read_values)\r
115\r
116 def convert_mbcs(s):\r
117 dec = getattr(s, "decode", None)\r
118 if dec is not None:\r
119 try:\r
120 s = dec("mbcs")\r
121 except UnicodeError:\r
122 pass\r
123 return s\r
124 convert_mbcs = staticmethod(convert_mbcs)\r
125\r
126class MacroExpander:\r
127\r
128 def __init__(self, version):\r
129 self.macros = {}\r
130 self.vsbase = VS_BASE % version\r
131 self.load_macros(version)\r
132\r
133 def set_macro(self, macro, path, key):\r
134 self.macros["$(%s)" % macro] = Reg.get_value(path, key)\r
135\r
136 def load_macros(self, version):\r
137 self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")\r
138 self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")\r
139 self.set_macro("FrameworkDir", NET_BASE, "installroot")\r
140 try:\r
141 if version >= 8.0:\r
142 self.set_macro("FrameworkSDKDir", NET_BASE,\r
143 "sdkinstallrootv2.0")\r
144 else:\r
145 raise KeyError("sdkinstallrootv2.0")\r
146 except KeyError:\r
147 raise DistutilsPlatformError(\r
148 """Python was built with Visual Studio 2008;\r
149extensions must be built with a compiler than can generate compatible binaries.\r
150Visual Studio 2008 was not found on this system. If you have Cygwin installed,\r
151you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")\r
152\r
153 if version >= 9.0:\r
154 self.set_macro("FrameworkVersion", self.vsbase, "clr version")\r
155 self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")\r
156 else:\r
157 p = r"Software\Microsoft\NET Framework Setup\Product"\r
158 for base in HKEYS:\r
159 try:\r
160 h = RegOpenKeyEx(base, p)\r
161 except RegError:\r
162 continue\r
163 key = RegEnumKey(h, 0)\r
164 d = Reg.get_value(base, r"%s\%s" % (p, key))\r
165 self.macros["$(FrameworkVersion)"] = d["version"]\r
166\r
167 def sub(self, s):\r
168 for k, v in self.macros.items():\r
169 s = s.replace(k, v)\r
170 return s\r
171\r
172def get_build_version():\r
173 """Return the version of MSVC that was used to build Python.\r
174\r
175 For Python 2.3 and up, the version number is included in\r
176 sys.version. For earlier versions, assume the compiler is MSVC 6.\r
177 """\r
178 prefix = "MSC v."\r
179 i = sys.version.find(prefix)\r
180 if i == -1:\r
181 return 6\r
182 i = i + len(prefix)\r
183 s, rest = sys.version[i:].split(" ", 1)\r
184 majorVersion = int(s[:-2]) - 6\r
185 minorVersion = int(s[2:3]) / 10.0\r
186 # I don't think paths are affected by minor version in version 6\r
187 if majorVersion == 6:\r
188 minorVersion = 0\r
189 if majorVersion >= 6:\r
190 return majorVersion + minorVersion\r
191 # else we don't know what version of the compiler this is\r
192 return None\r
193\r
194def normalize_and_reduce_paths(paths):\r
195 """Return a list of normalized paths with duplicates removed.\r
196\r
197 The current order of paths is maintained.\r
198 """\r
199 # Paths are normalized so things like: /a and /a/ aren't both preserved.\r
200 reduced_paths = []\r
201 for p in paths:\r
202 np = os.path.normpath(p)\r
203 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.\r
204 if np not in reduced_paths:\r
205 reduced_paths.append(np)\r
206 return reduced_paths\r
207\r
208def removeDuplicates(variable):\r
209 """Remove duplicate values of an environment variable.\r
210 """\r
211 oldList = variable.split(os.pathsep)\r
212 newList = []\r
213 for i in oldList:\r
214 if i not in newList:\r
215 newList.append(i)\r
216 newVariable = os.pathsep.join(newList)\r
217 return newVariable\r
218\r
219def find_vcvarsall(version):\r
220 """Find the vcvarsall.bat file\r
221\r
222 At first it tries to find the productdir of VS 2008 in the registry. If\r
223 that fails it falls back to the VS90COMNTOOLS env var.\r
224 """\r
225 vsbase = VS_BASE % version\r
226 try:\r
227 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,\r
228 "productdir")\r
229 except KeyError:\r
230 productdir = None\r
231\r
232 # trying Express edition\r
233 if productdir is None:\r
234 vsbase = VSEXPRESS_BASE % version\r
235 try:\r
236 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,\r
237 "productdir")\r
238 except KeyError:\r
239 productdir = None\r
240 log.debug("Unable to find productdir in registry")\r
241\r
242 if not productdir or not os.path.isdir(productdir):\r
243 toolskey = "VS%0.f0COMNTOOLS" % version\r
244 toolsdir = os.environ.get(toolskey, None)\r
245\r
246 if toolsdir and os.path.isdir(toolsdir):\r
247 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")\r
248 productdir = os.path.abspath(productdir)\r
249 if not os.path.isdir(productdir):\r
250 log.debug("%s is not a valid directory" % productdir)\r
251 return None\r
252 else:\r
253 log.debug("Env var %s is not set or invalid" % toolskey)\r
254 if not productdir:\r
255 log.debug("No productdir found")\r
256 return None\r
257 vcvarsall = os.path.join(productdir, "vcvarsall.bat")\r
258 if os.path.isfile(vcvarsall):\r
259 return vcvarsall\r
260 log.debug("Unable to find vcvarsall.bat")\r
261 return None\r
262\r
263def query_vcvarsall(version, arch="x86"):\r
264 """Launch vcvarsall.bat and read the settings from its environment\r
265 """\r
266 vcvarsall = find_vcvarsall(version)\r
267 interesting = set(("include", "lib", "libpath", "path"))\r
268 result = {}\r
269\r
270 if vcvarsall is None:\r
271 raise DistutilsPlatformError("Unable to find vcvarsall.bat")\r
272 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)\r
273 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),\r
274 stdout=subprocess.PIPE,\r
275 stderr=subprocess.PIPE)\r
276 try:\r
277 stdout, stderr = popen.communicate()\r
278 if popen.wait() != 0:\r
279 raise DistutilsPlatformError(stderr.decode("mbcs"))\r
280\r
281 stdout = stdout.decode("mbcs")\r
282 for line in stdout.split("\n"):\r
283 line = Reg.convert_mbcs(line)\r
284 if '=' not in line:\r
285 continue\r
286 line = line.strip()\r
287 key, value = line.split('=', 1)\r
288 key = key.lower()\r
289 if key in interesting:\r
290 if value.endswith(os.pathsep):\r
291 value = value[:-1]\r
292 result[key] = removeDuplicates(value)\r
293\r
294 finally:\r
295 popen.stdout.close()\r
296 popen.stderr.close()\r
297\r
298 if len(result) != len(interesting):\r
299 raise ValueError(str(list(result.keys())))\r
300\r
301 return result\r
302\r
303# More globals\r
304VERSION = get_build_version()\r
305if VERSION < 8.0:\r
306 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)\r
307# MACROS = MacroExpander(VERSION)\r
308\r
309class MSVCCompiler(CCompiler) :\r
310 """Concrete class that implements an interface to Microsoft Visual C++,\r
311 as defined by the CCompiler abstract class."""\r
312\r
313 compiler_type = 'msvc'\r
314\r
315 # Just set this so CCompiler's constructor doesn't barf. We currently\r
316 # don't use the 'set_executables()' bureaucracy provided by CCompiler,\r
317 # as it really isn't necessary for this sort of single-compiler class.\r
318 # Would be nice to have a consistent interface with UnixCCompiler,\r
319 # though, so it's worth thinking about.\r
320 executables = {}\r
321\r
322 # Private class data (need to distinguish C from C++ source for compiler)\r
323 _c_extensions = ['.c']\r
324 _cpp_extensions = ['.cc', '.cpp', '.cxx']\r
325 _rc_extensions = ['.rc']\r
326 _mc_extensions = ['.mc']\r
327\r
328 # Needed for the filename generation methods provided by the\r
329 # base class, CCompiler.\r
330 src_extensions = (_c_extensions + _cpp_extensions +\r
331 _rc_extensions + _mc_extensions)\r
332 res_extension = '.res'\r
333 obj_extension = '.obj'\r
334 static_lib_extension = '.lib'\r
335 shared_lib_extension = '.dll'\r
336 static_lib_format = shared_lib_format = '%s%s'\r
337 exe_extension = '.exe'\r
338\r
339 def __init__(self, verbose=0, dry_run=0, force=0):\r
340 CCompiler.__init__ (self, verbose, dry_run, force)\r
341 self.__version = VERSION\r
342 self.__root = r"Software\Microsoft\VisualStudio"\r
343 # self.__macros = MACROS\r
344 self.__paths = []\r
345 # target platform (.plat_name is consistent with 'bdist')\r
346 self.plat_name = None\r
347 self.__arch = None # deprecated name\r
348 self.initialized = False\r
349\r
350 def initialize(self, plat_name=None):\r
351 # multi-init means we would need to check platform same each time...\r
352 assert not self.initialized, "don't init multiple times"\r
353 if plat_name is None:\r
354 plat_name = get_platform()\r
355 # sanity check for platforms to prevent obscure errors later.\r
356 ok_plats = 'win32', 'win-amd64', 'win-ia64'\r
357 if plat_name not in ok_plats:\r
358 raise DistutilsPlatformError("--plat-name must be one of %s" %\r
359 (ok_plats,))\r
360\r
361 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):\r
362 # Assume that the SDK set up everything alright; don't try to be\r
363 # smarter\r
364 self.cc = "cl.exe"\r
365 self.linker = "link.exe"\r
366 self.lib = "lib.exe"\r
367 self.rc = "rc.exe"\r
368 self.mc = "mc.exe"\r
369 else:\r
370 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;\r
371 # to cross compile, you use 'x86_amd64'.\r
372 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross\r
373 # compile use 'x86' (ie, it runs the x86 compiler directly)\r
374 # No idea how itanium handles this, if at all.\r
375 if plat_name == get_platform() or plat_name == 'win32':\r
376 # native build or cross-compile to win32\r
377 plat_spec = PLAT_TO_VCVARS[plat_name]\r
378 else:\r
379 # cross compile from win32 -> some 64bit\r
380 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \\r
381 PLAT_TO_VCVARS[plat_name]\r
382\r
383 vc_env = query_vcvarsall(VERSION, plat_spec)\r
384\r
385 # take care to only use strings in the environment.\r
386 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)\r
387 os.environ['lib'] = vc_env['lib'].encode('mbcs')\r
388 os.environ['include'] = vc_env['include'].encode('mbcs')\r
389\r
390 if len(self.__paths) == 0:\r
391 raise DistutilsPlatformError("Python was built with %s, "\r
392 "and extensions need to be built with the same "\r
393 "version of the compiler, but it isn't installed."\r
394 % self.__product)\r
395\r
396 self.cc = self.find_exe("cl.exe")\r
397 self.linker = self.find_exe("link.exe")\r
398 self.lib = self.find_exe("lib.exe")\r
399 self.rc = self.find_exe("rc.exe") # resource compiler\r
400 self.mc = self.find_exe("mc.exe") # message compiler\r
401 #self.set_path_env_var('lib')\r
402 #self.set_path_env_var('include')\r
403\r
404 # extend the MSVC path with the current path\r
405 try:\r
406 for p in os.environ['path'].split(';'):\r
407 self.__paths.append(p)\r
408 except KeyError:\r
409 pass\r
410 self.__paths = normalize_and_reduce_paths(self.__paths)\r
411 os.environ['path'] = ";".join(self.__paths)\r
412\r
413 self.preprocess_options = None\r
414 if self.__arch == "x86":\r
415 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',\r
416 '/DNDEBUG']\r
417 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',\r
418 '/Z7', '/D_DEBUG']\r
419 else:\r
420 # Win64\r
421 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,\r
422 '/DNDEBUG']\r
423 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',\r
424 '/Z7', '/D_DEBUG']\r
425\r
426 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']\r
427 if self.__version >= 7:\r
428 self.ldflags_shared_debug = [\r
429 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'\r
430 ]\r
431 self.ldflags_static = [ '/nologo']\r
432\r
433 self.initialized = True\r
434\r
435 # -- Worker methods ------------------------------------------------\r
436\r
437 def object_filenames(self,\r
438 source_filenames,\r
439 strip_dir=0,\r
440 output_dir=''):\r
441 # Copied from ccompiler.py, extended to return .res as 'object'-file\r
442 # for .rc input file\r
443 if output_dir is None: output_dir = ''\r
444 obj_names = []\r
445 for src_name in source_filenames:\r
446 (base, ext) = os.path.splitext (src_name)\r
447 base = os.path.splitdrive(base)[1] # Chop off the drive\r
448 base = base[os.path.isabs(base):] # If abs, chop off leading /\r
449 if ext not in self.src_extensions:\r
450 # Better to raise an exception instead of silently continuing\r
451 # and later complain about sources and targets having\r
452 # different lengths\r
453 raise CompileError ("Don't know how to compile %s" % src_name)\r
454 if strip_dir:\r
455 base = os.path.basename (base)\r
456 if ext in self._rc_extensions:\r
457 obj_names.append (os.path.join (output_dir,\r
458 base + self.res_extension))\r
459 elif ext in self._mc_extensions:\r
460 obj_names.append (os.path.join (output_dir,\r
461 base + self.res_extension))\r
462 else:\r
463 obj_names.append (os.path.join (output_dir,\r
464 base + self.obj_extension))\r
465 return obj_names\r
466\r
467\r
468 def compile(self, sources,\r
469 output_dir=None, macros=None, include_dirs=None, debug=0,\r
470 extra_preargs=None, extra_postargs=None, depends=None):\r
471\r
472 if not self.initialized:\r
473 self.initialize()\r
474 compile_info = self._setup_compile(output_dir, macros, include_dirs,\r
475 sources, depends, extra_postargs)\r
476 macros, objects, extra_postargs, pp_opts, build = compile_info\r
477\r
478 compile_opts = extra_preargs or []\r
479 compile_opts.append ('/c')\r
480 if debug:\r
481 compile_opts.extend(self.compile_options_debug)\r
482 else:\r
483 compile_opts.extend(self.compile_options)\r
484\r
485 for obj in objects:\r
486 try:\r
487 src, ext = build[obj]\r
488 except KeyError:\r
489 continue\r
490 if debug:\r
491 # pass the full pathname to MSVC in debug mode,\r
492 # this allows the debugger to find the source file\r
493 # without asking the user to browse for it\r
494 src = os.path.abspath(src)\r
495\r
496 if ext in self._c_extensions:\r
497 input_opt = "/Tc" + src\r
498 elif ext in self._cpp_extensions:\r
499 input_opt = "/Tp" + src\r
500 elif ext in self._rc_extensions:\r
501 # compile .RC to .RES file\r
502 input_opt = src\r
503 output_opt = "/fo" + obj\r
504 try:\r
505 self.spawn([self.rc] + pp_opts +\r
506 [output_opt] + [input_opt])\r
507 except DistutilsExecError, msg:\r
508 raise CompileError(msg)\r
509 continue\r
510 elif ext in self._mc_extensions:\r
511 # Compile .MC to .RC file to .RES file.\r
512 # * '-h dir' specifies the directory for the\r
513 # generated include file\r
514 # * '-r dir' specifies the target directory of the\r
515 # generated RC file and the binary message resource\r
516 # it includes\r
517 #\r
518 # For now (since there are no options to change this),\r
519 # we use the source-directory for the include file and\r
520 # the build directory for the RC file and message\r
521 # resources. This works at least for win32all.\r
522 h_dir = os.path.dirname(src)\r
523 rc_dir = os.path.dirname(obj)\r
524 try:\r
525 # first compile .MC to .RC and .H file\r
526 self.spawn([self.mc] +\r
527 ['-h', h_dir, '-r', rc_dir] + [src])\r
528 base, _ = os.path.splitext (os.path.basename (src))\r
529 rc_file = os.path.join (rc_dir, base + '.rc')\r
530 # then compile .RC to .RES file\r
531 self.spawn([self.rc] +\r
532 ["/fo" + obj] + [rc_file])\r
533\r
534 except DistutilsExecError, msg:\r
535 raise CompileError(msg)\r
536 continue\r
537 else:\r
538 # how to handle this file?\r
539 raise CompileError("Don't know how to compile %s to %s"\r
540 % (src, obj))\r
541\r
542 output_opt = "/Fo" + obj\r
543 try:\r
544 self.spawn([self.cc] + compile_opts + pp_opts +\r
545 [input_opt, output_opt] +\r
546 extra_postargs)\r
547 except DistutilsExecError, msg:\r
548 raise CompileError(msg)\r
549\r
550 return objects\r
551\r
552\r
553 def create_static_lib(self,\r
554 objects,\r
555 output_libname,\r
556 output_dir=None,\r
557 debug=0,\r
558 target_lang=None):\r
559\r
560 if not self.initialized:\r
561 self.initialize()\r
562 (objects, output_dir) = self._fix_object_args(objects, output_dir)\r
563 output_filename = self.library_filename(output_libname,\r
564 output_dir=output_dir)\r
565\r
566 if self._need_link(objects, output_filename):\r
567 lib_args = objects + ['/OUT:' + output_filename]\r
568 if debug:\r
569 pass # XXX what goes here?\r
570 try:\r
571 self.spawn([self.lib] + lib_args)\r
572 except DistutilsExecError, msg:\r
573 raise LibError(msg)\r
574 else:\r
575 log.debug("skipping %s (up-to-date)", output_filename)\r
576\r
577\r
578 def link(self,\r
579 target_desc,\r
580 objects,\r
581 output_filename,\r
582 output_dir=None,\r
583 libraries=None,\r
584 library_dirs=None,\r
585 runtime_library_dirs=None,\r
586 export_symbols=None,\r
587 debug=0,\r
588 extra_preargs=None,\r
589 extra_postargs=None,\r
590 build_temp=None,\r
591 target_lang=None):\r
592\r
593 if not self.initialized:\r
594 self.initialize()\r
595 (objects, output_dir) = self._fix_object_args(objects, output_dir)\r
596 fixed_args = self._fix_lib_args(libraries, library_dirs,\r
597 runtime_library_dirs)\r
598 (libraries, library_dirs, runtime_library_dirs) = fixed_args\r
599\r
600 if runtime_library_dirs:\r
601 self.warn ("I don't know what to do with 'runtime_library_dirs': "\r
602 + str (runtime_library_dirs))\r
603\r
604 lib_opts = gen_lib_options(self,\r
605 library_dirs, runtime_library_dirs,\r
606 libraries)\r
607 if output_dir is not None:\r
608 output_filename = os.path.join(output_dir, output_filename)\r
609\r
610 if self._need_link(objects, output_filename):\r
611 if target_desc == CCompiler.EXECUTABLE:\r
612 if debug:\r
613 ldflags = self.ldflags_shared_debug[1:]\r
614 else:\r
615 ldflags = self.ldflags_shared[1:]\r
616 else:\r
617 if debug:\r
618 ldflags = self.ldflags_shared_debug\r
619 else:\r
620 ldflags = self.ldflags_shared\r
621\r
622 export_opts = []\r
623 for sym in (export_symbols or []):\r
624 export_opts.append("/EXPORT:" + sym)\r
625\r
626 ld_args = (ldflags + lib_opts + export_opts +\r
627 objects + ['/OUT:' + output_filename])\r
628\r
629 # The MSVC linker generates .lib and .exp files, which cannot be\r
630 # suppressed by any linker switches. The .lib files may even be\r
631 # needed! Make sure they are generated in the temporary build\r
632 # directory. Since they have different names for debug and release\r
633 # builds, they can go into the same directory.\r
634 build_temp = os.path.dirname(objects[0])\r
635 if export_symbols is not None:\r
636 (dll_name, dll_ext) = os.path.splitext(\r
637 os.path.basename(output_filename))\r
638 implib_file = os.path.join(\r
639 build_temp,\r
640 self.library_filename(dll_name))\r
641 ld_args.append ('/IMPLIB:' + implib_file)\r
642\r
643 # Embedded manifests are recommended - see MSDN article titled\r
644 # "How to: Embed a Manifest Inside a C/C++ Application"\r
645 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)\r
646 # Ask the linker to generate the manifest in the temp dir, so\r
647 # we can embed it later.\r
648 temp_manifest = os.path.join(\r
649 build_temp,\r
650 os.path.basename(output_filename) + ".manifest")\r
651 ld_args.append('/MANIFESTFILE:' + temp_manifest)\r
652\r
653 if extra_preargs:\r
654 ld_args[:0] = extra_preargs\r
655 if extra_postargs:\r
656 ld_args.extend(extra_postargs)\r
657\r
658 self.mkpath(os.path.dirname(output_filename))\r
659 try:\r
660 self.spawn([self.linker] + ld_args)\r
661 except DistutilsExecError, msg:\r
662 raise LinkError(msg)\r
663\r
664 # embed the manifest\r
665 # XXX - this is somewhat fragile - if mt.exe fails, distutils\r
666 # will still consider the DLL up-to-date, but it will not have a\r
667 # manifest. Maybe we should link to a temp file? OTOH, that\r
668 # implies a build environment error that shouldn't go undetected.\r
669 if target_desc == CCompiler.EXECUTABLE:\r
670 mfid = 1\r
671 else:\r
672 mfid = 2\r
673 self._remove_visual_c_ref(temp_manifest)\r
674 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)\r
675 try:\r
676 self.spawn(['mt.exe', '-nologo', '-manifest',\r
677 temp_manifest, out_arg])\r
678 except DistutilsExecError, msg:\r
679 raise LinkError(msg)\r
680 else:\r
681 log.debug("skipping %s (up-to-date)", output_filename)\r
682\r
683 def _remove_visual_c_ref(self, manifest_file):\r
684 try:\r
685 # Remove references to the Visual C runtime, so they will\r
686 # fall through to the Visual C dependency of Python.exe.\r
687 # This way, when installed for a restricted user (e.g.\r
688 # runtimes are not in WinSxS folder, but in Python's own\r
689 # folder), the runtimes do not need to be in every folder\r
690 # with .pyd's.\r
691 manifest_f = open(manifest_file)\r
692 try:\r
693 manifest_buf = manifest_f.read()\r
694 finally:\r
695 manifest_f.close()\r
696 pattern = re.compile(\r
697 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\\r
698 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",\r
699 re.DOTALL)\r
700 manifest_buf = re.sub(pattern, "", manifest_buf)\r
701 pattern = "<dependentAssembly>\s*</dependentAssembly>"\r
702 manifest_buf = re.sub(pattern, "", manifest_buf)\r
703 manifest_f = open(manifest_file, 'w')\r
704 try:\r
705 manifest_f.write(manifest_buf)\r
706 finally:\r
707 manifest_f.close()\r
708 except IOError:\r
709 pass\r
710\r
711 # -- Miscellaneous methods -----------------------------------------\r
712 # These are all used by the 'gen_lib_options() function, in\r
713 # ccompiler.py.\r
714\r
715 def library_dir_option(self, dir):\r
716 return "/LIBPATH:" + dir\r
717\r
718 def runtime_library_dir_option(self, dir):\r
719 raise DistutilsPlatformError(\r
720 "don't know how to set runtime library search path for MSVC++")\r
721\r
722 def library_option(self, lib):\r
723 return self.library_filename(lib)\r
724\r
725\r
726 def find_library_file(self, dirs, lib, debug=0):\r
727 # Prefer a debugging library if found (and requested), but deal\r
728 # with it if we don't have one.\r
729 if debug:\r
730 try_names = [lib + "_d", lib]\r
731 else:\r
732 try_names = [lib]\r
733 for dir in dirs:\r
734 for name in try_names:\r
735 libfile = os.path.join(dir, self.library_filename (name))\r
736 if os.path.exists(libfile):\r
737 return libfile\r
738 else:\r
739 # Oops, didn't find it in *any* of 'dirs'\r
740 return None\r
741\r
742 # Helper methods for using the MSVC registry settings\r
743\r
744 def find_exe(self, exe):\r
745 """Return path to an MSVC executable program.\r
746\r
747 Tries to find the program in several places: first, one of the\r
748 MSVC program search paths from the registry; next, the directories\r
749 in the PATH environment variable. If any of those work, return an\r
750 absolute path that is known to exist. If none of them work, just\r
751 return the original program name, 'exe'.\r
752 """\r
753 for p in self.__paths:\r
754 fn = os.path.join(os.path.abspath(p), exe)\r
755 if os.path.isfile(fn):\r
756 return fn\r
757\r
758 # didn't find it; try existing path\r
759 for p in os.environ['Path'].split(';'):\r
760 fn = os.path.join(os.path.abspath(p),exe)\r
761 if os.path.isfile(fn):\r
762 return fn\r
763\r
764 return exe\r