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