comparison env/lib/python3.9/site-packages/setuptools/_distutils/msvccompiler.py @ 0:4f3585e2f14b draft default tip

"planemo upload commit 60cee0fc7c0cda8592644e1aad72851dec82c959"
author shellac
date Mon, 22 Mar 2021 18:12:50 +0000
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:4f3585e2f14b
1 """distutils.msvccompiler
2
3 Contains MSVCCompiler, an implementation of the abstract CCompiler class
4 for the Microsoft Visual Studio.
5 """
6
7 # Written by Perry Stoll
8 # hacked by Robin Becker and Thomas Heller to do a better job of
9 # finding DevStudio (through the registry)
10
11 import sys, os
12 from distutils.errors import \
13 DistutilsExecError, DistutilsPlatformError, \
14 CompileError, LibError, LinkError
15 from distutils.ccompiler import \
16 CCompiler, gen_lib_options
17 from distutils import log
18
19 _can_read_reg = False
20 try:
21 import winreg
22
23 _can_read_reg = True
24 hkey_mod = winreg
25
26 RegOpenKeyEx = winreg.OpenKeyEx
27 RegEnumKey = winreg.EnumKey
28 RegEnumValue = winreg.EnumValue
29 RegError = winreg.error
30
31 except ImportError:
32 try:
33 import win32api
34 import win32con
35 _can_read_reg = True
36 hkey_mod = win32con
37
38 RegOpenKeyEx = win32api.RegOpenKeyEx
39 RegEnumKey = win32api.RegEnumKey
40 RegEnumValue = win32api.RegEnumValue
41 RegError = win32api.error
42 except ImportError:
43 log.info("Warning: Can't read registry to find the "
44 "necessary compiler setting\n"
45 "Make sure that Python modules winreg, "
46 "win32api or win32con are installed.")
47 pass
48
49 if _can_read_reg:
50 HKEYS = (hkey_mod.HKEY_USERS,
51 hkey_mod.HKEY_CURRENT_USER,
52 hkey_mod.HKEY_LOCAL_MACHINE,
53 hkey_mod.HKEY_CLASSES_ROOT)
54
55 def read_keys(base, key):
56 """Return list of registry keys."""
57 try:
58 handle = RegOpenKeyEx(base, key)
59 except RegError:
60 return None
61 L = []
62 i = 0
63 while True:
64 try:
65 k = RegEnumKey(handle, i)
66 except RegError:
67 break
68 L.append(k)
69 i += 1
70 return L
71
72 def read_values(base, key):
73 """Return dict of registry keys and values.
74
75 All names are converted to lowercase.
76 """
77 try:
78 handle = RegOpenKeyEx(base, key)
79 except RegError:
80 return None
81 d = {}
82 i = 0
83 while True:
84 try:
85 name, value, type = RegEnumValue(handle, i)
86 except RegError:
87 break
88 name = name.lower()
89 d[convert_mbcs(name)] = convert_mbcs(value)
90 i += 1
91 return d
92
93 def convert_mbcs(s):
94 dec = getattr(s, "decode", None)
95 if dec is not None:
96 try:
97 s = dec("mbcs")
98 except UnicodeError:
99 pass
100 return s
101
102 class MacroExpander:
103 def __init__(self, version):
104 self.macros = {}
105 self.load_macros(version)
106
107 def set_macro(self, macro, path, key):
108 for base in HKEYS:
109 d = read_values(base, path)
110 if d:
111 self.macros["$(%s)" % macro] = d[key]
112 break
113
114 def load_macros(self, version):
115 vsbase = r"Software\Microsoft\VisualStudio\%0.1f" % version
116 self.set_macro("VCInstallDir", vsbase + r"\Setup\VC", "productdir")
117 self.set_macro("VSInstallDir", vsbase + r"\Setup\VS", "productdir")
118 net = r"Software\Microsoft\.NETFramework"
119 self.set_macro("FrameworkDir", net, "installroot")
120 try:
121 if version > 7.0:
122 self.set_macro("FrameworkSDKDir", net, "sdkinstallrootv1.1")
123 else:
124 self.set_macro("FrameworkSDKDir", net, "sdkinstallroot")
125 except KeyError as exc: #
126 raise DistutilsPlatformError(
127 """Python was built with Visual Studio 2003;
128 extensions must be built with a compiler than can generate compatible binaries.
129 Visual Studio 2003 was not found on this system. If you have Cygwin installed,
130 you can try compiling with MingW32, by passing "-c mingw32" to setup.py.""")
131
132 p = r"Software\Microsoft\NET Framework Setup\Product"
133 for base in HKEYS:
134 try:
135 h = RegOpenKeyEx(base, p)
136 except RegError:
137 continue
138 key = RegEnumKey(h, 0)
139 d = read_values(base, r"%s\%s" % (p, key))
140 self.macros["$(FrameworkVersion)"] = d["version"]
141
142 def sub(self, s):
143 for k, v in self.macros.items():
144 s = s.replace(k, v)
145 return s
146
147 def get_build_version():
148 """Return the version of MSVC that was used to build Python.
149
150 For Python 2.3 and up, the version number is included in
151 sys.version. For earlier versions, assume the compiler is MSVC 6.
152 """
153 prefix = "MSC v."
154 i = sys.version.find(prefix)
155 if i == -1:
156 return 6
157 i = i + len(prefix)
158 s, rest = sys.version[i:].split(" ", 1)
159 majorVersion = int(s[:-2]) - 6
160 if majorVersion >= 13:
161 # v13 was skipped and should be v14
162 majorVersion += 1
163 minorVersion = int(s[2:3]) / 10.0
164 # I don't think paths are affected by minor version in version 6
165 if majorVersion == 6:
166 minorVersion = 0
167 if majorVersion >= 6:
168 return majorVersion + minorVersion
169 # else we don't know what version of the compiler this is
170 return None
171
172 def get_build_architecture():
173 """Return the processor architecture.
174
175 Possible results are "Intel" or "AMD64".
176 """
177
178 prefix = " bit ("
179 i = sys.version.find(prefix)
180 if i == -1:
181 return "Intel"
182 j = sys.version.find(")", i)
183 return sys.version[i+len(prefix):j]
184
185 def normalize_and_reduce_paths(paths):
186 """Return a list of normalized paths with duplicates removed.
187
188 The current order of paths is maintained.
189 """
190 # Paths are normalized so things like: /a and /a/ aren't both preserved.
191 reduced_paths = []
192 for p in paths:
193 np = os.path.normpath(p)
194 # XXX(nnorwitz): O(n**2), if reduced_paths gets long perhaps use a set.
195 if np not in reduced_paths:
196 reduced_paths.append(np)
197 return reduced_paths
198
199
200 class MSVCCompiler(CCompiler) :
201 """Concrete class that implements an interface to Microsoft Visual C++,
202 as defined by the CCompiler abstract class."""
203
204 compiler_type = 'msvc'
205
206 # Just set this so CCompiler's constructor doesn't barf. We currently
207 # don't use the 'set_executables()' bureaucracy provided by CCompiler,
208 # as it really isn't necessary for this sort of single-compiler class.
209 # Would be nice to have a consistent interface with UnixCCompiler,
210 # though, so it's worth thinking about.
211 executables = {}
212
213 # Private class data (need to distinguish C from C++ source for compiler)
214 _c_extensions = ['.c']
215 _cpp_extensions = ['.cc', '.cpp', '.cxx']
216 _rc_extensions = ['.rc']
217 _mc_extensions = ['.mc']
218
219 # Needed for the filename generation methods provided by the
220 # base class, CCompiler.
221 src_extensions = (_c_extensions + _cpp_extensions +
222 _rc_extensions + _mc_extensions)
223 res_extension = '.res'
224 obj_extension = '.obj'
225 static_lib_extension = '.lib'
226 shared_lib_extension = '.dll'
227 static_lib_format = shared_lib_format = '%s%s'
228 exe_extension = '.exe'
229
230 def __init__(self, verbose=0, dry_run=0, force=0):
231 CCompiler.__init__ (self, verbose, dry_run, force)
232 self.__version = get_build_version()
233 self.__arch = get_build_architecture()
234 if self.__arch == "Intel":
235 # x86
236 if self.__version >= 7:
237 self.__root = r"Software\Microsoft\VisualStudio"
238 self.__macros = MacroExpander(self.__version)
239 else:
240 self.__root = r"Software\Microsoft\Devstudio"
241 self.__product = "Visual Studio version %s" % self.__version
242 else:
243 # Win64. Assume this was built with the platform SDK
244 self.__product = "Microsoft SDK compiler %s" % (self.__version + 6)
245
246 self.initialized = False
247
248 def initialize(self):
249 self.__paths = []
250 if "DISTUTILS_USE_SDK" in os.environ and "MSSdk" in os.environ and self.find_exe("cl.exe"):
251 # Assume that the SDK set up everything alright; don't try to be
252 # smarter
253 self.cc = "cl.exe"
254 self.linker = "link.exe"
255 self.lib = "lib.exe"
256 self.rc = "rc.exe"
257 self.mc = "mc.exe"
258 else:
259 self.__paths = self.get_msvc_paths("path")
260
261 if len(self.__paths) == 0:
262 raise DistutilsPlatformError("Python was built with %s, "
263 "and extensions need to be built with the same "
264 "version of the compiler, but it isn't installed."
265 % self.__product)
266
267 self.cc = self.find_exe("cl.exe")
268 self.linker = self.find_exe("link.exe")
269 self.lib = self.find_exe("lib.exe")
270 self.rc = self.find_exe("rc.exe") # resource compiler
271 self.mc = self.find_exe("mc.exe") # message compiler
272 self.set_path_env_var('lib')
273 self.set_path_env_var('include')
274
275 # extend the MSVC path with the current path
276 try:
277 for p in os.environ['path'].split(';'):
278 self.__paths.append(p)
279 except KeyError:
280 pass
281 self.__paths = normalize_and_reduce_paths(self.__paths)
282 os.environ['path'] = ";".join(self.__paths)
283
284 self.preprocess_options = None
285 if self.__arch == "Intel":
286 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GX' ,
287 '/DNDEBUG']
288 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GX',
289 '/Z7', '/D_DEBUG']
290 else:
291 # Win64
292 self.compile_options = [ '/nologo', '/Ox', '/MD', '/W3', '/GS-' ,
293 '/DNDEBUG']
294 self.compile_options_debug = ['/nologo', '/Od', '/MDd', '/W3', '/GS-',
295 '/Z7', '/D_DEBUG']
296
297 self.ldflags_shared = ['/DLL', '/nologo', '/INCREMENTAL:NO']
298 if self.__version >= 7:
299 self.ldflags_shared_debug = [
300 '/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG'
301 ]
302 else:
303 self.ldflags_shared_debug = [
304 '/DLL', '/nologo', '/INCREMENTAL:no', '/pdb:None', '/DEBUG'
305 ]
306 self.ldflags_static = [ '/nologo']
307
308 self.initialized = True
309
310 # -- Worker methods ------------------------------------------------
311
312 def object_filenames(self,
313 source_filenames,
314 strip_dir=0,
315 output_dir=''):
316 # Copied from ccompiler.py, extended to return .res as 'object'-file
317 # for .rc input file
318 if output_dir is None: output_dir = ''
319 obj_names = []
320 for src_name in source_filenames:
321 (base, ext) = os.path.splitext (src_name)
322 base = os.path.splitdrive(base)[1] # Chop off the drive
323 base = base[os.path.isabs(base):] # If abs, chop off leading /
324 if ext not in self.src_extensions:
325 # Better to raise an exception instead of silently continuing
326 # and later complain about sources and targets having
327 # different lengths
328 raise CompileError ("Don't know how to compile %s" % src_name)
329 if strip_dir:
330 base = os.path.basename (base)
331 if ext in self._rc_extensions:
332 obj_names.append (os.path.join (output_dir,
333 base + self.res_extension))
334 elif ext in self._mc_extensions:
335 obj_names.append (os.path.join (output_dir,
336 base + self.res_extension))
337 else:
338 obj_names.append (os.path.join (output_dir,
339 base + self.obj_extension))
340 return obj_names
341
342
343 def compile(self, sources,
344 output_dir=None, macros=None, include_dirs=None, debug=0,
345 extra_preargs=None, extra_postargs=None, depends=None):
346
347 if not self.initialized:
348 self.initialize()
349 compile_info = self._setup_compile(output_dir, macros, include_dirs,
350 sources, depends, extra_postargs)
351 macros, objects, extra_postargs, pp_opts, build = compile_info
352
353 compile_opts = extra_preargs or []
354 compile_opts.append ('/c')
355 if debug:
356 compile_opts.extend(self.compile_options_debug)
357 else:
358 compile_opts.extend(self.compile_options)
359
360 for obj in objects:
361 try:
362 src, ext = build[obj]
363 except KeyError:
364 continue
365 if debug:
366 # pass the full pathname to MSVC in debug mode,
367 # this allows the debugger to find the source file
368 # without asking the user to browse for it
369 src = os.path.abspath(src)
370
371 if ext in self._c_extensions:
372 input_opt = "/Tc" + src
373 elif ext in self._cpp_extensions:
374 input_opt = "/Tp" + src
375 elif ext in self._rc_extensions:
376 # compile .RC to .RES file
377 input_opt = src
378 output_opt = "/fo" + obj
379 try:
380 self.spawn([self.rc] + pp_opts +
381 [output_opt] + [input_opt])
382 except DistutilsExecError as msg:
383 raise CompileError(msg)
384 continue
385 elif ext in self._mc_extensions:
386 # Compile .MC to .RC file to .RES file.
387 # * '-h dir' specifies the directory for the
388 # generated include file
389 # * '-r dir' specifies the target directory of the
390 # generated RC file and the binary message resource
391 # it includes
392 #
393 # For now (since there are no options to change this),
394 # we use the source-directory for the include file and
395 # the build directory for the RC file and message
396 # resources. This works at least for win32all.
397 h_dir = os.path.dirname(src)
398 rc_dir = os.path.dirname(obj)
399 try:
400 # first compile .MC to .RC and .H file
401 self.spawn([self.mc] +
402 ['-h', h_dir, '-r', rc_dir] + [src])
403 base, _ = os.path.splitext (os.path.basename (src))
404 rc_file = os.path.join (rc_dir, base + '.rc')
405 # then compile .RC to .RES file
406 self.spawn([self.rc] +
407 ["/fo" + obj] + [rc_file])
408
409 except DistutilsExecError as msg:
410 raise CompileError(msg)
411 continue
412 else:
413 # how to handle this file?
414 raise CompileError("Don't know how to compile %s to %s"
415 % (src, obj))
416
417 output_opt = "/Fo" + obj
418 try:
419 self.spawn([self.cc] + compile_opts + pp_opts +
420 [input_opt, output_opt] +
421 extra_postargs)
422 except DistutilsExecError as msg:
423 raise CompileError(msg)
424
425 return objects
426
427
428 def create_static_lib(self,
429 objects,
430 output_libname,
431 output_dir=None,
432 debug=0,
433 target_lang=None):
434
435 if not self.initialized:
436 self.initialize()
437 (objects, output_dir) = self._fix_object_args(objects, output_dir)
438 output_filename = self.library_filename(output_libname,
439 output_dir=output_dir)
440
441 if self._need_link(objects, output_filename):
442 lib_args = objects + ['/OUT:' + output_filename]
443 if debug:
444 pass # XXX what goes here?
445 try:
446 self.spawn([self.lib] + lib_args)
447 except DistutilsExecError as msg:
448 raise LibError(msg)
449 else:
450 log.debug("skipping %s (up-to-date)", output_filename)
451
452
453 def link(self,
454 target_desc,
455 objects,
456 output_filename,
457 output_dir=None,
458 libraries=None,
459 library_dirs=None,
460 runtime_library_dirs=None,
461 export_symbols=None,
462 debug=0,
463 extra_preargs=None,
464 extra_postargs=None,
465 build_temp=None,
466 target_lang=None):
467
468 if not self.initialized:
469 self.initialize()
470 (objects, output_dir) = self._fix_object_args(objects, output_dir)
471 fixed_args = self._fix_lib_args(libraries, library_dirs,
472 runtime_library_dirs)
473 (libraries, library_dirs, runtime_library_dirs) = fixed_args
474
475 if runtime_library_dirs:
476 self.warn ("I don't know what to do with 'runtime_library_dirs': "
477 + str (runtime_library_dirs))
478
479 lib_opts = gen_lib_options(self,
480 library_dirs, runtime_library_dirs,
481 libraries)
482 if output_dir is not None:
483 output_filename = os.path.join(output_dir, output_filename)
484
485 if self._need_link(objects, output_filename):
486 if target_desc == CCompiler.EXECUTABLE:
487 if debug:
488 ldflags = self.ldflags_shared_debug[1:]
489 else:
490 ldflags = self.ldflags_shared[1:]
491 else:
492 if debug:
493 ldflags = self.ldflags_shared_debug
494 else:
495 ldflags = self.ldflags_shared
496
497 export_opts = []
498 for sym in (export_symbols or []):
499 export_opts.append("/EXPORT:" + sym)
500
501 ld_args = (ldflags + lib_opts + export_opts +
502 objects + ['/OUT:' + output_filename])
503
504 # The MSVC linker generates .lib and .exp files, which cannot be
505 # suppressed by any linker switches. The .lib files may even be
506 # needed! Make sure they are generated in the temporary build
507 # directory. Since they have different names for debug and release
508 # builds, they can go into the same directory.
509 if export_symbols is not None:
510 (dll_name, dll_ext) = os.path.splitext(
511 os.path.basename(output_filename))
512 implib_file = os.path.join(
513 os.path.dirname(objects[0]),
514 self.library_filename(dll_name))
515 ld_args.append ('/IMPLIB:' + implib_file)
516
517 if extra_preargs:
518 ld_args[:0] = extra_preargs
519 if extra_postargs:
520 ld_args.extend(extra_postargs)
521
522 self.mkpath(os.path.dirname(output_filename))
523 try:
524 self.spawn([self.linker] + ld_args)
525 except DistutilsExecError as msg:
526 raise LinkError(msg)
527
528 else:
529 log.debug("skipping %s (up-to-date)", output_filename)
530
531
532 # -- Miscellaneous methods -----------------------------------------
533 # These are all used by the 'gen_lib_options() function, in
534 # ccompiler.py.
535
536 def library_dir_option(self, dir):
537 return "/LIBPATH:" + dir
538
539 def runtime_library_dir_option(self, dir):
540 raise DistutilsPlatformError(
541 "don't know how to set runtime library search path for MSVC++")
542
543 def library_option(self, lib):
544 return self.library_filename(lib)
545
546
547 def find_library_file(self, dirs, lib, debug=0):
548 # Prefer a debugging library if found (and requested), but deal
549 # with it if we don't have one.
550 if debug:
551 try_names = [lib + "_d", lib]
552 else:
553 try_names = [lib]
554 for dir in dirs:
555 for name in try_names:
556 libfile = os.path.join(dir, self.library_filename (name))
557 if os.path.exists(libfile):
558 return libfile
559 else:
560 # Oops, didn't find it in *any* of 'dirs'
561 return None
562
563 # Helper methods for using the MSVC registry settings
564
565 def find_exe(self, exe):
566 """Return path to an MSVC executable program.
567
568 Tries to find the program in several places: first, one of the
569 MSVC program search paths from the registry; next, the directories
570 in the PATH environment variable. If any of those work, return an
571 absolute path that is known to exist. If none of them work, just
572 return the original program name, 'exe'.
573 """
574 for p in self.__paths:
575 fn = os.path.join(os.path.abspath(p), exe)
576 if os.path.isfile(fn):
577 return fn
578
579 # didn't find it; try existing path
580 for p in os.environ['Path'].split(';'):
581 fn = os.path.join(os.path.abspath(p),exe)
582 if os.path.isfile(fn):
583 return fn
584
585 return exe
586
587 def get_msvc_paths(self, path, platform='x86'):
588 """Get a list of devstudio directories (include, lib or path).
589
590 Return a list of strings. The list will be empty if unable to
591 access the registry or appropriate registry keys not found.
592 """
593 if not _can_read_reg:
594 return []
595
596 path = path + " dirs"
597 if self.__version >= 7:
598 key = (r"%s\%0.1f\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories"
599 % (self.__root, self.__version))
600 else:
601 key = (r"%s\6.0\Build System\Components\Platforms"
602 r"\Win32 (%s)\Directories" % (self.__root, platform))
603
604 for base in HKEYS:
605 d = read_values(base, key)
606 if d:
607 if self.__version >= 7:
608 return self.__macros.sub(d[path]).split(";")
609 else:
610 return d[path].split(";")
611 # MSVC 6 seems to create the registry entries we need only when
612 # the GUI is run.
613 if self.__version == 6:
614 for base in HKEYS:
615 if read_values(base, r"%s\6.0" % self.__root) is not None:
616 self.warn("It seems you have Visual Studio 6 installed, "
617 "but the expected registry settings are not present.\n"
618 "You must at least run the Visual Studio GUI once "
619 "so that these entries are created.")
620 break
621 return []
622
623 def set_path_env_var(self, name):
624 """Set environment variable 'name' to an MSVC path type value.
625
626 This is equivalent to a SET command prior to execution of spawned
627 commands.
628 """
629
630 if name == "lib":
631 p = self.get_msvc_paths("library")
632 else:
633 p = self.get_msvc_paths(name)
634 if p:
635 os.environ[name] = ';'.join(p)
636
637
638 if get_build_version() >= 8.0:
639 log.debug("Importing new compiler from distutils.msvc9compiler")
640 OldMSVCCompiler = MSVCCompiler
641 from distutils.msvc9compiler import MSVCCompiler
642 # get_build_architecture not really relevant now we support cross-compile
643 from distutils.msvc9compiler import MacroExpander