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