blob: 932b6ea2d9b6222cbf11a33ac3f2c69c58601a54 [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
40VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
Tarek Ziadéc49b6ef2010-03-06 02:17:28 +000041VSEXPRESS_BASE = r"Software\Microsoft\VCExpress\%0.1f"
Christian Heimes3305c522007-12-03 13:47:29 +000042WINSDK_BASE = r"Software\Microsoft\Microsoft SDKs\Windows"
43NET_BASE = r"Software\Microsoft\.NETFramework"
Christian Heimes3305c522007-12-03 13:47:29 +000044
Mark Hammond495cf992008-04-07 01:53:39 +000045# A map keyed by get_platform() return values to values accepted by
46# 'vcvarsall.bat'. Note a cross-compile may combine these (eg, 'x86_amd64' is
47# the param to cross-compile on x86 targetting amd64.)
48PLAT_TO_VCVARS = {
49 'win32' : 'x86',
50 'win-amd64' : 'amd64',
51 'win-ia64' : 'ia64',
52}
Christian Heimes3305c522007-12-03 13:47:29 +000053
54class Reg:
55 """Helper class to read values from the registry
56 """
57
Christian Heimes3305c522007-12-03 13:47:29 +000058 def get_value(cls, path, key):
59 for base in HKEYS:
60 d = cls.read_values(base, path)
61 if d and key in d:
62 return d[key]
63 raise KeyError(key)
Tarek Ziadé943b24e2009-03-07 00:32:45 +000064 get_value = classmethod(get_value)
Christian Heimes3305c522007-12-03 13:47:29 +000065
Christian Heimes3305c522007-12-03 13:47:29 +000066 def read_keys(cls, base, key):
67 """Return list of registry keys."""
68 try:
69 handle = RegOpenKeyEx(base, key)
70 except RegError:
71 return None
72 L = []
73 i = 0
74 while True:
75 try:
76 k = RegEnumKey(handle, i)
77 except RegError:
78 break
79 L.append(k)
80 i += 1
81 return L
Tarek Ziadé943b24e2009-03-07 00:32:45 +000082 read_keys = classmethod(read_keys)
Christian Heimes3305c522007-12-03 13:47:29 +000083
Christian Heimes3305c522007-12-03 13:47:29 +000084 def read_values(cls, base, key):
85 """Return dict of registry keys and values.
86
87 All names are converted to lowercase.
88 """
89 try:
90 handle = RegOpenKeyEx(base, key)
91 except RegError:
92 return None
93 d = {}
94 i = 0
95 while True:
96 try:
97 name, value, type = RegEnumValue(handle, i)
98 except RegError:
99 break
100 name = name.lower()
101 d[cls.convert_mbcs(name)] = cls.convert_mbcs(value)
102 i += 1
103 return d
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000104 read_values = classmethod(read_values)
Christian Heimes3305c522007-12-03 13:47:29 +0000105
Christian Heimes3305c522007-12-03 13:47:29 +0000106 def convert_mbcs(s):
107 dec = getattr(s, "decode", None)
108 if dec is not None:
109 try:
110 s = dec("mbcs")
111 except UnicodeError:
112 pass
113 return s
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000114 convert_mbcs = staticmethod(convert_mbcs)
Christian Heimes3305c522007-12-03 13:47:29 +0000115
116class MacroExpander:
117
118 def __init__(self, version):
119 self.macros = {}
120 self.vsbase = VS_BASE % version
121 self.load_macros(version)
122
123 def set_macro(self, macro, path, key):
124 self.macros["$(%s)" % macro] = Reg.get_value(path, key)
125
126 def load_macros(self, version):
127 self.set_macro("VCInstallDir", self.vsbase + r"\Setup\VC", "productdir")
128 self.set_macro("VSInstallDir", self.vsbase + r"\Setup\VS", "productdir")
129 self.set_macro("FrameworkDir", NET_BASE, "installroot")
130 try:
131 if version >= 8.0:
132 self.set_macro("FrameworkSDKDir", NET_BASE,
133 "sdkinstallrootv2.0")
134 else:
135 raise KeyError("sdkinstallrootv2.0")
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000136 except KeyError:
Christian Heimes3305c522007-12-03 13:47:29 +0000137 raise DistutilsPlatformError(
138 """Python was built with Visual Studio 2008;
139extensions must be built with a compiler than can generate compatible binaries.
140Visual Studio 2008 was not found on this system. If you have Cygwin installed,
141you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
142
143 if version >= 9.0:
144 self.set_macro("FrameworkVersion", self.vsbase, "clr version")
145 self.set_macro("WindowsSdkDir", WINSDK_BASE, "currentinstallfolder")
146 else:
147 p = r"Software\Microsoft\NET Framework Setup\Product"
148 for base in HKEYS:
149 try:
150 h = RegOpenKeyEx(base, p)
151 except RegError:
152 continue
153 key = RegEnumKey(h, 0)
154 d = Reg.get_value(base, r"%s\%s" % (p, key))
155 self.macros["$(FrameworkVersion)"] = d["version"]
156
157 def sub(self, s):
158 for k, v in self.macros.items():
159 s = s.replace(k, v)
160 return s
161
162def get_build_version():
163 """Return the version of MSVC that was used to build Python.
164
165 For Python 2.3 and up, the version number is included in
166 sys.version. For earlier versions, assume the compiler is MSVC 6.
167 """
168 prefix = "MSC v."
169 i = sys.version.find(prefix)
170 if i == -1:
171 return 6
172 i = i + len(prefix)
173 s, rest = sys.version[i:].split(" ", 1)
174 majorVersion = int(s[:-2]) - 6
175 minorVersion = int(s[2:3]) / 10.0
176 # I don't think paths are affected by minor version in version 6
177 if majorVersion == 6:
178 minorVersion = 0
179 if majorVersion >= 6:
180 return majorVersion + minorVersion
181 # else we don't know what version of the compiler this is
182 return None
183
Christian Heimes3305c522007-12-03 13:47:29 +0000184def normalize_and_reduce_paths(paths):
185 """Return a list of normalized paths with duplicates removed.
186
187 The current order of paths is maintained.
188 """
189 # Paths are normalized so things like: /a and /a/ aren't both preserved.
190 reduced_paths = []
191 for p in paths:
192 np = os.path.normpath(p)
193 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
194 if np not in reduced_paths:
195 reduced_paths.append(np)
196 return reduced_paths
197
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000198def removeDuplicates(variable):
199 """Remove duplicate values of an environment variable.
200 """
201 oldList = variable.split(os.pathsep)
202 newList = []
203 for i in oldList:
204 if i not in newList:
205 newList.append(i)
206 newVariable = os.pathsep.join(newList)
207 return newVariable
208
Christian Heimes3305c522007-12-03 13:47:29 +0000209def find_vcvarsall(version):
210 """Find the vcvarsall.bat file
211
212 At first it tries to find the productdir of VS 2008 in the registry. If
213 that fails it falls back to the VS90COMNTOOLS env var.
214 """
215 vsbase = VS_BASE % version
216 try:
217 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
218 "productdir")
219 except KeyError:
Christian Heimes3305c522007-12-03 13:47:29 +0000220 productdir = None
221
Tarek Ziadéc49b6ef2010-03-06 02:17:28 +0000222 # trying Express edition
223 if productdir is None:
224 vsbase = VSEXPRESS_BASE % version
225 try:
226 productdir = Reg.get_value(r"%s\Setup\VC" % vsbase,
227 "productdir")
228 except KeyError:
229 productdir = None
230 log.debug("Unable to find productdir in registry")
231
Christian Heimes3305c522007-12-03 13:47:29 +0000232 if not productdir or not os.path.isdir(productdir):
233 toolskey = "VS%0.f0COMNTOOLS" % version
234 toolsdir = os.environ.get(toolskey, None)
235
236 if toolsdir and os.path.isdir(toolsdir):
237 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
238 productdir = os.path.abspath(productdir)
239 if not os.path.isdir(productdir):
240 log.debug("%s is not a valid directory" % productdir)
241 return None
242 else:
243 log.debug("Env var %s is not set or invalid" % toolskey)
244 if not productdir:
245 log.debug("No productdir found")
246 return None
247 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
248 if os.path.isfile(vcvarsall):
249 return vcvarsall
250 log.debug("Unable to find vcvarsall.bat")
251 return None
252
253def query_vcvarsall(version, arch="x86"):
254 """Launch vcvarsall.bat and read the settings from its environment
255 """
256 vcvarsall = find_vcvarsall(version)
257 interesting = set(("include", "lib", "libpath", "path"))
258 result = {}
259
260 if vcvarsall is None:
Tarek Ziadéb1a85412008-12-30 23:03:41 +0000261 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Mark Hammond495cf992008-04-07 01:53:39 +0000262 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimes3305c522007-12-03 13:47:29 +0000263 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
264 stdout=subprocess.PIPE,
265 stderr=subprocess.PIPE)
Christian Heimes3305c522007-12-03 13:47:29 +0000266
Christian Heimescbdb7052007-12-05 20:10:38 +0000267 stdout, stderr = popen.communicate()
268 if popen.wait() != 0:
Tarek Ziadéb1a85412008-12-30 23:03:41 +0000269 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimescbdb7052007-12-05 20:10:38 +0000270
271 stdout = stdout.decode("mbcs")
272 for line in stdout.split("\n"):
Christian Heimes3305c522007-12-03 13:47:29 +0000273 line = Reg.convert_mbcs(line)
274 if '=' not in line:
275 continue
276 line = line.strip()
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000277 key, value = line.split('=', 1)
Christian Heimes3305c522007-12-03 13:47:29 +0000278 key = key.lower()
279 if key in interesting:
280 if value.endswith(os.pathsep):
281 value = value[:-1]
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000282 result[key] = removeDuplicates(value)
Christian Heimes3305c522007-12-03 13:47:29 +0000283
284 if len(result) != len(interesting):
285 raise ValueError(str(list(result.keys())))
286
287 return result
288
289# More globals
290VERSION = get_build_version()
291if VERSION < 8.0:
292 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000293# MACROS = MacroExpander(VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000294
295class MSVCCompiler(CCompiler) :
296 """Concrete class that implements an interface to Microsoft Visual C++,
297 as defined by the CCompiler abstract class."""
298
299 compiler_type = 'msvc'
300
301 # Just set this so CCompiler's constructor doesn't barf. We currently
302 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
303 # as it really isn't necessary for this sort of single-compiler class.
304 # Would be nice to have a consistent interface with UnixCCompiler,
305 # though, so it's worth thinking about.
306 executables = {}
307
308 # Private class data (need to distinguish C from C++ source for compiler)
309 _c_extensions = ['.c']
310 _cpp_extensions = ['.cc', '.cpp', '.cxx']
311 _rc_extensions = ['.rc']
312 _mc_extensions = ['.mc']
313
314 # Needed for the filename generation methods provided by the
315 # base class, CCompiler.
316 src_extensions = (_c_extensions + _cpp_extensions +
317 _rc_extensions + _mc_extensions)
318 res_extension = '.res'
319 obj_extension = '.obj'
320 static_lib_extension = '.lib'
321 shared_lib_extension = '.dll'
322 static_lib_format = shared_lib_format = '%s%s'
323 exe_extension = '.exe'
324
325 def __init__(self, verbose=0, dry_run=0, force=0):
326 CCompiler.__init__ (self, verbose, dry_run, force)
327 self.__version = VERSION
Christian Heimes3305c522007-12-03 13:47:29 +0000328 self.__root = r"Software\Microsoft\VisualStudio"
329 # self.__macros = MACROS
Christian Heimesaa674712008-11-28 11:02:32 +0000330 self.__paths = []
Mark Hammond495cf992008-04-07 01:53:39 +0000331 # target platform (.plat_name is consistent with 'bdist')
332 self.plat_name = None
333 self.__arch = None # deprecated name
Christian Heimes3305c522007-12-03 13:47:29 +0000334 self.initialized = False
335
Mark Hammond495cf992008-04-07 01:53:39 +0000336 def initialize(self, plat_name=None):
337 # multi-init means we would need to check platform same each time...
338 assert not self.initialized, "don't init multiple times"
339 if plat_name is None:
Tarek Ziadé92e68af2010-01-26 22:46:15 +0000340 plat_name = get_platform()
Mark Hammond495cf992008-04-07 01:53:39 +0000341 # sanity check for platforms to prevent obscure errors later.
342 ok_plats = 'win32', 'win-amd64', 'win-ia64'
343 if plat_name not in ok_plats:
344 raise DistutilsPlatformError("--plat-name must be one of %s" %
345 (ok_plats,))
346
Christian Heimes3305c522007-12-03 13:47:29 +0000347 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
348 # Assume that the SDK set up everything alright; don't try to be
349 # smarter
350 self.cc = "cl.exe"
351 self.linker = "link.exe"
352 self.lib = "lib.exe"
353 self.rc = "rc.exe"
354 self.mc = "mc.exe"
355 else:
Mark Hammond495cf992008-04-07 01:53:39 +0000356 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
357 # to cross compile, you use 'x86_amd64'.
358 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
359 # compile use 'x86' (ie, it runs the x86 compiler directly)
360 # No idea how itanium handles this, if at all.
Tarek Ziadé92e68af2010-01-26 22:46:15 +0000361 if plat_name == get_platform() or plat_name == 'win32':
Mark Hammond495cf992008-04-07 01:53:39 +0000362 # native build or cross-compile to win32
363 plat_spec = PLAT_TO_VCVARS[plat_name]
364 else:
365 # cross compile from win32 -> some 64bit
Tarek Ziadé92e68af2010-01-26 22:46:15 +0000366 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
Mark Hammond495cf992008-04-07 01:53:39 +0000367 PLAT_TO_VCVARS[plat_name]
368
369 vc_env = query_vcvarsall(VERSION, plat_spec)
370
Mark Hammond900155f2008-09-18 03:51:46 +0000371 # take care to only use strings in the environment.
372 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
373 os.environ['lib'] = vc_env['lib'].encode('mbcs')
374 os.environ['include'] = vc_env['include'].encode('mbcs')
Christian Heimes3305c522007-12-03 13:47:29 +0000375
376 if len(self.__paths) == 0:
377 raise DistutilsPlatformError("Python was built with %s, "
378 "and extensions need to be built with the same "
379 "version of the compiler, but it isn't installed."
380 % self.__product)
381
382 self.cc = self.find_exe("cl.exe")
383 self.linker = self.find_exe("link.exe")
384 self.lib = self.find_exe("lib.exe")
385 self.rc = self.find_exe("rc.exe") # resource compiler
386 self.mc = self.find_exe("mc.exe") # message compiler
387 #self.set_path_env_var('lib')
388 #self.set_path_env_var('include')
389
390 # extend the MSVC path with the current path
391 try:
392 for p in os.environ['path'].split(';'):
393 self.__paths.append(p)
394 except KeyError:
395 pass
396 self.__paths = normalize_and_reduce_paths(self.__paths)
397 os.environ['path'] = ";".join(self.__paths)
398
399 self.preprocess_options = None
400 if self.__arch == "x86":
401 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
402 '/DNDEBUG']
403 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
404 '/Z7', '/D_DEBUG']
405 else:
406 # Win64
407 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
408 '/DNDEBUG']
409 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
410 '/Z7', '/D_DEBUG']
411
412 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
413 if self.__version >= 7:
414 self.ldflags_shared_debug = [
415 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
416 ]
417 self.ldflags_static = [ '/nologo']
418
419 self.initialized = True
420
421 # -- Worker methods ------------------------------------------------
422
423 def object_filenames(self,
424 source_filenames,
425 strip_dir=0,
426 output_dir=''):
427 # Copied from ccompiler.py, extended to return .res as 'object'-file
428 # for .rc input file
429 if output_dir is None: output_dir = ''
430 obj_names = []
431 for src_name in source_filenames:
432 (base, ext) = os.path.splitext (src_name)
433 base = os.path.splitdrive(base)[1] # Chop off the drive
434 base = base[os.path.isabs(base):] # If abs, chop off leading /
435 if ext not in self.src_extensions:
436 # Better to raise an exception instead of silently continuing
437 # and later complain about sources and targets having
438 # different lengths
439 raise CompileError ("Don't know how to compile %s" % src_name)
440 if strip_dir:
441 base = os.path.basename (base)
442 if ext in self._rc_extensions:
443 obj_names.append (os.path.join (output_dir,
444 base + self.res_extension))
445 elif ext in self._mc_extensions:
446 obj_names.append (os.path.join (output_dir,
447 base + self.res_extension))
448 else:
449 obj_names.append (os.path.join (output_dir,
450 base + self.obj_extension))
451 return obj_names
452
453
454 def compile(self, sources,
455 output_dir=None, macros=None, include_dirs=None, debug=0,
456 extra_preargs=None, extra_postargs=None, depends=None):
457
458 if not self.initialized:
459 self.initialize()
460 compile_info = self._setup_compile(output_dir, macros, include_dirs,
461 sources, depends, extra_postargs)
462 macros, objects, extra_postargs, pp_opts, build = compile_info
463
464 compile_opts = extra_preargs or []
465 compile_opts.append ('/c')
466 if debug:
467 compile_opts.extend(self.compile_options_debug)
468 else:
469 compile_opts.extend(self.compile_options)
470
471 for obj in objects:
472 try:
473 src, ext = build[obj]
474 except KeyError:
475 continue
476 if debug:
477 # pass the full pathname to MSVC in debug mode,
478 # this allows the debugger to find the source file
479 # without asking the user to browse for it
480 src = os.path.abspath(src)
481
482 if ext in self._c_extensions:
483 input_opt = "/Tc" + src
484 elif ext in self._cpp_extensions:
485 input_opt = "/Tp" + src
486 elif ext in self._rc_extensions:
487 # compile .RC to .RES file
488 input_opt = src
489 output_opt = "/fo" + obj
490 try:
491 self.spawn([self.rc] + pp_opts +
492 [output_opt] + [input_opt])
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000493 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000494 raise CompileError(msg)
495 continue
496 elif ext in self._mc_extensions:
497 # Compile .MC to .RC file to .RES file.
498 # * '-h dir' specifies the directory for the
499 # generated include file
500 # * '-r dir' specifies the target directory of the
501 # generated RC file and the binary message resource
502 # it includes
503 #
504 # For now (since there are no options to change this),
505 # we use the source-directory for the include file and
506 # the build directory for the RC file and message
507 # resources. This works at least for win32all.
508 h_dir = os.path.dirname(src)
509 rc_dir = os.path.dirname(obj)
510 try:
511 # first compile .MC to .RC and .H file
512 self.spawn([self.mc] +
513 ['-h', h_dir, '-r', rc_dir] + [src])
514 base, _ = os.path.splitext (os.path.basename (src))
515 rc_file = os.path.join (rc_dir, base + '.rc')
516 # then compile .RC to .RES file
517 self.spawn([self.rc] +
518 ["/fo" + obj] + [rc_file])
519
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000520 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000521 raise CompileError(msg)
522 continue
523 else:
524 # how to handle this file?
525 raise CompileError("Don't know how to compile %s to %s"
526 % (src, obj))
527
528 output_opt = "/Fo" + obj
529 try:
530 self.spawn([self.cc] + compile_opts + pp_opts +
531 [input_opt, output_opt] +
532 extra_postargs)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000533 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000534 raise CompileError(msg)
535
536 return objects
537
538
539 def create_static_lib(self,
540 objects,
541 output_libname,
542 output_dir=None,
543 debug=0,
544 target_lang=None):
545
546 if not self.initialized:
547 self.initialize()
548 (objects, output_dir) = self._fix_object_args(objects, output_dir)
549 output_filename = self.library_filename(output_libname,
550 output_dir=output_dir)
551
552 if self._need_link(objects, output_filename):
553 lib_args = objects + ['/OUT:' + output_filename]
554 if debug:
555 pass # XXX what goes here?
556 try:
557 self.spawn([self.lib] + lib_args)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000558 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000559 raise LibError(msg)
560 else:
561 log.debug("skipping %s (up-to-date)", output_filename)
562
563
564 def link(self,
565 target_desc,
566 objects,
567 output_filename,
568 output_dir=None,
569 libraries=None,
570 library_dirs=None,
571 runtime_library_dirs=None,
572 export_symbols=None,
573 debug=0,
574 extra_preargs=None,
575 extra_postargs=None,
576 build_temp=None,
577 target_lang=None):
578
579 if not self.initialized:
580 self.initialize()
581 (objects, output_dir) = self._fix_object_args(objects, output_dir)
582 fixed_args = self._fix_lib_args(libraries, library_dirs,
583 runtime_library_dirs)
584 (libraries, library_dirs, runtime_library_dirs) = fixed_args
585
586 if runtime_library_dirs:
587 self.warn ("I don't know what to do with 'runtime_library_dirs': "
588 + str (runtime_library_dirs))
589
590 lib_opts = gen_lib_options(self,
591 library_dirs, runtime_library_dirs,
592 libraries)
593 if output_dir is not None:
594 output_filename = os.path.join(output_dir, output_filename)
595
596 if self._need_link(objects, output_filename):
597 if target_desc == CCompiler.EXECUTABLE:
598 if debug:
599 ldflags = self.ldflags_shared_debug[1:]
600 else:
601 ldflags = self.ldflags_shared[1:]
602 else:
603 if debug:
604 ldflags = self.ldflags_shared_debug
605 else:
606 ldflags = self.ldflags_shared
607
608 export_opts = []
609 for sym in (export_symbols or []):
610 export_opts.append("/EXPORT:" + sym)
611
612 ld_args = (ldflags + lib_opts + export_opts +
613 objects + ['/OUT:' + output_filename])
614
615 # The MSVC linker generates .lib and .exp files, which cannot be
616 # suppressed by any linker switches. The .lib files may even be
617 # needed! Make sure they are generated in the temporary build
618 # directory. Since they have different names for debug and release
619 # builds, they can go into the same directory.
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000620 build_temp = os.path.dirname(objects[0])
Christian Heimes3305c522007-12-03 13:47:29 +0000621 if export_symbols is not None:
622 (dll_name, dll_ext) = os.path.splitext(
623 os.path.basename(output_filename))
624 implib_file = os.path.join(
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000625 build_temp,
Christian Heimes3305c522007-12-03 13:47:29 +0000626 self.library_filename(dll_name))
627 ld_args.append ('/IMPLIB:' + implib_file)
628
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000629 # Embedded manifests are recommended - see MSDN article titled
630 # "How to: Embed a Manifest Inside a C/C++ Application"
631 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
632 # Ask the linker to generate the manifest in the temp dir, so
633 # we can embed it later.
634 temp_manifest = os.path.join(
635 build_temp,
636 os.path.basename(output_filename) + ".manifest")
637 ld_args.append('/MANIFESTFILE:' + temp_manifest)
638
Christian Heimes3305c522007-12-03 13:47:29 +0000639 if extra_preargs:
640 ld_args[:0] = extra_preargs
641 if extra_postargs:
642 ld_args.extend(extra_postargs)
643
644 self.mkpath(os.path.dirname(output_filename))
645 try:
646 self.spawn([self.linker] + ld_args)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000647 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000648 raise LinkError(msg)
649
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000650 # embed the manifest
651 # XXX - this is somewhat fragile - if mt.exe fails, distutils
652 # will still consider the DLL up-to-date, but it will not have a
653 # manifest. Maybe we should link to a temp file? OTOH, that
654 # implies a build environment error that shouldn't go undetected.
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000655 if target_desc == CCompiler.EXECUTABLE:
656 mfid = 1
657 else:
658 mfid = 2
Tarek Ziadé3efd7672009-12-21 23:31:55 +0000659 self._remove_visual_c_ref(temp_manifest)
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000660 out_arg = '-outputresource:%s;%s' % (output_filename, mfid)
661 try:
662 self.spawn(['mt.exe', '-nologo', '-manifest',
663 temp_manifest, out_arg])
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000664 except DistutilsExecError, msg:
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000665 raise LinkError(msg)
Christian Heimes3305c522007-12-03 13:47:29 +0000666 else:
667 log.debug("skipping %s (up-to-date)", output_filename)
668
Tarek Ziadé3efd7672009-12-21 23:31:55 +0000669 def _remove_visual_c_ref(self, manifest_file):
670 try:
671 # Remove references to the Visual C runtime, so they will
672 # fall through to the Visual C dependency of Python.exe.
673 # This way, when installed for a restricted user (e.g.
674 # runtimes are not in WinSxS folder, but in Python's own
675 # folder), the runtimes do not need to be in every folder
676 # with .pyd's.
677 manifest_f = open(manifest_file)
678 try:
679 manifest_buf = manifest_f.read()
680 finally:
681 manifest_f.close()
682 pattern = re.compile(
683 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
684 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
685 re.DOTALL)
686 manifest_buf = re.sub(pattern, "", manifest_buf)
687 pattern = "<dependentAssembly>\s*</dependentAssembly>"
688 manifest_buf = re.sub(pattern, "", manifest_buf)
689 manifest_f = open(manifest_file, 'w')
690 try:
691 manifest_f.write(manifest_buf)
692 finally:
693 manifest_f.close()
694 except IOError:
695 pass
Christian Heimes3305c522007-12-03 13:47:29 +0000696
697 # -- Miscellaneous methods -----------------------------------------
698 # These are all used by the 'gen_lib_options() function, in
699 # ccompiler.py.
700
701 def library_dir_option(self, dir):
702 return "/LIBPATH:" + dir
703
704 def runtime_library_dir_option(self, dir):
705 raise DistutilsPlatformError(
706 "don't know how to set runtime library search path for MSVC++")
707
708 def library_option(self, lib):
709 return self.library_filename(lib)
710
711
712 def find_library_file(self, dirs, lib, debug=0):
713 # Prefer a debugging library if found (and requested), but deal
714 # with it if we don't have one.
715 if debug:
716 try_names = [lib + "_d", lib]
717 else:
718 try_names = [lib]
719 for dir in dirs:
720 for name in try_names:
721 libfile = os.path.join(dir, self.library_filename (name))
722 if os.path.exists(libfile):
723 return libfile
724 else:
725 # Oops, didn't find it in *any* of 'dirs'
726 return None
727
728 # Helper methods for using the MSVC registry settings
729
730 def find_exe(self, exe):
731 """Return path to an MSVC executable program.
732
733 Tries to find the program in several places: first, one of the
734 MSVC program search paths from the registry; next, the directories
735 in the PATH environment variable. If any of those work, return an
736 absolute path that is known to exist. If none of them work, just
737 return the original program name, 'exe'.
738 """
739 for p in self.__paths:
740 fn = os.path.join(os.path.abspath(p), exe)
741 if os.path.isfile(fn):
742 return fn
743
744 # didn't find it; try existing path
745 for p in os.environ['Path'].split(';'):
746 fn = os.path.join(os.path.abspath(p),exe)
747 if os.path.isfile(fn):
748 return fn
749
750 return exe