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