blob: c2287d9291618ffa122055a28b86de49b4ccf883 [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
22from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
23 CompileError, LibError, LinkError
24from distutils.ccompiler import CCompiler, gen_preprocess_options, \
25 gen_lib_options
Christian Heimes3305c522007-12-03 13:47:29 +000026from distutils import log
Mark Hammond495cf992008-04-07 01:53:39 +000027from distutils.util import get_platform
Christian Heimes3305c522007-12-03 13:47:29 +000028
29import _winreg
30
31RegOpenKeyEx = _winreg.OpenKeyEx
32RegEnumKey = _winreg.EnumKey
33RegEnumValue = _winreg.EnumValue
34RegError = _winreg.error
35
36HKEYS = (_winreg.HKEY_USERS,
37 _winreg.HKEY_CURRENT_USER,
38 _winreg.HKEY_LOCAL_MACHINE,
39 _winreg.HKEY_CLASSES_ROOT)
40
41VS_BASE = r"Software\Microsoft\VisualStudio\%0.1f"
42WINSDK_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:
220 log.debug("Unable to find productdir in registry")
221 productdir = None
222
223 if not productdir or not os.path.isdir(productdir):
224 toolskey = "VS%0.f0COMNTOOLS" % version
225 toolsdir = os.environ.get(toolskey, None)
226
227 if toolsdir and os.path.isdir(toolsdir):
228 productdir = os.path.join(toolsdir, os.pardir, os.pardir, "VC")
229 productdir = os.path.abspath(productdir)
230 if not os.path.isdir(productdir):
231 log.debug("%s is not a valid directory" % productdir)
232 return None
233 else:
234 log.debug("Env var %s is not set or invalid" % toolskey)
235 if not productdir:
236 log.debug("No productdir found")
237 return None
238 vcvarsall = os.path.join(productdir, "vcvarsall.bat")
239 if os.path.isfile(vcvarsall):
240 return vcvarsall
241 log.debug("Unable to find vcvarsall.bat")
242 return None
243
244def query_vcvarsall(version, arch="x86"):
245 """Launch vcvarsall.bat and read the settings from its environment
246 """
247 vcvarsall = find_vcvarsall(version)
248 interesting = set(("include", "lib", "libpath", "path"))
249 result = {}
250
251 if vcvarsall is None:
Tarek Ziadéb1a85412008-12-30 23:03:41 +0000252 raise DistutilsPlatformError("Unable to find vcvarsall.bat")
Mark Hammond495cf992008-04-07 01:53:39 +0000253 log.debug("Calling 'vcvarsall.bat %s' (version=%s)", arch, version)
Christian Heimes3305c522007-12-03 13:47:29 +0000254 popen = subprocess.Popen('"%s" %s & set' % (vcvarsall, arch),
255 stdout=subprocess.PIPE,
256 stderr=subprocess.PIPE)
Christian Heimes3305c522007-12-03 13:47:29 +0000257
Christian Heimescbdb7052007-12-05 20:10:38 +0000258 stdout, stderr = popen.communicate()
259 if popen.wait() != 0:
Tarek Ziadéb1a85412008-12-30 23:03:41 +0000260 raise DistutilsPlatformError(stderr.decode("mbcs"))
Christian Heimescbdb7052007-12-05 20:10:38 +0000261
262 stdout = stdout.decode("mbcs")
263 for line in stdout.split("\n"):
Christian Heimes3305c522007-12-03 13:47:29 +0000264 line = Reg.convert_mbcs(line)
265 if '=' not in line:
266 continue
267 line = line.strip()
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000268 key, value = line.split('=', 1)
Christian Heimes3305c522007-12-03 13:47:29 +0000269 key = key.lower()
270 if key in interesting:
271 if value.endswith(os.pathsep):
272 value = value[:-1]
Amaury Forgeot d'Arc293924b2008-09-02 23:19:56 +0000273 result[key] = removeDuplicates(value)
Christian Heimes3305c522007-12-03 13:47:29 +0000274
275 if len(result) != len(interesting):
276 raise ValueError(str(list(result.keys())))
277
278 return result
279
280# More globals
281VERSION = get_build_version()
282if VERSION < 8.0:
283 raise DistutilsPlatformError("VC %0.1f is not supported by this module" % VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000284# MACROS = MacroExpander(VERSION)
Christian Heimes3305c522007-12-03 13:47:29 +0000285
286class MSVCCompiler(CCompiler) :
287 """Concrete class that implements an interface to Microsoft Visual C++,
288 as defined by the CCompiler abstract class."""
289
290 compiler_type = 'msvc'
291
292 # Just set this so CCompiler's constructor doesn't barf. We currently
293 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
294 # as it really isn't necessary for this sort of single-compiler class.
295 # Would be nice to have a consistent interface with UnixCCompiler,
296 # though, so it's worth thinking about.
297 executables = {}
298
299 # Private class data (need to distinguish C from C++ source for compiler)
300 _c_extensions = ['.c']
301 _cpp_extensions = ['.cc', '.cpp', '.cxx']
302 _rc_extensions = ['.rc']
303 _mc_extensions = ['.mc']
304
305 # Needed for the filename generation methods provided by the
306 # base class, CCompiler.
307 src_extensions = (_c_extensions + _cpp_extensions +
308 _rc_extensions + _mc_extensions)
309 res_extension = '.res'
310 obj_extension = '.obj'
311 static_lib_extension = '.lib'
312 shared_lib_extension = '.dll'
313 static_lib_format = shared_lib_format = '%s%s'
314 exe_extension = '.exe'
315
316 def __init__(self, verbose=0, dry_run=0, force=0):
317 CCompiler.__init__ (self, verbose, dry_run, force)
318 self.__version = VERSION
Christian Heimes3305c522007-12-03 13:47:29 +0000319 self.__root = r"Software\Microsoft\VisualStudio"
320 # self.__macros = MACROS
Christian Heimesaa674712008-11-28 11:02:32 +0000321 self.__paths = []
Mark Hammond495cf992008-04-07 01:53:39 +0000322 # target platform (.plat_name is consistent with 'bdist')
323 self.plat_name = None
324 self.__arch = None # deprecated name
Christian Heimes3305c522007-12-03 13:47:29 +0000325 self.initialized = False
326
Mark Hammond495cf992008-04-07 01:53:39 +0000327 def initialize(self, plat_name=None):
328 # multi-init means we would need to check platform same each time...
329 assert not self.initialized, "don't init multiple times"
330 if plat_name is None:
331 plat_name = get_platform()
332 # sanity check for platforms to prevent obscure errors later.
333 ok_plats = 'win32', 'win-amd64', 'win-ia64'
334 if plat_name not in ok_plats:
335 raise DistutilsPlatformError("--plat-name must be one of %s" %
336 (ok_plats,))
337
Christian Heimes3305c522007-12-03 13:47:29 +0000338 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
339 # Assume that the SDK set up everything alright; don't try to be
340 # smarter
341 self.cc = "cl.exe"
342 self.linker = "link.exe"
343 self.lib = "lib.exe"
344 self.rc = "rc.exe"
345 self.mc = "mc.exe"
346 else:
Mark Hammond495cf992008-04-07 01:53:39 +0000347 # On x86, 'vcvars32.bat amd64' creates an env that doesn't work;
348 # to cross compile, you use 'x86_amd64'.
349 # On AMD64, 'vcvars32.bat amd64' is a native build env; to cross
350 # compile use 'x86' (ie, it runs the x86 compiler directly)
351 # No idea how itanium handles this, if at all.
352 if plat_name == get_platform() or plat_name == 'win32':
353 # native build or cross-compile to win32
354 plat_spec = PLAT_TO_VCVARS[plat_name]
355 else:
356 # cross compile from win32 -> some 64bit
357 plat_spec = PLAT_TO_VCVARS[get_platform()] + '_' + \
358 PLAT_TO_VCVARS[plat_name]
359
360 vc_env = query_vcvarsall(VERSION, plat_spec)
361
Mark Hammond900155f2008-09-18 03:51:46 +0000362 # take care to only use strings in the environment.
363 self.__paths = vc_env['path'].encode('mbcs').split(os.pathsep)
364 os.environ['lib'] = vc_env['lib'].encode('mbcs')
365 os.environ['include'] = vc_env['include'].encode('mbcs')
Christian Heimes3305c522007-12-03 13:47:29 +0000366
367 if len(self.__paths) == 0:
368 raise DistutilsPlatformError("Python was built with %s, "
369 "and extensions need to be built with the same "
370 "version of the compiler, but it isn't installed."
371 % self.__product)
372
373 self.cc = self.find_exe("cl.exe")
374 self.linker = self.find_exe("link.exe")
375 self.lib = self.find_exe("lib.exe")
376 self.rc = self.find_exe("rc.exe") # resource compiler
377 self.mc = self.find_exe("mc.exe") # message compiler
378 #self.set_path_env_var('lib')
379 #self.set_path_env_var('include')
380
381 # extend the MSVC path with the current path
382 try:
383 for p in os.environ['path'].split(';'):
384 self.__paths.append(p)
385 except KeyError:
386 pass
387 self.__paths = normalize_and_reduce_paths(self.__paths)
388 os.environ['path'] = ";".join(self.__paths)
389
390 self.preprocess_options = None
391 if self.__arch == "x86":
392 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3',
393 '/DNDEBUG']
394 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3',
395 '/Z7', '/D_DEBUG']
396 else:
397 # Win64
398 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
399 '/DNDEBUG']
400 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
401 '/Z7', '/D_DEBUG']
402
403 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
404 if self.__version >= 7:
405 self.ldflags_shared_debug = [
406 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG', '/pdb:None'
407 ]
408 self.ldflags_static = [ '/nologo']
409
410 self.initialized = True
411
412 # -- Worker methods ------------------------------------------------
413
414 def object_filenames(self,
415 source_filenames,
416 strip_dir=0,
417 output_dir=''):
418 # Copied from ccompiler.py, extended to return .res as 'object'-file
419 # for .rc input file
420 if output_dir is None: output_dir = ''
421 obj_names = []
422 for src_name in source_filenames:
423 (base, ext) = os.path.splitext (src_name)
424 base = os.path.splitdrive(base)[1] # Chop off the drive
425 base = base[os.path.isabs(base):] # If abs, chop off leading /
426 if ext not in self.src_extensions:
427 # Better to raise an exception instead of silently continuing
428 # and later complain about sources and targets having
429 # different lengths
430 raise CompileError ("Don't know how to compile %s" % src_name)
431 if strip_dir:
432 base = os.path.basename (base)
433 if ext in self._rc_extensions:
434 obj_names.append (os.path.join (output_dir,
435 base + self.res_extension))
436 elif ext in self._mc_extensions:
437 obj_names.append (os.path.join (output_dir,
438 base + self.res_extension))
439 else:
440 obj_names.append (os.path.join (output_dir,
441 base + self.obj_extension))
442 return obj_names
443
444
445 def compile(self, sources,
446 output_dir=None, macros=None, include_dirs=None, debug=0,
447 extra_preargs=None, extra_postargs=None, depends=None):
448
449 if not self.initialized:
450 self.initialize()
451 compile_info = self._setup_compile(output_dir, macros, include_dirs,
452 sources, depends, extra_postargs)
453 macros, objects, extra_postargs, pp_opts, build = compile_info
454
455 compile_opts = extra_preargs or []
456 compile_opts.append ('/c')
457 if debug:
458 compile_opts.extend(self.compile_options_debug)
459 else:
460 compile_opts.extend(self.compile_options)
461
462 for obj in objects:
463 try:
464 src, ext = build[obj]
465 except KeyError:
466 continue
467 if debug:
468 # pass the full pathname to MSVC in debug mode,
469 # this allows the debugger to find the source file
470 # without asking the user to browse for it
471 src = os.path.abspath(src)
472
473 if ext in self._c_extensions:
474 input_opt = "/Tc" + src
475 elif ext in self._cpp_extensions:
476 input_opt = "/Tp" + src
477 elif ext in self._rc_extensions:
478 # compile .RC to .RES file
479 input_opt = src
480 output_opt = "/fo" + obj
481 try:
482 self.spawn([self.rc] + pp_opts +
483 [output_opt] + [input_opt])
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000484 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000485 raise CompileError(msg)
486 continue
487 elif ext in self._mc_extensions:
488 # Compile .MC to .RC file to .RES file.
489 # * '-h dir' specifies the directory for the
490 # generated include file
491 # * '-r dir' specifies the target directory of the
492 # generated RC file and the binary message resource
493 # it includes
494 #
495 # For now (since there are no options to change this),
496 # we use the source-directory for the include file and
497 # the build directory for the RC file and message
498 # resources. This works at least for win32all.
499 h_dir = os.path.dirname(src)
500 rc_dir = os.path.dirname(obj)
501 try:
502 # first compile .MC to .RC and .H file
503 self.spawn([self.mc] +
504 ['-h', h_dir, '-r', rc_dir] + [src])
505 base, _ = os.path.splitext (os.path.basename (src))
506 rc_file = os.path.join (rc_dir, base + '.rc')
507 # then compile .RC to .RES file
508 self.spawn([self.rc] +
509 ["/fo" + obj] + [rc_file])
510
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000511 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000512 raise CompileError(msg)
513 continue
514 else:
515 # how to handle this file?
516 raise CompileError("Don't know how to compile %s to %s"
517 % (src, obj))
518
519 output_opt = "/Fo" + obj
520 try:
521 self.spawn([self.cc] + compile_opts + pp_opts +
522 [input_opt, output_opt] +
523 extra_postargs)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000524 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000525 raise CompileError(msg)
526
527 return objects
528
529
530 def create_static_lib(self,
531 objects,
532 output_libname,
533 output_dir=None,
534 debug=0,
535 target_lang=None):
536
537 if not self.initialized:
538 self.initialize()
539 (objects, output_dir) = self._fix_object_args(objects, output_dir)
540 output_filename = self.library_filename(output_libname,
541 output_dir=output_dir)
542
543 if self._need_link(objects, output_filename):
544 lib_args = objects + ['/OUT:' + output_filename]
545 if debug:
546 pass # XXX what goes here?
547 try:
548 self.spawn([self.lib] + lib_args)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000549 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000550 raise LibError(msg)
551 else:
552 log.debug("skipping %s (up-to-date)", output_filename)
553
554
555 def link(self,
556 target_desc,
557 objects,
558 output_filename,
559 output_dir=None,
560 libraries=None,
561 library_dirs=None,
562 runtime_library_dirs=None,
563 export_symbols=None,
564 debug=0,
565 extra_preargs=None,
566 extra_postargs=None,
567 build_temp=None,
568 target_lang=None):
569
570 if not self.initialized:
571 self.initialize()
572 (objects, output_dir) = self._fix_object_args(objects, output_dir)
573 fixed_args = self._fix_lib_args(libraries, library_dirs,
574 runtime_library_dirs)
575 (libraries, library_dirs, runtime_library_dirs) = fixed_args
576
577 if runtime_library_dirs:
578 self.warn ("I don't know what to do with 'runtime_library_dirs': "
579 + str (runtime_library_dirs))
580
581 lib_opts = gen_lib_options(self,
582 library_dirs, runtime_library_dirs,
583 libraries)
584 if output_dir is not None:
585 output_filename = os.path.join(output_dir, output_filename)
586
587 if self._need_link(objects, output_filename):
588 if target_desc == CCompiler.EXECUTABLE:
589 if debug:
590 ldflags = self.ldflags_shared_debug[1:]
591 else:
592 ldflags = self.ldflags_shared[1:]
593 else:
594 if debug:
595 ldflags = self.ldflags_shared_debug
596 else:
597 ldflags = self.ldflags_shared
598
599 export_opts = []
600 for sym in (export_symbols or []):
601 export_opts.append("/EXPORT:" + sym)
602
603 ld_args = (ldflags + lib_opts + export_opts +
604 objects + ['/OUT:' + output_filename])
605
606 # The MSVC linker generates .lib and .exp files, which cannot be
607 # suppressed by any linker switches. The .lib files may even be
608 # needed! Make sure they are generated in the temporary build
609 # directory. Since they have different names for debug and release
610 # builds, they can go into the same directory.
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000611 build_temp = os.path.dirname(objects[0])
Christian Heimes3305c522007-12-03 13:47:29 +0000612 if export_symbols is not None:
613 (dll_name, dll_ext) = os.path.splitext(
614 os.path.basename(output_filename))
615 implib_file = os.path.join(
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000616 build_temp,
Christian Heimes3305c522007-12-03 13:47:29 +0000617 self.library_filename(dll_name))
618 ld_args.append ('/IMPLIB:' + implib_file)
619
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000620 # Embedded manifests are recommended - see MSDN article titled
621 # "How to: Embed a Manifest Inside a C/C++ Application"
622 # (currently at http://msdn2.microsoft.com/en-us/library/ms235591(VS.80).aspx)
623 # Ask the linker to generate the manifest in the temp dir, so
624 # we can embed it later.
625 temp_manifest = os.path.join(
626 build_temp,
627 os.path.basename(output_filename) + ".manifest")
628 ld_args.append('/MANIFESTFILE:' + temp_manifest)
629
Christian Heimes3305c522007-12-03 13:47:29 +0000630 if extra_preargs:
631 ld_args[:0] = extra_preargs
632 if extra_postargs:
633 ld_args.extend(extra_postargs)
634
635 self.mkpath(os.path.dirname(output_filename))
636 try:
637 self.spawn([self.linker] + ld_args)
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000638 except DistutilsExecError, msg:
Christian Heimes3305c522007-12-03 13:47:29 +0000639 raise LinkError(msg)
640
Mark Hammond7c5c8e62008-05-02 12:48:15 +0000641 # embed the manifest
642 # XXX - this is somewhat fragile - if mt.exe fails, distutils
643 # will still consider the DLL up-to-date, but it will not have a
644 # manifest. Maybe we should link to a temp file? OTOH, that
645 # implies a build environment error that shouldn't go undetected.
Tarek Ziadé943b24e2009-03-07 00:32:45 +0000646 if target_desc == CCompiler.EXECUTABLE:
647 mfid = 1
648 else:
649 mfid = 2
Martin v. Löwisc218a2f2009-12-03 20:53:51 +0000650 try:
651 # Remove references to the Visual C runtime, so they will
652 # fall through to the Visual C dependency of Python.exe.
653 # This way, when installed for a restricted user (e.g.
654 # runtimes are not in WinSxS folder, but in Python's own
655 # folder), the runtimes do not need to be in every folder
656 # with .pyd's.
657 manifest_f = open(temp_manifest, "rb")
658 manifest_buf = manifest_f.read()
659 manifest_f.close()
660 pattern = re.compile(
661 r"""<assemblyIdentity.*?name=("|')Microsoft\."""\
662 r"""VC\d{2}\.CRT("|').*?(/>|</assemblyIdentity>)""",
663 re.DOTALL)
664 manifest_buf = re.sub(pattern, "", manifest_buf)
665 pattern = "<dependentAssembly>\s*</dependentAssembly>"
666 manifest_buf = re.sub(pattern, "", manifest_buf)
667 manifest_f = open(temp_manifest, "wb")
668 manifest_f.write(manifest_buf)
669 manifest_f.close()
670 except IOError:
671 pass
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
681
682 # -- Miscellaneous methods -----------------------------------------
683 # These are all used by the 'gen_lib_options() function, in
684 # ccompiler.py.
685
686 def library_dir_option(self, dir):
687 return "/LIBPATH:" + dir
688
689 def runtime_library_dir_option(self, dir):
690 raise DistutilsPlatformError(
691 "don't know how to set runtime library search path for MSVC++")
692
693 def library_option(self, lib):
694 return self.library_filename(lib)
695
696
697 def find_library_file(self, dirs, lib, debug=0):
698 # Prefer a debugging library if found (and requested), but deal
699 # with it if we don't have one.
700 if debug:
701 try_names = [lib + "_d", lib]
702 else:
703 try_names = [lib]
704 for dir in dirs:
705 for name in try_names:
706 libfile = os.path.join(dir, self.library_filename (name))
707 if os.path.exists(libfile):
708 return libfile
709 else:
710 # Oops, didn't find it in *any* of 'dirs'
711 return None
712
713 # Helper methods for using the MSVC registry settings
714
715 def find_exe(self, exe):
716 """Return path to an MSVC executable program.
717
718 Tries to find the program in several places: first, one of the
719 MSVC program search paths from the registry; next, the directories
720 in the PATH environment variable. If any of those work, return an
721 absolute path that is known to exist. If none of them work, just
722 return the original program name, 'exe'.
723 """
724 for p in self.__paths:
725 fn = os.path.join(os.path.abspath(p), exe)
726 if os.path.isfile(fn):
727 return fn
728
729 # didn't find it; try existing path
730 for p in os.environ['Path'].split(';'):
731 fn = os.path.join(os.path.abspath(p),exe)
732 if os.path.isfile(fn):
733 return fn
734
735 return exe