blob: da4b21d22a9aaa7516dd0df3997a0c063253fad5 [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
Christian Heimescbf3b5c2007-12-03 21:02:03 +000015import os
16import subprocess
17import sys
Martin v. Löwis1679ea82009-12-03 20:57:49 +000018import re
Tarek Ziadé63b64c02009-03-07 00:51:53 +000019
Tarek Ziadé36797272010-07-22 12:50:05 +000020from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
21 CompileError, LibError, LinkError
22from distutils.ccompiler import CCompiler, gen_preprocess_options, \
23 gen_lib_options
Christian Heimescbf3b5c2007-12-03 21:02:03 +000024from distutils import log
Tarek Ziadé8b441d02010-01-29 11:46:31 +000025from distutils.util import get_platform
Christian Heimescbf3b5c2007-12-03 21:02:03 +000026
Tarek Ziadé8b441d02010-01-29 11:46:31 +000027import winreg
Tarek Ziadéedacea32010-01-29 11:41:03 +000028
Georg Brandl38feaf02008-05-25 07:45:51 +000029RegOpenKeyEx = winreg.OpenKeyEx
30RegEnumKey = winreg.EnumKey
31RegEnumValue = winreg.EnumValue
32RegError = winreg.error
Christian Heimescbf3b5c2007-12-03 21:02:03 +000033
Georg Brandl38feaf02008-05-25 07:45:51 +000034HKEYS = (winreg.HKEY_USERS,
35 winreg.HKEY_CURRENT_USER,
36 winreg.HKEY_LOCAL_MACHINE,
37 winreg.HKEY_CLASSES_ROOT)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000038
Benjamin Peterson31b16a52010-06-21 15:37:16 +000039NATIVE_WIN64 = (sys.platform == 'win32' and sys.maxsize > 2**32)
40if NATIVE_WIN64:
41 # Visual C++ is a 32-bit application, so we need to look in
42 # the corresponding registry branch, if we're running a
43 # 64-bit Python on Win64
44 VS_BASE = r"Software\Wow6432Node\Microsoft\VisualStudio\%0.1f"
45 WINSDK_BASE = r"Software\Wow6432Node\Microsoft\Microsoft SDKs\Windows"
46 NET_BASE = r"Software\Wow6432Node\Microsoft\.NETFramework"
47else:
48 VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
49 WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
50 NET_BASE = r"Software\Microsoft\.NETFramework"
Christian Heimescbf3b5c2007-12-03 21:02:03 +000051
Christian Heimes5e696852008-04-09 08:37:03 +000052# A map keyed by get_platform() return values to values accepted by
53# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
54# the param to cross-compile on x86 targetting amd64.)
55PLAT_TO_VCVARS = {
56 'win32' : 'x86',
57 'win-amd64' : 'amd64',
58 'win-ia64' : 'ia64',
59}
Christian Heimescbf3b5c2007-12-03 21:02:03 +000060
61class Reg:
62 """Helper class to read values from the registry
63 """
64
Christian Heimescbf3b5c2007-12-03 21:02:03 +000065 def get_value(cls, path, key):
66 for base in HKEYS:
67 d = cls.read_values(base, path)
68 if d and key in d:
69 return d[key]
70 raise KeyError(key)
Tarek Ziadé63b64c02009-03-07 00:51:53 +000071 get_value = classmethod(get_value)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000072
Christian Heimescbf3b5c2007-12-03 21:02:03 +000073 def read_keys(cls, base, key):
74 """Return list of registry keys."""
75 try:
76 handle = RegOpenKeyEx(base, key)
77 except RegError:
78 return None
79 L = []
80 i = 0
81 while True:
82 try:
83 k = RegEnumKey(handle, i)
84 except RegError:
85 break
86 L.append(k)
87 i += 1
88 return L
Tarek Ziadé63b64c02009-03-07 00:51:53 +000089 read_keys = classmethod(read_keys)
Christian Heimescbf3b5c2007-12-03 21:02:03 +000090
Christian Heimescbf3b5c2007-12-03 21:02:03 +000091 def read_values(cls, base, key):
92 """Return dict of registry keys and values.
93
94 All names are converted to lowercase.
95 """
96 try:
97 handle = RegOpenKeyEx(base, key)
98 except RegError:
99 return None
100 d = {}
101 i = 0
102 while True:
103 try:
104 name, value, type = RegEnumValue(handle, i)
105 except RegError:
106 break
107 name = name.lower()
108 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
109 i += 1
110 return d
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000111 read_values = classmethod(read_values)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000112
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000113 def convert_mbcs(s):
114 dec = getattr(s, "decode", None)
115 if dec is not None:
116 try:
117 s = dec("mbcs")
118 except UnicodeError:
119 pass
120 return s
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000121 convert_mbcs = staticmethod(convert_mbcs)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000122
123class MacroExpander:
124
125 def __init__(self, version):
126 self.macros = {}
127 self.vsbase = VS_BASE % version
128 self.load_macros(version)
129
130 def set_macro(self, macro, path, key):
131 self.macros["$(%s)" % macro] = Reg.get_value(path, key)
132
133 def load_macros(self, version):
134 self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
135 self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
136 self.set_macro("FrameworkDir", NET_BASE, "installroot")
137 try:
138 if version >= 8.0:
139 self.set_macro("FrameworkSDKDir", NET_BASE,
140 "sdkinstallrootv2.0")
141 else:
142 raise KeyError("sdkinstallrootv2.0")
Tarek Ziadé63b64c02009-03-07 00:51:53 +0000143 except KeyError:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000144 raise DistutilsPlatformError(
145 """Python was built with Visual Studio 2008;
146extensions must be built with a compiler than can generate compatible binaries.
147Visual Studio 2008 was not found on this system. If you have Cygwin installed,
148you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
149
150 if version >= 9.0:
151 self.set_macro("FrameworkVersion", self.vsbase, "clr version")
152 self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
153 else:
154 p = r"Software\Microsoft\NET Framework Setup\Product"
155 for base in HKEYS:
156 try:
157 h = RegOpenKeyEx(base, p)
158 except RegError:
159 continue
160 key = RegEnumKey(h, 0)
161 d = Reg.get_value(base, r"%s\%s" % (p, key))
162 self.macros["$(FrameworkVersion)"] = d["version"]
163
164 def sub(self, s):
165 for k, v in self.macros.items():
166 s = s.replace(k, v)
167 return s
168
169def get_build_version():
170 """Return the version of MSVC that was used to build Python.
171
172 For Python 2.3 and up, the version number is included in
173 sys.version. For earlier versions, assume the compiler is MSVC 6.
174 """
175 prefix = "MSC v."
176 i = sys.version.find(prefix)
177 if i == -1:
178 return 6
179 i = i + len(prefix)
180 s, rest = sys.version[i:].split(" ", 1)
181 majorVersion = int(s[:-2]) - 6
Steve Dower65e4cb12014-11-22 12:54:57 -0800182 if majorVersion >= 13:
183 # v13 was skipped and should be v14
184 majorVersion += 1
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000185 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 Heimescbf3b5c2007-12-03 21:02:03 +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'Arcd8976f12008-09-02 23:22: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 Heimescbf3b5c2007-12-03 21:02:03 +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:
230 log.debug("Unable to find productdir in registry")
231 productdir = None
232
233 if not productdir or not os.path.isdir(productdir):
234 toolskey = "VS%0.f0COMNTOOLS" % version
235 toolsdir = os.environ.get(toolskey, None)
236
237 if toolsdir and os.path.isdir(toolsdir):
238 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
239 productdir = os.path.abspath(productdir)
240 if not os.path.isdir(productdir):
241 log.debug("%s is not a valid directory" % productdir)
242 return None
243 else:
244 log.debug("Env var %s is not set or invalid" % toolskey)
245 if not productdir:
246 log.debug("No productdir found")
247 return None
248 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
249 if os.path.isfile(vcvarsall):
250 return vcvarsall
251 log.debug("Unable to find vcvarsall.bat")
252 return None
253
254def query_vcvarsall(version, arch="x86"):
255 """Launch vcvarsall.bat and read the settings from its environment
256 """
257 vcvarsall = find_vcvarsall(version)
258 interesting = set(("include", "lib", "libpath", "path"))
259 result = {}
260
261 if vcvarsall is None:
Tarek Ziadé9df8ce32008-12-30 23:09:20 +0000262 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Christian Heimes5e696852008-04-09 08:37:03 +0000263 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000264 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
265 stdout=subprocess.PIPE,
266 stderr=subprocess.PIPE)
Éric Araujo5ac6d802010-11-06 02:10:32 +0000267 try:
268 stdout, stderr = popen.communicate()
269 if popen.wait() != 0:
270 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimesb9eccbf2007-12-05 20:18:38 +0000271
Éric Araujo8bdbe9c2010-11-06 15:57:52 +0000272 stdout = stdout.decode("mbcs")
273 for line in stdout.split("\n"):
274 line = Reg.convert_mbcs(line)
275 if '=' not in line:
276 continue
277 line = line.strip()
278 key, value = line.split('=', 1)
279 key = key.lower()
280 if key in interesting:
281 if value.endswith(os.pathsep):
282 value = value[:-1]
283 result[key] = removeDuplicates(value)
284
285 finally:
Éric Araujo8bdbe9c2010-11-06 15:57:52 +0000286 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:
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000345 plat_name = get_platform()
Christian Heimes5e696852008-04-09 08:37:03 +0000346 # 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.
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000366 if plat_name == get_platform() or plat_name == 'win32':
Christian Heimes5e696852008-04-09 08:37:03 +0000367 # native build or cross-compile to win32
368 plat_spec = PLAT_TO_VCVARS[plat_name]
369 else:
370 # cross compile from win32 -> some 64bit
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000371 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
Christian Heimes5e696852008-04-09 08:37:03 +0000372 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 = [
Steve Dower3a7ffa72015-08-07 19:48:03 -0700419 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000420 ]
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
Mark Hammond6c58b282011-10-17 11:05:57 +1100633 self.manifest_setup_ldargs(output_filename, build_temp, ld_args)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000634
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000635 if extra_preargs:
636 ld_args[:0] = extra_preargs
637 if extra_postargs:
638 ld_args.extend(extra_postargs)
639
640 self.mkpath(os.path.dirname(output_filename))
641 try:
642 self.spawn([self.linker] + ld_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000643 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000644 raise LinkError(msg)
645
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000646 # embed the manifest
647 # XXX - this is somewhat fragile - if mt.exe fails, distutils
648 # will still consider the DLL up-to-date, but it will not have a
649 # manifest. Maybe we should link to a temp file? OTOH, that
650 # implies a build environment error that shouldn't go undetected.
Mark Hammond6c58b282011-10-17 11:05:57 +1100651 mfinfo = self.manifest_get_embed_info(target_desc, ld_args)
652 if mfinfo is not None:
653 mffilename, mfid = mfinfo
654 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
655 try:
656 self.spawn(['mt.exe', '-nologo', '-manifest',
657 mffilename, out_arg])
658 except DistutilsExecError as msg:
659 raise LinkError(msg)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000660 else:
661 log.debug("skipping %s (up-to-date)", output_filename)
662
Mark Hammond6c58b282011-10-17 11:05:57 +1100663 def manifest_setup_ldargs(self, output_filename, build_temp, ld_args):
664 # If we need a manifest at all, an embedded manifest is recommended.
665 # See MSDN article titled
666 # "How to: Embed a Manifest Inside a C/C++ Application"
667 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
668 # Ask the linker to generate the manifest in the temp dir, so
669 # we can check it, and possibly embed it, later.
670 temp_manifest = os.path.join(
671 build_temp,
672 os.path.basename(output_filename) + ".manifest")
673 ld_args.append('/MANIFESTFILE:' + temp_manifest)
674
675 def manifest_get_embed_info(self, target_desc, ld_args):
676 # If a manifest should be embedded, return a tuple of
677 # (manifest_filename, resource_id). Returns None if no manifest
678 # should be embedded. See http://bugs.python.org/issue7833 for why
679 # we want to avoid any manifest for extension modules if we can)
680 for arg in ld_args:
681 if arg.startswith("/MANIFESTFILE:"):
682 temp_manifest = arg.split(":", 1)[1]
683 break
684 else:
685 # no /MANIFESTFILE so nothing to do.
686 return None
687 if target_desc == CCompiler.EXECUTABLE:
688 # by default, executables always get the manifest with the
689 # CRT referenced.
690 mfid = 1
691 else:
692 # Extension modules try and avoid any manifest if possible.
693 mfid = 2
694 temp_manifest = self._remove_visual_c_ref(temp_manifest)
695 if temp_manifest is None:
696 return None
697 return temp_manifest, mfid
698
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000699 def _remove_visual_c_ref(self, manifest_file):
700 try:
701 # Remove references to the Visual C runtime, so they will
702 # fall through to the Visual C dependency of Python.exe.
703 # This way, when installed for a restricted user (e.g.
704 # runtimes are not in WinSxS folder, but in Python's own
705 # folder), the runtimes do not need to be in every folder
706 # with .pyd's.
Mark Hammond6c58b282011-10-17 11:05:57 +1100707 # Returns either the filename of the modified manifest or
708 # None if no manifest should be embedded.
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000709 manifest_f = open(manifest_file)
710 try:
711 manifest_buf = manifest_f.read()
712 finally:
713 manifest_f.close()
714 pattern = re.compile(
715 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
716 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
717 re.DOTALL)
718 manifest_buf = re.sub(pattern, "", manifest_buf)
719 pattern = "<dependentAssembly>\s*</dependentAssembly>"
720 manifest_buf = re.sub(pattern, "", manifest_buf)
Mark Hammond53e4a9a2011-10-17 11:35:31 +1100721 # Now see if any other assemblies are referenced - if not, we
Mark Hammond6c58b282011-10-17 11:05:57 +1100722 # don't want a manifest embedded.
723 pattern = re.compile(
724 r"""<assemblyIdentity.*?name=(?:"|')(.+?)(?:"|')"""
725 r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL)
726 if re.search(pattern, manifest_buf) is None:
727 return None
728
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000729 manifest_f = open(manifest_file, 'w')
730 try:
731 manifest_f.write(manifest_buf)
Mark Hammond6c58b282011-10-17 11:05:57 +1100732 return manifest_file
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000733 finally:
734 manifest_f.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200735 except OSError:
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000736 pass
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000737
738 # -- Miscellaneous methods -----------------------------------------
739 # These are all used by the 'gen_lib_options() function, in
740 # ccompiler.py.
741
742 def library_dir_option(self, dir):
743 return "/LIBPATH:" + dir
744
745 def runtime_library_dir_option(self, dir):
746 raise DistutilsPlatformError(
747 "don't know how to set runtime library search path for MSVC++")
748
749 def library_option(self, lib):
750 return self.library_filename(lib)
751
752
753 def find_library_file(self, dirs, lib, debug=0):
754 # Prefer a debugging library if found (and requested), but deal
755 # with it if we don't have one.
756 if debug:
757 try_names = [lib + "_d", lib]
758 else:
759 try_names = [lib]
760 for dir in dirs:
761 for name in try_names:
762 libfile = os.path.join(dir, self.library_filename (name))
763 if os.path.exists(libfile):
764 return libfile
765 else:
766 # Oops, didn't find it in *any* of 'dirs'
767 return None
768
769 # Helper methods for using the MSVC registry settings
770
771 def find_exe(self, exe):
772 """Return path to an MSVC executable program.
773
774 Tries to find the program in several places: first, one of the
775 MSVC program search paths from the registry; next, the directories
776 in the PATH environment variable. If any of those work, return an
777 absolute path that is known to exist. If none of them work, just
778 return the original program name, 'exe'.
779 """
780 for p in self.__paths:
781 fn = os.path.join(os.path.abspath(p), exe)
782 if os.path.isfile(fn):
783 return fn
784
785 # didn't find it; try existing path
786 for p in os.environ['Path'].split(';'):
787 fn = os.path.join(os.path.abspath(p),exe)
788 if os.path.isfile(fn):
789 return fn
790
791 return exe