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