blob: 6d7825df86ea32e7f814f40ae65710185cf28102 [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"))
270 finally:
271 popen.close()
Christian Heimesb9eccbf2007-12-05 20:18:38 +0000272
273 stdout = stdout.decode("mbcs")
274 for line in stdout.split("\n"):
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000275 line = Reg.convert_mbcs(line)
276 if '=' not in line:
277 continue
278 line = line.strip()
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000279 key, value = line.split('=', 1)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000280 key = key.lower()
281 if key in interesting:
282 if value.endswith(os.pathsep):
283 value = value[:-1]
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000284 result[key] = removeDuplicates(value)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000285
286 if len(result) != len(interesting):
287 raise ValueError(str(list(result.keys())))
288
289 return result
290
291# More globals
292VERSION = get_build_version()
293if VERSION < 8.0:
294 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000295# MACROS = MacroExpander(VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000296
297class MSVCCompiler(CCompiler) :
298 """Concrete class that implements an interface to Microsoft Visual C++,
299 as defined by the CCompiler abstract class."""
300
301 compiler_type = 'msvc'
302
303 # Just set this so CCompiler's constructor doesn't barf. We currently
304 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
305 # as it really isn't necessary for this sort of single-compiler class.
306 # Would be nice to have a consistent interface with UnixCCompiler,
307 # though, so it's worth thinking about.
308 executables = {}
309
310 # Private class data (need to distinguish C from C++ source for compiler)
311 _c_extensions = ['.c']
312 _cpp_extensions = ['.cc', '.cpp', '.cxx']
313 _rc_extensions = ['.rc']
314 _mc_extensions = ['.mc']
315
316 # Needed for the filename generation methods provided by the
317 # base class, CCompiler.
318 src_extensions = (_c_extensions + _cpp_extensions +
319 _rc_extensions + _mc_extensions)
320 res_extension = '.res'
321 obj_extension = '.obj'
322 static_lib_extension = '.lib'
323 shared_lib_extension = '.dll'
324 static_lib_format = shared_lib_format = '%s%s'
325 exe_extension = '.exe'
326
327 def __init__(self, verbose=0, dry_run=0, force=0):
328 CCompiler.__init__ (self, verbose, dry_run, force)
329 self.__version = VERSION
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000330 self.__root = r"Software\Microsoft\VisualStudio"
331 # self.__macros = MACROS
Christian Heimes94e07722008-11-28 11:05:17 +0000332 self.__paths = []
Christian Heimes5e696852008-04-09 08:37:03 +0000333 # target platform (.plat_name is consistent with 'bdist')
334 self.plat_name = None
335 self.__arch = None # deprecated name
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000336 self.initialized = False
337
Christian Heimes5e696852008-04-09 08:37:03 +0000338 def initialize(self, plat_name=None):
339 # multi-init means we would need to check platform same each time...
340 assert not self.initialized, "don't init multiple times"
341 if plat_name is None:
342 plat_name = get_platform()
343 # sanity check for platforms to prevent obscure errors later.
344 ok_plats = 'win32', 'win-amd64', 'win-ia64'
345 if plat_name not in ok_plats:
346 raise DistutilsPlatformError("--plat-name must be one of %s" %
347 (ok_plats,))
348
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000349 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
350 # Assume that the SDK set up everything alright; don't try to be
351 # smarter
352 self.cc = "cl.exe"
353 self.linker = "link.exe"
354 self.lib = "lib.exe"
355 self.rc = "rc.exe"
356 self.mc = "mc.exe"
357 else:
Christian Heimes5e696852008-04-09 08:37:03 +0000358 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
359 # to cross compile, you use 'x86_amd64'.
360 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
361 # compile use 'x86' (ie, it runs the x86 compiler directly)
362 # No idea how itanium handles this, if at all.
363 if plat_name == get_platform() or plat_name == 'win32':
364 # native build or cross-compile to win32
365 plat_spec = PLAT_TO_VCVARS[plat_name]
366 else:
367 # cross compile from win32 -> some 64bit
368 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
369 PLAT_TO_VCVARS[plat_name]
370
371 vc_env = query_vcvarsall(VERSION, plat_spec)
372
373 self.__paths = vc_env['path'].split(os.pathsep)
374 os.environ['lib'] = vc_env['lib']
375 os.environ['include'] = vc_env['include']
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000376
377 if len(self.__paths) == 0:
378 raise DistutilsPlatformError("Python was built with %s, "
379 "and extensions need to be built with the same "
380 "version of the compiler, but it isn't installed."
381 % self.__product)
382
383 self.cc = self.find_exe("cl.exe")
384 self.linker = self.find_exe("link.exe")
385 self.lib = self.find_exe("lib.exe")
386 self.rc = self.find_exe("rc.exe") # resource compiler
387 self.mc = self.find_exe("mc.exe") # message compiler
388 #self.set_path_env_var('lib')
389 #self.set_path_env_var('include')
390
391 # extend the MSVC path with the current path
392 try:
393 for p in os.environ['path'].split(';'):
394 self.__paths.append(p)
395 except KeyError:
396 pass
397 self.__paths = normalize_and_reduce_paths(self.__paths)
398 os.environ['path'] = ";".join(self.__paths)
399
400 self.preprocess_options = None
401 if self.__arch == "x86":
402 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
403 '/DNDEBUG']
404 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
405 '/Z7', '/D_DEBUG']
406 else:
407 # Win64
408 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
409 '/DNDEBUG']
410 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
411 '/Z7', '/D_DEBUG']
412
413 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
414 if self.__version >= 7:
415 self.ldflags_shared_debug = [
416 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
417 ]
418 self.ldflags_static = [ '/nologo']
419
420 self.initialized = True
421
422 # -- Worker methods ------------------------------------------------
423
424 def object_filenames(self,
425 source_filenames,
426 strip_dir=0,
427 output_dir=''):
428 # Copied from ccompiler.py, extended to return .res as 'object'-file
429 # for .rc input file
430 if output_dir is None: output_dir = ''
431 obj_names = []
432 for src_name in source_filenames:
433 (base, ext) = os.path.splitext (src_name)
434 base = os.path.splitdrive(base)[1] # Chop off the drive
435 base = base[os.path.isabs(base):] # If abs, chop off leading /
436 if ext not in self.src_extensions:
437 # Better to raise an exception instead of silently continuing
438 # and later complain about sources and targets having
439 # different lengths
440 raise CompileError ("Don't know how to compile %s" % src_name)
441 if strip_dir:
442 base = os.path.basename (base)
443 if ext in self._rc_extensions:
444 obj_names.append (os.path.join (output_dir,
445 base + self.res_extension))
446 elif ext in self._mc_extensions:
447 obj_names.append (os.path.join (output_dir,
448 base + self.res_extension))
449 else:
450 obj_names.append (os.path.join (output_dir,
451 base + self.obj_extension))
452 return obj_names
453
454
455 def compile(self, sources,
456 output_dir=None, macros=None, include_dirs=None, debug=0,
457 extra_preargs=None, extra_postargs=None, depends=None):
458
459 if not self.initialized:
460 self.initialize()
461 compile_info = self._setup_compile(output_dir, macros, include_dirs,
462 sources, depends, extra_postargs)
463 macros, objects, extra_postargs, pp_opts, build = compile_info
464
465 compile_opts = extra_preargs or []
466 compile_opts.append ('/c')
467 if debug:
468 compile_opts.extend(self.compile_options_debug)
469 else:
470 compile_opts.extend(self.compile_options)
471
472 for obj in objects:
473 try:
474 src, ext = build[obj]
475 except KeyError:
476 continue
477 if debug:
478 # pass the full pathname to MSVC in debug mode,
479 # this allows the debugger to find the source file
480 # without asking the user to browse for it
481 src = os.path.abspath(src)
482
483 if ext in self._c_extensions:
484 input_opt = "/Tc" + src
485 elif ext in self._cpp_extensions:
486 input_opt = "/Tp" + src
487 elif ext in self._rc_extensions:
488 # compile .RC to .RES file
489 input_opt = src
490 output_opt = "/fo" + obj
491 try:
492 self.spawn([self.rc] + pp_opts +
493 [output_opt] + [input_opt])
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000494 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000495 raise CompileError(msg)
496 continue
497 elif ext in self._mc_extensions:
498 # Compile .MC to .RC file to .RES file.
499 # * '-h dir' specifies the directory for the
500 # generated include file
501 # * '-r dir' specifies the target directory of the
502 # generated RC file and the binary message resource
503 # it includes
504 #
505 # For now (since there are no options to change this),
506 # we use the source-directory for the include file and
507 # the build directory for the RC file and message
508 # resources. This works at least for win32all.
509 h_dir = os.path.dirname(src)
510 rc_dir = os.path.dirname(obj)
511 try:
512 # first compile .MC to .RC and .H file
513 self.spawn([self.mc] +
514 ['-h', h_dir, '-r', rc_dir] + [src])
515 base, _ = os.path.splitext (os.path.basename (src))
516 rc_file = os.path.join (rc_dir, base + '.rc')
517 # then compile .RC to .RES file
518 self.spawn([self.rc] +
519 ["/fo" + obj] + [rc_file])
520
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000521 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000522 raise CompileError(msg)
523 continue
524 else:
525 # how to handle this file?
526 raise CompileError("Don't know how to compile %s to %s"
527 % (src, obj))
528
529 output_opt = "/Fo" + obj
530 try:
531 self.spawn([self.cc] + compile_opts + pp_opts +
532 [input_opt, output_opt] +
533 extra_postargs)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000534 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000535 raise CompileError(msg)
536
537 return objects
538
539
540 def create_static_lib(self,
541 objects,
542 output_libname,
543 output_dir=None,
544 debug=0,
545 target_lang=None):
546
547 if not self.initialized:
548 self.initialize()
549 (objects, output_dir) = self._fix_object_args(objects, output_dir)
550 output_filename = self.library_filename(output_libname,
551 output_dir=output_dir)
552
553 if self._need_link(objects, output_filename):
554 lib_args = objects + ['/OUT:' + output_filename]
555 if debug:
556 pass # XXX what goes here?
557 try:
558 self.spawn([self.lib] + lib_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000559 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000560 raise LibError(msg)
561 else:
562 log.debug("skipping %s (up-to-date)", output_filename)
563
564
565 def link(self,
566 target_desc,
567 objects,
568 output_filename,
569 output_dir=None,
570 libraries=None,
571 library_dirs=None,
572 runtime_library_dirs=None,
573 export_symbols=None,
574 debug=0,
575 extra_preargs=None,
576 extra_postargs=None,
577 build_temp=None,
578 target_lang=None):
579
580 if not self.initialized:
581 self.initialize()
582 (objects, output_dir) = self._fix_object_args(objects, output_dir)
583 fixed_args = self._fix_lib_args(libraries, library_dirs,
584 runtime_library_dirs)
585 (libraries, library_dirs, runtime_library_dirs) = fixed_args
586
587 if runtime_library_dirs:
588 self.warn ("I don't know what to do with 'runtime_library_dirs': "
589 + str (runtime_library_dirs))
590
591 lib_opts = gen_lib_options(self,
592 library_dirs, runtime_library_dirs,
593 libraries)
594 if output_dir is not None:
595 output_filename = os.path.join(output_dir, output_filename)
596
597 if self._need_link(objects, output_filename):
598 if target_desc == CCompiler.EXECUTABLE:
599 if debug:
600 ldflags = self.ldflags_shared_debug[1:]
601 else:
602 ldflags = self.ldflags_shared[1:]
603 else:
604 if debug:
605 ldflags = self.ldflags_shared_debug
606 else:
607 ldflags = self.ldflags_shared
608
609 export_opts = []
610 for sym in (export_symbols or []):
611 export_opts.append("/EXPORT:" + sym)
612
613 ld_args = (ldflags + lib_opts + export_opts +
614 objects + ['/OUT:' + output_filename])
615
616 # The MSVC linker generates .lib and .exp files, which cannot be
617 # suppressed by any linker switches. The .lib files may even be
618 # needed! Make sure they are generated in the temporary build
619 # directory. Since they have different names for debug and release
620 # builds, they can go into the same directory.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000621 build_temp = os.path.dirname(objects[0])
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000622 if export_symbols is not None:
623 (dll_name, dll_ext) = os.path.splitext(
624 os.path.basename(output_filename))
625 implib_file = os.path.join(
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000626 build_temp,
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000627 self.library_filename(dll_name))
628 ld_args.append ('/IMPLIB:' + implib_file)
629
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000630 # Embedded manifests are recommended - see MSDN article titled
631 # "How to: Embed a Manifest Inside a C/C++ Application"
632 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
633 # Ask the linker to generate the manifest in the temp dir, so
634 # we can embed it later.
635 temp_manifest = os.path.join(
636 build_temp,
637 os.path.basename(output_filename) + ".manifest")
638 ld_args.append('/MANIFESTFILE:' + temp_manifest)
639
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000640 if extra_preargs:
641 ld_args[:0] = extra_preargs
642 if extra_postargs:
643 ld_args.extend(extra_postargs)
644
645 self.mkpath(os.path.dirname(output_filename))
646 try:
647 self.spawn([self.linker] + ld_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000648 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000649 raise LinkError(msg)
650
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000651 # embed the manifest
652 # XXX - this is somewhat fragile - if mt.exe fails, distutils
653 # will still consider the DLL up-to-date, but it will not have a
654 # manifest. Maybe we should link to a temp file? OTOH, that
655 # implies a build environment error that shouldn't go undetected.
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000656 if target_desc == CCompiler.EXECUTABLE:
657 mfid = 1
658 else:
659 mfid = 2
Tarek Ziadéb7e82bb2009-12-21 23:18:02 +0000660 # Remove references to the Visual C runtime
661 self._remove_visual_c_ref(temp_manifest)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000662 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
663 try:
664 self.spawn(['mt.exe', '-nologo', '-manifest',
665 temp_manifest, out_arg])
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000666 except DistutilsExecError as msg:
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000667 raise LinkError(msg)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000668 else:
669 log.debug("skipping %s (up-to-date)", output_filename)
670
Tarek Ziadéb7e82bb2009-12-21 23:18:02 +0000671 def _remove_visual_c_ref(self, manifest_file):
672 try:
673 # Remove references to the Visual C runtime, so they will
674 # fall through to the Visual C dependency of Python.exe.
675 # This way, when installed for a restricted user (e.g.
676 # runtimes are not in WinSxS folder, but in Python's own
677 # folder), the runtimes do not need to be in every folder
678 # with .pyd's.
679 manifest_f = open(manifest_file)
680 try:
681 manifest_buf = manifest_f.read()
682 finally:
683 manifest_f.close()
684 pattern = re.compile(
685 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
686 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
687 re.DOTALL)
688 manifest_buf = re.sub(pattern, "", manifest_buf)
689 pattern = "<dependentAssembly>\s*</dependentAssembly>"
690 manifest_buf = re.sub(pattern, "", manifest_buf)
691 manifest_f = open(manifest_file, 'w')
692 try:
693 manifest_f.write(manifest_buf)
694 finally:
695 manifest_f.close()
696 except IOError:
697 pass
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000698
699 # -- Miscellaneous methods -----------------------------------------
700 # These are all used by the 'gen_lib_options() function, in
701 # ccompiler.py.
702
703 def library_dir_option(self, dir):
704 return "/LIBPATH:" + dir
705
706 def runtime_library_dir_option(self, dir):
707 raise DistutilsPlatformError(
708 "don't know how to set runtime library search path for MSVC++")
709
710 def library_option(self, lib):
711 return self.library_filename(lib)
712
713
714 def find_library_file(self, dirs, lib, debug=0):
715 # Prefer a debugging library if found (and requested), but deal
716 # with it if we don't have one.
717 if debug:
718 try_names = [lib + "_d", lib]
719 else:
720 try_names = [lib]
721 for dir in dirs:
722 for name in try_names:
723 libfile = os.path.join(dir, self.library_filename (name))
724 if os.path.exists(libfile):
725 return libfile
726 else:
727 # Oops, didn't find it in *any* of 'dirs'
728 return None
729
730 # Helper methods for using the MSVC registry settings
731
732 def find_exe(self, exe):
733 """Return path to an MSVC executable program.
734
735 Tries to find the program in several places: first, one of the
736 MSVC program search paths from the registry; next, the directories
737 in the PATH environment variable. If any of those work, return an
738 absolute path that is known to exist. If none of them work, just
739 return the original program name, 'exe'.
740 """
741 for p in self.__paths:
742 fn = os.path.join(os.path.abspath(p), exe)
743 if os.path.isfile(fn):
744 return fn
745
746 # didn't find it; try existing path
747 for p in os.environ['Path'].split(';'):
748 fn = os.path.join(os.path.abspath(p),exe)
749 if os.path.isfile(fn):
750 return fn
751
752 return exe