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