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