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