blob: 7ec9b92a5dcbd0656c3bc4ecf32269d3a9e82202 [file] [log] [blame]
Christian Heimes3305c522007-12-03 13:47:29 +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öwisc218a2f2009-12-03 20:53:51 +000020import re
Tarek Ziadé943b24e2009-03-07 00:32:45 +000021
Tarek Ziadé2b66da72009-12-21 01:22:46 +000022from distutils.errors import (DistutilsExecError, DistutilsPlatformError,
23 CompileError, LibError, LinkError)
24from distutils.ccompiler import CCompiler, gen_lib_options
Christian Heimes3305c522007-12-03 13:47:29 +000025from distutils import log
Tarek Ziadé92e68af2010-01-26 22:46:15 +000026from distutils.util import get_platform
Christian Heimes3305c522007-12-03 13:47:29 +000027
Tarek Ziadé92e68af2010-01-26 22:46:15 +000028import _winreg
Tarek Ziadé5633a802010-01-23 09:23:15 +000029
Christian Heimes3305c522007-12-03 13:47:29 +000030RegOpenKeyEx = _winreg.OpenKeyEx
31RegEnumKey = _winreg.EnumKey
32RegEnumValue = _winreg.EnumValue
33RegError = _winreg.error
34
35HKEYS = (_winreg.HKEY_USERS,
36 _winreg.HKEY_CURRENT_USER,
37 _winreg.HKEY_LOCAL_MACHINE,
38 _winreg.HKEY_CLASSES_ROOT)
39
Benjamin Petersonafa1b302010-06-21 15:27:46 +000040NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)
41if NATIVE_WIN64:
42 # Visual C++ is a 32-bit application, so we need to look in
43 # the corresponding registry branch, if we're running a
44 # 64-bit Python on Win64
45 VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
46 VSEXPRESS_BASE = r"Software\Wow6432Node\Microsoft\VCExpress\%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 VSEXPRESS_BASE = r"Software\Microsoft\VCExpress\%0.1f"
52 WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
53 NET_BASE = r"Software\Microsoft\.NETFramework"
Christian Heimes3305c522007-12-03 13:47:29 +000054
Mark Hammond495cf992008-04-07 01:53:39 +000055# A map keyed by get_platform() return values to values accepted by
56# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
57# the param to cross-compile on x86 targetting amd64.)
58PLAT_TO_VCVARS = {
59 'win32' : 'x86',
60 'win-amd64' : 'amd64',
61 'win-ia64' : 'ia64',
62}
Christian Heimes3305c522007-12-03 13:47:29 +000063
64class Reg:
65 """Helper class to read values from the registry
66 """
67
Christian Heimes3305c522007-12-03 13:47:29 +000068 def get_value(cls, path, key):
69 for base in HKEYS:
70 d = cls.read_values(base, path)
71 if d and key in d:
72 return d[key]
73 raise KeyError(key)
Tarek Ziadé943b24e2009-03-07 00:32:45 +000074 get_value = classmethod(get_value)
Christian Heimes3305c522007-12-03 13:47:29 +000075
Christian Heimes3305c522007-12-03 13:47:29 +000076 def read_keys(cls, base, key):
77 """Return list of registry keys."""
78 try:
79 handle = RegOpenKeyEx(base, key)
80 except RegError:
81 return None
82 L = []
83 i = 0
84 while True:
85 try:
86 k = RegEnumKey(handle, i)
87 except RegError:
88 break
89 L.append(k)
90 i += 1
91 return L
Tarek Ziadé943b24e2009-03-07 00:32:45 +000092 read_keys = classmethod(read_keys)
Christian Heimes3305c522007-12-03 13:47:29 +000093
Christian Heimes3305c522007-12-03 13:47:29 +000094 def read_values(cls, base, key):
95 """Return dict of registry keys and values.
96
97 All names are converted to lowercase.
98 """
99 try:
100 handle = RegOpenKeyEx(base, key)
101 except RegError:
102 return None
103 d = {}
104 i = 0
105 while True:
106 try:
107 name, value, type = RegEnumValue(handle, i)
108 except RegError:
109 break
110 name = name.lower()
111 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
112 i += 1
113 return d
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000114 read_values = classmethod(read_values)
Christian Heimes3305c522007-12-03 13:47:29 +0000115
Christian Heimes3305c522007-12-03 13:47:29 +0000116 def convert_mbcs(s):
117 dec = getattr(s, "decode", None)
118 if dec is not None:
119 try:
120 s = dec("mbcs")
121 except UnicodeError:
122 pass
123 return s
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000124 convert_mbcs = staticmethod(convert_mbcs)
Christian Heimes3305c522007-12-03 13:47:29 +0000125
126class MacroExpander:
127
128 def __init__(self, version):
129 self.macros = {}
130 self.vsbase = VS_BASE % version
131 self.load_macros(version)
132
133 def set_macro(self, macro, path, key):
134 self.macros["$(%s)" % macro] = Reg.get_value(path, key)
135
136 def load_macros(self, version):
137 self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
138 self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
139 self.set_macro("FrameworkDir", NET_BASE, "installroot")
140 try:
141 if version >= 8.0:
142 self.set_macro("FrameworkSDKDir", NET_BASE,
143 "sdkinstallrootv2.0")
144 else:
145 raise KeyError("sdkinstallrootv2.0")
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000146 except KeyError:
Christian Heimes3305c522007-12-03 13:47:29 +0000147 raise DistutilsPlatformError(
148 """Python was built with Visual Studio 2008;
149extensions must be built with a compiler than can generate compatible binaries.
150Visual Studio 2008 was not found on this system. If you have Cygwin installed,
151you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
152
153 if version >= 9.0:
154 self.set_macro("FrameworkVersion", self.vsbase, "clr version")
155 self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
156 else:
157 p = r"Software\Microsoft\NET Framework Setup\Product"
158 for base in HKEYS:
159 try:
160 h = RegOpenKeyEx(base, p)
161 except RegError:
162 continue
163 key = RegEnumKey(h, 0)
164 d = Reg.get_value(base, r"%s\%s" % (p, key))
165 self.macros["$(FrameworkVersion)"] = d["version"]
166
167 def sub(self, s):
168 for k, v in self.macros.items():
169 s = s.replace(k, v)
170 return s
171
172def get_build_version():
173 """Return the version of MSVC that was used to build Python.
174
175 For Python 2.3 and up, the version number is included in
176 sys.version. For earlier versions, assume the compiler is MSVC 6.
177 """
178 prefix = "MSC v."
179 i = sys.version.find(prefix)
180 if i == -1:
181 return 6
182 i = i + len(prefix)
183 s, rest = sys.version[i:].split(" ", 1)
184 majorVersion = int(s[:-2]) - 6
185 minorVersion = int(s[2:3]) / 10.0
186 # I don't think paths are affected by minor version in version 6
187 if majorVersion == 6:
188 minorVersion = 0
189 if majorVersion >= 6:
190 return majorVersion + minorVersion
191 # else we don't know what version of the compiler this is
192 return None
193
Christian Heimes3305c522007-12-03 13:47:29 +0000194def normalize_and_reduce_paths(paths):
195 """Return a list of normalized paths with duplicates removed.
196
197 The current order of paths is maintained.
198 """
199 # Paths are normalized so things like: /a and /a/ aren't both preserved.
200 reduced_paths = []
201 for p in paths:
202 np = os.path.normpath(p)
203 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
204 if np not in reduced_paths:
205 reduced_paths.append(np)
206 return reduced_paths
207
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000208def removeDuplicates(variable):
209 """Remove duplicate values of an environment variable.
210 """
211 oldList = variable.split(os.pathsep)
212 newList = []
213 for i in oldList:
214 if i not in newList:
215 newList.append(i)
216 newVariable = os.pathsep.join(newList)
217 return newVariable
218
Christian Heimes3305c522007-12-03 13:47:29 +0000219def find_vcvarsall(version):
220 """Find the vcvarsall.bat file
221
222 At first it tries to find the productdir of VS 2008 in the registry. If
223 that fails it falls back to the VS90COMNTOOLS env var.
224 """
225 vsbase = VS_BASE % version
226 try:
227 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
228 "productdir")
229 except KeyError:
Christian Heimes3305c522007-12-03 13:47:29 +0000230 productdir = None
231
Tarek Ziadéc49b6ef2010-03-06 02:17:28 +0000232 # trying Express edition
233 if productdir is None:
234 vsbase = VSEXPRESS_BASE % version
235 try:
236 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
237 "productdir")
238 except KeyError:
239 productdir = None
240 log.debug("Unable to find productdir in registry")
241
Christian Heimes3305c522007-12-03 13:47:29 +0000242 if not productdir or not os.path.isdir(productdir):
243 toolskey = "VS%0.f0COMNTOOLS" % version
244 toolsdir = os.environ.get(toolskey, None)
245
246 if toolsdir and os.path.isdir(toolsdir):
247 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
248 productdir = os.path.abspath(productdir)
249 if not os.path.isdir(productdir):
250 log.debug("%s is not a valid directory" % productdir)
251 return None
252 else:
253 log.debug("Env var %s is not set or invalid" % toolskey)
254 if not productdir:
255 log.debug("No productdir found")
256 return None
257 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
258 if os.path.isfile(vcvarsall):
259 return vcvarsall
260 log.debug("Unable to find vcvarsall.bat")
261 return None
262
263def query_vcvarsall(version, arch="x86"):
264 """Launch vcvarsall.bat and read the settings from its environment
265 """
266 vcvarsall = find_vcvarsall(version)
267 interesting = set(("include", "lib", "libpath", "path"))
268 result = {}
269
270 if vcvarsall is None:
Tarek Ziadéb1a85412008-12-30 23:03:41 +0000271 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Mark Hammond495cf992008-04-07 01:53:39 +0000272 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimes3305c522007-12-03 13:47:29 +0000273 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
274 stdout=subprocess.PIPE,
275 stderr=subprocess.PIPE)
Éric Araujod1feff72010-11-06 04:06:18 +0000276 try:
277 stdout, stderr = popen.communicate()
278 if popen.wait() != 0:
279 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimescbdb7052007-12-05 20:10:38 +0000280
Éric Araujo4ca58a92010-11-12 20:31:17 +0000281 stdout = stdout.decode("mbcs")
282 for line in stdout.split("\n"):
283 line = Reg.convert_mbcs(line)
284 if '=' not in line:
285 continue
286 line = line.strip()
287 key, value = line.split('=', 1)
288 key = key.lower()
289 if key in interesting:
290 if value.endswith(os.pathsep):
291 value = value[:-1]
292 result[key] = removeDuplicates(value)
293
294 finally:
Éric Araujo4ca58a92010-11-12 20:31:17 +0000295 popen.stdout.close()
296 popen.stderr.close()
Christian Heimes3305c522007-12-03 13:47:29 +0000297
298 if len(result) != len(interesting):
299 raise ValueError(str(list(result.keys())))
300
301 return result
302
303# More globals
304VERSION = get_build_version()
305if VERSION < 8.0:
306 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000307# MACROS = MacroExpander(VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000308
309class MSVCCompiler(CCompiler) :
310 """Concrete class that implements an interface to Microsoft Visual C++,
311 as defined by the CCompiler abstract class."""
312
313 compiler_type = 'msvc'
314
315 # Just set this so CCompiler's constructor doesn't barf. We currently
316 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
317 # as it really isn't necessary for this sort of single-compiler class.
318 # Would be nice to have a consistent interface with UnixCCompiler,
319 # though, so it's worth thinking about.
320 executables = {}
321
322 # Private class data (need to distinguish C from C++ source for compiler)
323 _c_extensions = ['.c']
324 _cpp_extensions = ['.cc', '.cpp', '.cxx']
325 _rc_extensions = ['.rc']
326 _mc_extensions = ['.mc']
327
328 # Needed for the filename generation methods provided by the
329 # base class, CCompiler.
330 src_extensions = (_c_extensions + _cpp_extensions +
331 _rc_extensions + _mc_extensions)
332 res_extension = '.res'
333 obj_extension = '.obj'
334 static_lib_extension = '.lib'
335 shared_lib_extension = '.dll'
336 static_lib_format = shared_lib_format = '%s%s'
337 exe_extension = '.exe'
338
339 def __init__(self, verbose=0, dry_run=0, force=0):
340 CCompiler.__init__ (self, verbose, dry_run, force)
341 self.__version = VERSION
Christian Heimes3305c522007-12-03 13:47:29 +0000342 self.__root = r"Software\Microsoft\VisualStudio"
343 # self.__macros = MACROS
Christian Heimesaa674712008-11-28 11:02:32 +0000344 self.__paths = []
Mark Hammond495cf992008-04-07 01:53:39 +0000345 # target platform (.plat_name is consistent with 'bdist')
346 self.plat_name = None
347 self.__arch = None # deprecated name
Christian Heimes3305c522007-12-03 13:47:29 +0000348 self.initialized = False
349
Mark Hammond495cf992008-04-07 01:53:39 +0000350 def initialize(self, plat_name=None):
351 # multi-init means we would need to check platform same each time...
352 assert not self.initialized, "don't init multiple times"
353 if plat_name is None:
Tarek Ziadé92e68af2010-01-26 22:46:15 +0000354 plat_name = get_platform()
Mark Hammond495cf992008-04-07 01:53:39 +0000355 # sanity check for platforms to prevent obscure errors later.
356 ok_plats = 'win32', 'win-amd64', 'win-ia64'
357 if plat_name not in ok_plats:
358 raise DistutilsPlatformError("--plat-name must be one of %s" %
359 (ok_plats,))
360
Christian Heimes3305c522007-12-03 13:47:29 +0000361 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
362 # Assume that the SDK set up everything alright; don't try to be
363 # smarter
364 self.cc = "cl.exe"
365 self.linker = "link.exe"
366 self.lib = "lib.exe"
367 self.rc = "rc.exe"
368 self.mc = "mc.exe"
369 else:
Mark Hammond495cf992008-04-07 01:53:39 +0000370 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
371 # to cross compile, you use 'x86_amd64'.
372 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
373 # compile use 'x86' (ie, it runs the x86 compiler directly)
374 # No idea how itanium handles this, if at all.
Tarek Ziadé92e68af2010-01-26 22:46:15 +0000375 if plat_name == get_platform() or plat_name == 'win32':
Mark Hammond495cf992008-04-07 01:53:39 +0000376 # native build or cross-compile to win32
377 plat_spec = PLAT_TO_VCVARS[plat_name]
378 else:
379 # cross compile from win32 -> some 64bit
Tarek Ziadé92e68af2010-01-26 22:46:15 +0000380 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
Mark Hammond495cf992008-04-07 01:53:39 +0000381 PLAT_TO_VCVARS[plat_name]
382
383 vc_env = query_vcvarsall(VERSION, plat_spec)
384
Mark Hammond900155f2008-09-18 03:51:46 +0000385 # take care to only use strings in the environment.
386 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
387 os.environ['lib'] = vc_env['lib'].encode('mbcs')
388 os.environ['include'] = vc_env['include'].encode('mbcs')
Christian Heimes3305c522007-12-03 13:47:29 +0000389
390 if len(self.__paths) == 0:
391 raise DistutilsPlatformError("Python was built with %s, "
392 "and extensions need to be built with the same "
393 "version of the compiler, but it isn't installed."
394 % self.__product)
395
396 self.cc = self.find_exe("cl.exe")
397 self.linker = self.find_exe("link.exe")
398 self.lib = self.find_exe("lib.exe")
399 self.rc = self.find_exe("rc.exe") # resource compiler
400 self.mc = self.find_exe("mc.exe") # message compiler
401 #self.set_path_env_var('lib')
402 #self.set_path_env_var('include')
403
404 # extend the MSVC path with the current path
405 try:
406 for p in os.environ['path'].split(';'):
407 self.__paths.append(p)
408 except KeyError:
409 pass
410 self.__paths = normalize_and_reduce_paths(self.__paths)
411 os.environ['path'] = ";".join(self.__paths)
412
413 self.preprocess_options = None
414 if self.__arch == "x86":
415 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
416 '/DNDEBUG']
417 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
418 '/Z7', '/D_DEBUG']
419 else:
420 # Win64
421 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
422 '/DNDEBUG']
423 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
424 '/Z7', '/D_DEBUG']
425
426 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
427 if self.__version >= 7:
428 self.ldflags_shared_debug = [
429 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
430 ]
431 self.ldflags_static = [ '/nologo']
432
433 self.initialized = True
434
435 # -- Worker methods ------------------------------------------------
436
437 def object_filenames(self,
438 source_filenames,
439 strip_dir=0,
440 output_dir=''):
441 # Copied from ccompiler.py, extended to return .res as 'object'-file
442 # for .rc input file
443 if output_dir is None: output_dir = ''
444 obj_names = []
445 for src_name in source_filenames:
446 (base, ext) = os.path.splitext (src_name)
447 base = os.path.splitdrive(base)[1] # Chop off the drive
448 base = base[os.path.isabs(base):] # If abs, chop off leading /
449 if ext not in self.src_extensions:
450 # Better to raise an exception instead of silently continuing
451 # and later complain about sources and targets having
452 # different lengths
453 raise CompileError ("Don't know how to compile %s" % src_name)
454 if strip_dir:
455 base = os.path.basename (base)
456 if ext in self._rc_extensions:
457 obj_names.append (os.path.join (output_dir,
458 base + self.res_extension))
459 elif ext in self._mc_extensions:
460 obj_names.append (os.path.join (output_dir,
461 base + self.res_extension))
462 else:
463 obj_names.append (os.path.join (output_dir,
464 base + self.obj_extension))
465 return obj_names
466
467
468 def compile(self, sources,
469 output_dir=None, macros=None, include_dirs=None, debug=0,
470 extra_preargs=None, extra_postargs=None, depends=None):
471
472 if not self.initialized:
473 self.initialize()
474 compile_info = self._setup_compile(output_dir, macros, include_dirs,
475 sources, depends, extra_postargs)
476 macros, objects, extra_postargs, pp_opts, build = compile_info
477
478 compile_opts = extra_preargs or []
479 compile_opts.append ('/c')
480 if debug:
481 compile_opts.extend(self.compile_options_debug)
482 else:
483 compile_opts.extend(self.compile_options)
484
485 for obj in objects:
486 try:
487 src, ext = build[obj]
488 except KeyError:
489 continue
490 if debug:
491 # pass the full pathname to MSVC in debug mode,
492 # this allows the debugger to find the source file
493 # without asking the user to browse for it
494 src = os.path.abspath(src)
495
496 if ext in self._c_extensions:
497 input_opt = "/Tc" + src
498 elif ext in self._cpp_extensions:
499 input_opt = "/Tp" + src
500 elif ext in self._rc_extensions:
501 # compile .RC to .RES file
502 input_opt = src
503 output_opt = "/fo" + obj
504 try:
505 self.spawn([self.rc] + pp_opts +
506 [output_opt] + [input_opt])
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000507 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000508 raise CompileError(msg)
509 continue
510 elif ext in self._mc_extensions:
511 # Compile .MC to .RC file to .RES file.
512 # * '-h dir' specifies the directory for the
513 # generated include file
514 # * '-r dir' specifies the target directory of the
515 # generated RC file and the binary message resource
516 # it includes
517 #
518 # For now (since there are no options to change this),
519 # we use the source-directory for the include file and
520 # the build directory for the RC file and message
521 # resources. This works at least for win32all.
522 h_dir = os.path.dirname(src)
523 rc_dir = os.path.dirname(obj)
524 try:
525 # first compile .MC to .RC and .H file
526 self.spawn([self.mc] +
527 ['-h', h_dir, '-r', rc_dir] + [src])
528 base, _ = os.path.splitext (os.path.basename (src))
529 rc_file = os.path.join (rc_dir, base + '.rc')
530 # then compile .RC to .RES file
531 self.spawn([self.rc] +
532 ["/fo" + obj] + [rc_file])
533
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000534 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000535 raise CompileError(msg)
536 continue
537 else:
538 # how to handle this file?
539 raise CompileError("Don't know how to compile %s to %s"
540 % (src, obj))
541
542 output_opt = "/Fo" + obj
543 try:
544 self.spawn([self.cc] + compile_opts + pp_opts +
545 [input_opt, output_opt] +
546 extra_postargs)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000547 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000548 raise CompileError(msg)
549
550 return objects
551
552
553 def create_static_lib(self,
554 objects,
555 output_libname,
556 output_dir=None,
557 debug=0,
558 target_lang=None):
559
560 if not self.initialized:
561 self.initialize()
562 (objects, output_dir) = self._fix_object_args(objects, output_dir)
563 output_filename = self.library_filename(output_libname,
564 output_dir=output_dir)
565
566 if self._need_link(objects, output_filename):
567 lib_args = objects + ['/OUT:' + output_filename]
568 if debug:
569 pass # XXX what goes here?
570 try:
571 self.spawn([self.lib] + lib_args)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000572 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000573 raise LibError(msg)
574 else:
575 log.debug("skipping %s (up-to-date)", output_filename)
576
577
578 def link(self,
579 target_desc,
580 objects,
581 output_filename,
582 output_dir=None,
583 libraries=None,
584 library_dirs=None,
585 runtime_library_dirs=None,
586 export_symbols=None,
587 debug=0,
588 extra_preargs=None,
589 extra_postargs=None,
590 build_temp=None,
591 target_lang=None):
592
593 if not self.initialized:
594 self.initialize()
595 (objects, output_dir) = self._fix_object_args(objects, output_dir)
596 fixed_args = self._fix_lib_args(libraries, library_dirs,
597 runtime_library_dirs)
598 (libraries, library_dirs, runtime_library_dirs) = fixed_args
599
600 if runtime_library_dirs:
601 self.warn ("I don't know what to do with 'runtime_library_dirs': "
602 + str (runtime_library_dirs))
603
604 lib_opts = gen_lib_options(self,
605 library_dirs, runtime_library_dirs,
606 libraries)
607 if output_dir is not None:
608 output_filename = os.path.join(output_dir, output_filename)
609
610 if self._need_link(objects, output_filename):
611 if target_desc == CCompiler.EXECUTABLE:
612 if debug:
613 ldflags = self.ldflags_shared_debug[1:]
614 else:
615 ldflags = self.ldflags_shared[1:]
616 else:
617 if debug:
618 ldflags = self.ldflags_shared_debug
619 else:
620 ldflags = self.ldflags_shared
621
622 export_opts = []
623 for sym in (export_symbols or []):
624 export_opts.append("/EXPORT:" + sym)
625
626 ld_args = (ldflags + lib_opts + export_opts +
627 objects + ['/OUT:' + output_filename])
628
629 # The MSVC linker generates .lib and .exp files, which cannot be
630 # suppressed by any linker switches. The .lib files may even be
631 # needed! Make sure they are generated in the temporary build
632 # directory. Since they have different names for debug and release
633 # builds, they can go into the same directory.
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000634 build_temp = os.path.dirname(objects[0])
Christian Heimes3305c522007-12-03 13:47:29 +0000635 if export_symbols is not None:
636 (dll_name, dll_ext) = os.path.splitext(
637 os.path.basename(output_filename))
638 implib_file = os.path.join(
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000639 build_temp,
Christian Heimes3305c522007-12-03 13:47:29 +0000640 self.library_filename(dll_name))
641 ld_args.append ('/IMPLIB:' + implib_file)
642
Mark Hammond323b5da2011-10-17 11:05:36 +1100643 self.manifest_setup_ldargs(output_filename, build_temp, ld_args)
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000644
Christian Heimes3305c522007-12-03 13:47:29 +0000645 if extra_preargs:
646 ld_args[:0] = extra_preargs
647 if extra_postargs:
648 ld_args.extend(extra_postargs)
649
650 self.mkpath(os.path.dirname(output_filename))
651 try:
652 self.spawn([self.linker] + ld_args)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000653 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000654 raise LinkError(msg)
655
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000656 # embed the manifest
657 # XXX - this is somewhat fragile - if mt.exe fails, distutils
658 # will still consider the DLL up-to-date, but it will not have a
659 # manifest. Maybe we should link to a temp file? OTOH, that
660 # implies a build environment error that shouldn't go undetected.
Mark Hammond323b5da2011-10-17 11:05:36 +1100661 mfinfo = self.manifest_get_embed_info(target_desc, ld_args)
662 if mfinfo is not None:
663 mffilename, mfid = mfinfo
664 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
665 try:
666 self.spawn(['mt.exe', '-nologo', '-manifest',
667 mffilename, out_arg])
668 except DistutilsExecError, msg:
669 raise LinkError(msg)
Christian Heimes3305c522007-12-03 13:47:29 +0000670 else:
671 log.debug("skipping %s (up-to-date)", output_filename)
672
Mark Hammond323b5da2011-10-17 11:05:36 +1100673 def manifest_setup_ldargs(self, output_filename, build_temp, ld_args):
674 # If we need a manifest at all, an embedded manifest is recommended.
675 # See MSDN article titled
676 # "How to: Embed a Manifest Inside a C/C++ Application"
677 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
678 # Ask the linker to generate the manifest in the temp dir, so
679 # we can check it, and possibly embed it, later.
680 temp_manifest = os.path.join(
681 build_temp,
682 os.path.basename(output_filename) + ".manifest")
683 ld_args.append('/MANIFESTFILE:' + temp_manifest)
684
685 def manifest_get_embed_info(self, target_desc, ld_args):
686 # If a manifest should be embedded, return a tuple of
687 # (manifest_filename, resource_id). Returns None if no manifest
Mark Hammond3dca9f52011-10-17 11:35:06 +1100688 # should be embedded. See http://bugs.python.org/issue7833 for why
Mark Hammond323b5da2011-10-17 11:05:36 +1100689 # we want to avoid any manifest for extension modules if we can)
690 for arg in ld_args:
691 if arg.startswith("/MANIFESTFILE:"):
692 temp_manifest = arg.split(":", 1)[1]
693 break
694 else:
695 # no /MANIFESTFILE so nothing to do.
696 return None
697 if target_desc == CCompiler.EXECUTABLE:
698 # by default, executables always get the manifest with the
699 # CRT referenced.
700 mfid = 1
701 else:
702 # Extension modules try and avoid any manifest if possible.
703 mfid = 2
704 temp_manifest = self._remove_visual_c_ref(temp_manifest)
705 if temp_manifest is None:
706 return None
707 return temp_manifest, mfid
708
Tarek Ziadé3efd7672009-12-21 23:31:55 +0000709 def _remove_visual_c_ref(self, manifest_file):
710 try:
711 # Remove references to the Visual C runtime, so they will
712 # fall through to the Visual C dependency of Python.exe.
713 # This way, when installed for a restricted user (e.g.
714 # runtimes are not in WinSxS folder, but in Python's own
715 # folder), the runtimes do not need to be in every folder
716 # with .pyd's.
Mark Hammond323b5da2011-10-17 11:05:36 +1100717 # Returns either the filename of the modified manifest or
718 # None if no manifest should be embedded.
Tarek Ziadé3efd7672009-12-21 23:31:55 +0000719 manifest_f = open(manifest_file)
720 try:
721 manifest_buf = manifest_f.read()
722 finally:
723 manifest_f.close()
724 pattern = re.compile(
725 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
726 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
727 re.DOTALL)
728 manifest_buf = re.sub(pattern, "", manifest_buf)
729 pattern = "<dependentAssembly>\s*</dependentAssembly>"
730 manifest_buf = re.sub(pattern, "", manifest_buf)
Mark Hammond3dca9f52011-10-17 11:35:06 +1100731 # Now see if any other assemblies are referenced - if not, we
Mark Hammond323b5da2011-10-17 11:05:36 +1100732 # don't want a manifest embedded.
733 pattern = re.compile(
734 r"""<assemblyIdentity.*?name=(?:"|')(.+?)(?:"|')"""
735 r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL)
736 if re.search(pattern, manifest_buf) is None:
737 return None
738
Tarek Ziadé3efd7672009-12-21 23:31:55 +0000739 manifest_f = open(manifest_file, 'w')
740 try:
741 manifest_f.write(manifest_buf)
Mark Hammond323b5da2011-10-17 11:05:36 +1100742 return manifest_file
Tarek Ziadé3efd7672009-12-21 23:31:55 +0000743 finally:
744 manifest_f.close()
745 except IOError:
746 pass
Christian Heimes3305c522007-12-03 13:47:29 +0000747
748 # -- Miscellaneous methods -----------------------------------------
749 # These are all used by the 'gen_lib_options() function, in
750 # ccompiler.py.
751
752 def library_dir_option(self, dir):
753 return "/LIBPATH:" + dir
754
755 def runtime_library_dir_option(self, dir):
756 raise DistutilsPlatformError(
757 "don't know how to set runtime library search path for MSVC++")
758
759 def library_option(self, lib):
760 return self.library_filename(lib)
761
762
763 def find_library_file(self, dirs, lib, debug=0):
764 # Prefer a debugging library if found (and requested), but deal
765 # with it if we don't have one.
766 if debug:
767 try_names = [lib + "_d", lib]
768 else:
769 try_names = [lib]
770 for dir in dirs:
771 for name in try_names:
772 libfile = os.path.join(dir, self.library_filename (name))
773 if os.path.exists(libfile):
774 return libfile
775 else:
776 # Oops, didn't find it in *any* of 'dirs'
777 return None
778
779 # Helper methods for using the MSVC registry settings
780
781 def find_exe(self, exe):
782 """Return path to an MSVC executable program.
783
784 Tries to find the program in several places: first, one of the
785 MSVC program search paths from the registry; next, the directories
786 in the PATH environment variable. If any of those work, return an
787 absolute path that is known to exist. If none of them work, just
788 return the original program name, 'exe'.
789 """
790 for p in self.__paths:
791 fn = os.path.join(os.path.abspath(p), exe)
792 if os.path.isfile(fn):
793 return fn
794
795 # didn't find it; try existing path
796 for p in os.environ['Path'].split(';'):
797 fn = os.path.join(os.path.abspath(p),exe)
798 if os.path.isfile(fn):
799 return fn
800
801 return exe