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