blob: 9688f20019c828926e525276900cd27dc65d7575 [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
182 minorVersion = int(s[2:3]) / 10.0
183 # I don't think paths are affected by minor version in version 6
184 if majorVersion == 6:
185 minorVersion = 0
186 if majorVersion >= 6:
187 return majorVersion + minorVersion
188 # else we don't know what version of the compiler this is
189 return None
190
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000191def normalize_and_reduce_paths(paths):
192 """Return a list of normalized paths with duplicates removed.
193
194 The current order of paths is maintained.
195 """
196 # Paths are normalized so things like: /a and /a/ aren't both preserved.
197 reduced_paths = []
198 for p in paths:
199 np = os.path.normpath(p)
200 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
201 if np not in reduced_paths:
202 reduced_paths.append(np)
203 return reduced_paths
204
Amaury Forgeot d'Arcd8976f12008-09-02 23:22:56 +0000205def removeDuplicates(variable):
206 """Remove duplicate values of an environment variable.
207 """
208 oldList = variable.split(os.pathsep)
209 newList = []
210 for i in oldList:
211 if i not in newList:
212 newList.append(i)
213 newVariable = os.pathsep.join(newList)
214 return newVariable
215
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000216def find_vcvarsall(version):
217 """Find the vcvarsall.bat file
218
219 At first it tries to find the productdir of VS 2008 in the registry. If
220 that fails it falls back to the VS90COMNTOOLS env var.
221 """
222 vsbase = VS_BASE % version
223 try:
224 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
225 "productdir")
226 except KeyError:
227 log.debug("Unable to find productdir in registry")
228 productdir = None
229
230 if not productdir or not os.path.isdir(productdir):
231 toolskey = "VS%0.f0COMNTOOLS" % version
232 toolsdir = os.environ.get(toolskey, None)
233
234 if toolsdir and os.path.isdir(toolsdir):
235 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
236 productdir = os.path.abspath(productdir)
237 if not os.path.isdir(productdir):
238 log.debug("%s is not a valid directory" % productdir)
239 return None
240 else:
241 log.debug("Env var %s is not set or invalid" % toolskey)
242 if not productdir:
243 log.debug("No productdir found")
244 return None
245 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
246 if os.path.isfile(vcvarsall):
247 return vcvarsall
248 log.debug("Unable to find vcvarsall.bat")
249 return None
250
251def query_vcvarsall(version, arch="x86"):
252 """Launch vcvarsall.bat and read the settings from its environment
253 """
254 vcvarsall = find_vcvarsall(version)
255 interesting = set(("include", "lib", "libpath", "path"))
256 result = {}
257
258 if vcvarsall is None:
Tarek Ziadé9df8ce32008-12-30 23:09:20 +0000259 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Christian Heimes5e696852008-04-09 08:37:03 +0000260 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000261 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
262 stdout=subprocess.PIPE,
263 stderr=subprocess.PIPE)
Éric Araujo5ac6d802010-11-06 02:10:32 +0000264 try:
265 stdout, stderr = popen.communicate()
266 if popen.wait() != 0:
267 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimesb9eccbf2007-12-05 20:18:38 +0000268
Éric Araujo8bdbe9c2010-11-06 15:57:52 +0000269 stdout = stdout.decode("mbcs")
270 for line in stdout.split("\n"):
271 line = Reg.convert_mbcs(line)
272 if '=' not in line:
273 continue
274 line = line.strip()
275 key, value = line.split('=', 1)
276 key = key.lower()
277 if key in interesting:
278 if value.endswith(os.pathsep):
279 value = value[:-1]
280 result[key] = removeDuplicates(value)
281
282 finally:
Éric Araujo8bdbe9c2010-11-06 15:57:52 +0000283 popen.stdout.close()
284 popen.stderr.close()
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000285
286 if len(result) != len(interesting):
287 raise ValueError(str(list(result.keys())))
288
289 return result
290
291# More globals
292VERSION = get_build_version()
293if VERSION < 8.0:
294 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000295# MACROS = MacroExpander(VERSION)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000296
297class MSVCCompiler(CCompiler) :
298 """Concrete class that implements an interface to Microsoft Visual C++,
299 as defined by the CCompiler abstract class."""
300
301 compiler_type = 'msvc'
302
303 # Just set this so CCompiler's constructor doesn't barf. We currently
304 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
305 # as it really isn't necessary for this sort of single-compiler class.
306 # Would be nice to have a consistent interface with UnixCCompiler,
307 # though, so it's worth thinking about.
308 executables = {}
309
310 # Private class data (need to distinguish C from C++ source for compiler)
311 _c_extensions = ['.c']
312 _cpp_extensions = ['.cc', '.cpp', '.cxx']
313 _rc_extensions = ['.rc']
314 _mc_extensions = ['.mc']
315
316 # Needed for the filename generation methods provided by the
317 # base class, CCompiler.
318 src_extensions = (_c_extensions + _cpp_extensions +
319 _rc_extensions + _mc_extensions)
320 res_extension = '.res'
321 obj_extension = '.obj'
322 static_lib_extension = '.lib'
323 shared_lib_extension = '.dll'
324 static_lib_format = shared_lib_format = '%s%s'
325 exe_extension = '.exe'
326
327 def __init__(self, verbose=0, dry_run=0, force=0):
328 CCompiler.__init__ (self, verbose, dry_run, force)
329 self.__version = VERSION
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000330 self.__root = r"Software\Microsoft\VisualStudio"
331 # self.__macros = MACROS
Christian Heimes94e07722008-11-28 11:05:17 +0000332 self.__paths = []
Christian Heimes5e696852008-04-09 08:37:03 +0000333 # target platform (.plat_name is consistent with 'bdist')
334 self.plat_name = None
335 self.__arch = None # deprecated name
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000336 self.initialized = False
337
Christian Heimes5e696852008-04-09 08:37:03 +0000338 def initialize(self, plat_name=None):
339 # multi-init means we would need to check platform same each time...
340 assert not self.initialized, "don't init multiple times"
341 if plat_name is None:
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000342 plat_name = get_platform()
Christian Heimes5e696852008-04-09 08:37:03 +0000343 # sanity check for platforms to prevent obscure errors later.
344 ok_plats = 'win32', 'win-amd64', 'win-ia64'
345 if plat_name not in ok_plats:
346 raise DistutilsPlatformError("--plat-name must be one of %s" %
347 (ok_plats,))
348
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000349 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
350 # Assume that the SDK set up everything alright; don't try to be
351 # smarter
352 self.cc = "cl.exe"
353 self.linker = "link.exe"
354 self.lib = "lib.exe"
355 self.rc = "rc.exe"
356 self.mc = "mc.exe"
357 else:
Christian Heimes5e696852008-04-09 08:37:03 +0000358 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
359 # to cross compile, you use 'x86_amd64'.
360 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
361 # compile use 'x86' (ie, it runs the x86 compiler directly)
362 # No idea how itanium handles this, if at all.
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000363 if plat_name == get_platform() or plat_name == 'win32':
Christian Heimes5e696852008-04-09 08:37:03 +0000364 # native build or cross-compile to win32
365 plat_spec = PLAT_TO_VCVARS[plat_name]
366 else:
367 # cross compile from win32 -> some 64bit
Tarek Ziadé8b441d02010-01-29 11:46:31 +0000368 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
Christian Heimes5e696852008-04-09 08:37:03 +0000369 PLAT_TO_VCVARS[plat_name]
370
371 vc_env = query_vcvarsall(VERSION, plat_spec)
372
373 self.__paths = vc_env['path'].split(os.pathsep)
374 os.environ['lib'] = vc_env['lib']
375 os.environ['include'] = vc_env['include']
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000376
377 if len(self.__paths) == 0:
378 raise DistutilsPlatformError("Python was built with %s, "
379 "and extensions need to be built with the same "
380 "version of the compiler, but it isn't installed."
381 % self.__product)
382
383 self.cc = self.find_exe("cl.exe")
384 self.linker = self.find_exe("link.exe")
385 self.lib = self.find_exe("lib.exe")
386 self.rc = self.find_exe("rc.exe") # resource compiler
387 self.mc = self.find_exe("mc.exe") # message compiler
388 #self.set_path_env_var('lib')
389 #self.set_path_env_var('include')
390
391 # extend the MSVC path with the current path
392 try:
393 for p in os.environ['path'].split(';'):
394 self.__paths.append(p)
395 except KeyError:
396 pass
397 self.__paths = normalize_and_reduce_paths(self.__paths)
398 os.environ['path'] = ";".join(self.__paths)
399
400 self.preprocess_options = None
401 if self.__arch == "x86":
402 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
403 '/DNDEBUG']
404 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
405 '/Z7', '/D_DEBUG']
406 else:
407 # Win64
408 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
409 '/DNDEBUG']
410 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
411 '/Z7', '/D_DEBUG']
412
413 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
414 if self.__version >= 7:
415 self.ldflags_shared_debug = [
416 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
417 ]
418 self.ldflags_static = [ '/nologo']
419
420 self.initialized = True
421
422 # -- Worker methods ------------------------------------------------
423
424 def object_filenames(self,
425 source_filenames,
426 strip_dir=0,
427 output_dir=''):
428 # Copied from ccompiler.py, extended to return .res as 'object'-file
429 # for .rc input file
430 if output_dir is None: output_dir = ''
431 obj_names = []
432 for src_name in source_filenames:
433 (base, ext) = os.path.splitext (src_name)
434 base = os.path.splitdrive(base)[1] # Chop off the drive
435 base = base[os.path.isabs(base):] # If abs, chop off leading /
436 if ext not in self.src_extensions:
437 # Better to raise an exception instead of silently continuing
438 # and later complain about sources and targets having
439 # different lengths
440 raise CompileError ("Don't know how to compile %s" % src_name)
441 if strip_dir:
442 base = os.path.basename (base)
443 if ext in self._rc_extensions:
444 obj_names.append (os.path.join (output_dir,
445 base + self.res_extension))
446 elif ext in self._mc_extensions:
447 obj_names.append (os.path.join (output_dir,
448 base + self.res_extension))
449 else:
450 obj_names.append (os.path.join (output_dir,
451 base + self.obj_extension))
452 return obj_names
453
454
455 def compile(self, sources,
456 output_dir=None, macros=None, include_dirs=None, debug=0,
457 extra_preargs=None, extra_postargs=None, depends=None):
458
459 if not self.initialized:
460 self.initialize()
461 compile_info = self._setup_compile(output_dir, macros, include_dirs,
462 sources, depends, extra_postargs)
463 macros, objects, extra_postargs, pp_opts, build = compile_info
464
465 compile_opts = extra_preargs or []
466 compile_opts.append ('/c')
467 if debug:
468 compile_opts.extend(self.compile_options_debug)
469 else:
470 compile_opts.extend(self.compile_options)
471
472 for obj in objects:
473 try:
474 src, ext = build[obj]
475 except KeyError:
476 continue
477 if debug:
478 # pass the full pathname to MSVC in debug mode,
479 # this allows the debugger to find the source file
480 # without asking the user to browse for it
481 src = os.path.abspath(src)
482
483 if ext in self._c_extensions:
484 input_opt = "/Tc" + src
485 elif ext in self._cpp_extensions:
486 input_opt = "/Tp" + src
487 elif ext in self._rc_extensions:
488 # compile .RC to .RES file
489 input_opt = src
490 output_opt = "/fo" + obj
491 try:
492 self.spawn([self.rc] + pp_opts +
493 [output_opt] + [input_opt])
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000494 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000495 raise CompileError(msg)
496 continue
497 elif ext in self._mc_extensions:
498 # Compile .MC to .RC file to .RES file.
499 # * '-h dir' specifies the directory for the
500 # generated include file
501 # * '-r dir' specifies the target directory of the
502 # generated RC file and the binary message resource
503 # it includes
504 #
505 # For now (since there are no options to change this),
506 # we use the source-directory for the include file and
507 # the build directory for the RC file and message
508 # resources. This works at least for win32all.
509 h_dir = os.path.dirname(src)
510 rc_dir = os.path.dirname(obj)
511 try:
512 # first compile .MC to .RC and .H file
513 self.spawn([self.mc] +
514 ['-h', h_dir, '-r', rc_dir] + [src])
515 base, _ = os.path.splitext (os.path.basename (src))
516 rc_file = os.path.join (rc_dir, base + '.rc')
517 # then compile .RC to .RES file
518 self.spawn([self.rc] +
519 ["/fo" + obj] + [rc_file])
520
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000521 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000522 raise CompileError(msg)
523 continue
524 else:
525 # how to handle this file?
526 raise CompileError("Don't know how to compile %s to %s"
527 % (src, obj))
528
529 output_opt = "/Fo" + obj
530 try:
531 self.spawn([self.cc] + compile_opts + pp_opts +
532 [input_opt, output_opt] +
533 extra_postargs)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000534 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000535 raise CompileError(msg)
536
537 return objects
538
539
540 def create_static_lib(self,
541 objects,
542 output_libname,
543 output_dir=None,
544 debug=0,
545 target_lang=None):
546
547 if not self.initialized:
548 self.initialize()
549 (objects, output_dir) = self._fix_object_args(objects, output_dir)
550 output_filename = self.library_filename(output_libname,
551 output_dir=output_dir)
552
553 if self._need_link(objects, output_filename):
554 lib_args = objects + ['/OUT:' + output_filename]
555 if debug:
556 pass # XXX what goes here?
557 try:
558 self.spawn([self.lib] + lib_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000559 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000560 raise LibError(msg)
561 else:
562 log.debug("skipping %s (up-to-date)", output_filename)
563
564
565 def link(self,
566 target_desc,
567 objects,
568 output_filename,
569 output_dir=None,
570 libraries=None,
571 library_dirs=None,
572 runtime_library_dirs=None,
573 export_symbols=None,
574 debug=0,
575 extra_preargs=None,
576 extra_postargs=None,
577 build_temp=None,
578 target_lang=None):
579
580 if not self.initialized:
581 self.initialize()
582 (objects, output_dir) = self._fix_object_args(objects, output_dir)
583 fixed_args = self._fix_lib_args(libraries, library_dirs,
584 runtime_library_dirs)
585 (libraries, library_dirs, runtime_library_dirs) = fixed_args
586
587 if runtime_library_dirs:
588 self.warn ("I don't know what to do with 'runtime_library_dirs': "
589 + str (runtime_library_dirs))
590
591 lib_opts = gen_lib_options(self,
592 library_dirs, runtime_library_dirs,
593 libraries)
594 if output_dir is not None:
595 output_filename = os.path.join(output_dir, output_filename)
596
597 if self._need_link(objects, output_filename):
598 if target_desc == CCompiler.EXECUTABLE:
599 if debug:
600 ldflags = self.ldflags_shared_debug[1:]
601 else:
602 ldflags = self.ldflags_shared[1:]
603 else:
604 if debug:
605 ldflags = self.ldflags_shared_debug
606 else:
607 ldflags = self.ldflags_shared
608
609 export_opts = []
610 for sym in (export_symbols or []):
611 export_opts.append("/EXPORT:" + sym)
612
613 ld_args = (ldflags + lib_opts + export_opts +
614 objects + ['/OUT:' + output_filename])
615
616 # The MSVC linker generates .lib and .exp files, which cannot be
617 # suppressed by any linker switches. The .lib files may even be
618 # needed! Make sure they are generated in the temporary build
619 # directory. Since they have different names for debug and release
620 # builds, they can go into the same directory.
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000621 build_temp = os.path.dirname(objects[0])
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000622 if export_symbols is not None:
623 (dll_name, dll_ext) = os.path.splitext(
624 os.path.basename(output_filename))
625 implib_file = os.path.join(
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000626 build_temp,
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000627 self.library_filename(dll_name))
628 ld_args.append ('/IMPLIB:' + implib_file)
629
Mark Hammond6c58b282011-10-17 11:05:57 +1100630 self.manifest_setup_ldargs(output_filename, build_temp, ld_args)
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000631
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000632 if extra_preargs:
633 ld_args[:0] = extra_preargs
634 if extra_postargs:
635 ld_args.extend(extra_postargs)
636
637 self.mkpath(os.path.dirname(output_filename))
638 try:
639 self.spawn([self.linker] + ld_args)
Tarek Ziadéb3c6ed52009-03-07 01:12:09 +0000640 except DistutilsExecError as msg:
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000641 raise LinkError(msg)
642
Christian Heimes81ee3ef2008-05-04 22:42:01 +0000643 # embed the manifest
644 # XXX - this is somewhat fragile - if mt.exe fails, distutils
645 # will still consider the DLL up-to-date, but it will not have a
646 # manifest. Maybe we should link to a temp file? OTOH, that
647 # implies a build environment error that shouldn't go undetected.
Mark Hammond6c58b282011-10-17 11:05:57 +1100648 mfinfo = self.manifest_get_embed_info(target_desc, ld_args)
649 if mfinfo is not None:
650 mffilename, mfid = mfinfo
651 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
652 try:
653 self.spawn(['mt.exe', '-nologo', '-manifest',
654 mffilename, out_arg])
655 except DistutilsExecError as msg:
656 raise LinkError(msg)
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000657 else:
658 log.debug("skipping %s (up-to-date)", output_filename)
659
Mark Hammond6c58b282011-10-17 11:05:57 +1100660 def manifest_setup_ldargs(self, output_filename, build_temp, ld_args):
661 # If we need a manifest at all, an embedded manifest is recommended.
662 # See MSDN article titled
663 # "How to: Embed a Manifest Inside a C/C++ Application"
664 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
665 # Ask the linker to generate the manifest in the temp dir, so
666 # we can check it, and possibly embed it, later.
667 temp_manifest = os.path.join(
668 build_temp,
669 os.path.basename(output_filename) + ".manifest")
670 ld_args.append('/MANIFESTFILE:' + temp_manifest)
671
672 def manifest_get_embed_info(self, target_desc, ld_args):
673 # If a manifest should be embedded, return a tuple of
674 # (manifest_filename, resource_id). Returns None if no manifest
675 # should be embedded. See http://bugs.python.org/issue7833 for why
676 # we want to avoid any manifest for extension modules if we can)
677 for arg in ld_args:
678 if arg.startswith("/MANIFESTFILE:"):
679 temp_manifest = arg.split(":", 1)[1]
680 break
681 else:
682 # no /MANIFESTFILE so nothing to do.
683 return None
684 if target_desc == CCompiler.EXECUTABLE:
685 # by default, executables always get the manifest with the
686 # CRT referenced.
687 mfid = 1
688 else:
689 # Extension modules try and avoid any manifest if possible.
690 mfid = 2
691 temp_manifest = self._remove_visual_c_ref(temp_manifest)
692 if temp_manifest is None:
693 return None
694 return temp_manifest, mfid
695
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000696 def _remove_visual_c_ref(self, manifest_file):
697 try:
698 # Remove references to the Visual C runtime, so they will
699 # fall through to the Visual C dependency of Python.exe.
700 # This way, when installed for a restricted user (e.g.
701 # runtimes are not in WinSxS folder, but in Python's own
702 # folder), the runtimes do not need to be in every folder
703 # with .pyd's.
Mark Hammond6c58b282011-10-17 11:05:57 +1100704 # Returns either the filename of the modified manifest or
705 # None if no manifest should be embedded.
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000706 manifest_f = open(manifest_file)
707 try:
708 manifest_buf = manifest_f.read()
709 finally:
710 manifest_f.close()
711 pattern = re.compile(
712 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
713 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
714 re.DOTALL)
715 manifest_buf = re.sub(pattern, "", manifest_buf)
716 pattern = "<dependentAssembly>\s*</dependentAssembly>"
717 manifest_buf = re.sub(pattern, "", manifest_buf)
Mark Hammond53e4a9a2011-10-17 11:35:31 +1100718 # Now see if any other assemblies are referenced - if not, we
Mark Hammond6c58b282011-10-17 11:05:57 +1100719 # don't want a manifest embedded.
720 pattern = re.compile(
721 r"""<assemblyIdentity.*?name=(?:"|')(.+?)(?:"|')"""
722 r""".*?(?:/>|</assemblyIdentity>)""", re.DOTALL)
723 if re.search(pattern, manifest_buf) is None:
724 return None
725
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000726 manifest_f = open(manifest_file, 'w')
727 try:
728 manifest_f.write(manifest_buf)
Mark Hammond6c58b282011-10-17 11:05:57 +1100729 return manifest_file
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000730 finally:
731 manifest_f.close()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200732 except OSError:
Tarek Ziadéc60ea322009-12-21 23:12:41 +0000733 pass
Christian Heimescbf3b5c2007-12-03 21:02:03 +0000734
735 # -- Miscellaneous methods -----------------------------------------
736 # These are all used by the 'gen_lib_options() function, in
737 # ccompiler.py.
738
739 def library_dir_option(self, dir):
740 return "/LIBPATH:" + dir
741
742 def runtime_library_dir_option(self, dir):
743 raise DistutilsPlatformError(
744 "don't know how to set runtime library search path for MSVC++")
745
746 def library_option(self, lib):
747 return self.library_filename(lib)
748
749
750 def find_library_file(self, dirs, lib, debug=0):
751 # Prefer a debugging library if found (and requested), but deal
752 # with it if we don't have one.
753 if debug:
754 try_names = [lib + "_d", lib]
755 else:
756 try_names = [lib]
757 for dir in dirs:
758 for name in try_names:
759 libfile = os.path.join(dir, self.library_filename (name))
760 if os.path.exists(libfile):
761 return libfile
762 else:
763 # Oops, didn't find it in *any* of 'dirs'
764 return None
765
766 # Helper methods for using the MSVC registry settings
767
768 def find_exe(self, exe):
769 """Return path to an MSVC executable program.
770
771 Tries to find the program in several places: first, one of the
772 MSVC program search paths from the registry; next, the directories
773 in the PATH environment variable. If any of those work, return an
774 absolute path that is known to exist. If none of them work, just
775 return the original program name, 'exe'.
776 """
777 for p in self.__paths:
778 fn = os.path.join(os.path.abspath(p), exe)
779 if os.path.isfile(fn):
780 return fn
781
782 # didn't find it; try existing path
783 for p in os.environ['Path'].split(';'):
784 fn = os.path.join(os.path.abspath(p),exe)
785 if os.path.isfile(fn):
786 return fn
787
788 return exe