]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/setuptools/_distutils/msvccompiler.py
1 """distutils.msvccompiler
3 Contains MSVCCompiler, an implementation of the abstract CCompiler class
4 for the Microsoft Visual Studio.
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)
16 DistutilsPlatformError
,
21 from .ccompiler
import CCompiler
, gen_lib_options
31 RegOpenKeyEx
= winreg
.OpenKeyEx
32 RegEnumKey
= winreg
.EnumKey
33 RegEnumValue
= winreg
.EnumValue
34 RegError
= winreg
.error
44 RegOpenKeyEx
= win32api
.RegOpenKeyEx
45 RegEnumKey
= win32api
.RegEnumKey
46 RegEnumValue
= win32api
.RegEnumValue
47 RegError
= win32api
.error
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."
60 hkey_mod
.HKEY_CURRENT_USER
,
61 hkey_mod
.HKEY_LOCAL_MACHINE
,
62 hkey_mod
.HKEY_CLASSES_ROOT
,
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.",
74 def read_keys(base
, key
):
75 """Return list of registry keys."""
77 handle
= RegOpenKeyEx(base
, key
)
84 k
= RegEnumKey(handle
, i
)
92 def read_values(base
, key
):
93 """Return dict of registry keys and values.
95 All names are converted to lowercase.
98 handle
= RegOpenKeyEx(base
, key
)
105 name
, value
, type = RegEnumValue(handle
, i
)
109 d
[convert_mbcs(name
)] = convert_mbcs(value
)
115 dec
= getattr(s
, "decode", None)
125 def __init__(self
, version
):
127 self
.load_macros(version
)
129 def set_macro(self
, macro
, path
, key
):
131 d
= read_values(base
, path
)
133 self
.macros
["$(%s)" % macro
] = d
[key
]
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")
144 self
.set_macro("FrameworkSDKDir", net
, "sdkinstallrootv1.1")
146 self
.set_macro("FrameworkSDKDir", net
, "sdkinstallroot")
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."""
155 p
= r
"Software\Microsoft\NET Framework Setup\Product"
158 h
= RegOpenKeyEx(base
, p
)
161 key
= RegEnumKey(h
, 0)
162 d
= read_values(base
, r
"{}\{}".format(p
, key
))
163 self
.macros
["$(FrameworkVersion)"] = d
["version"]
166 for k
, v
in self
.macros
.items():
171 def get_build_version():
172 """Return the version of MSVC that was used to build Python.
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.
178 i
= sys
.version
.find(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
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:
191 if majorVersion
>= 6:
192 return majorVersion
+ minorVersion
193 # else we don't know what version of the compiler this is
197 def get_build_architecture():
198 """Return the processor architecture.
200 Possible results are "Intel" or "AMD64".
204 i
= sys
.version
.find(prefix
)
207 j
= sys
.version
.find(")", i
)
208 return sys
.version
[i
+ len(prefix
) : j
]
211 def normalize_and_reduce_paths(paths
):
212 """Return a list of normalized paths with duplicates removed.
214 The current order of paths is maintained.
216 # Paths are normalized so things like: /a and /a/ aren't both preserved.
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
)
226 class MSVCCompiler(CCompiler
):
227 """Concrete class that implements an interface to Microsoft Visual C++,
228 as defined by the CCompiler abstract class."""
230 compiler_type
= 'msvc'
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.
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']
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'
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":
261 if self
.__version
>= 7:
262 self
.__root
= r
"Software\Microsoft\VisualStudio"
263 self
.__macros
= MacroExpander(self
.__version
)
265 self
.__root
= r
"Software\Microsoft\Devstudio"
266 self
.__product
= "Visual Studio version %s" % self
.__version
268 # Win64. Assume this was built with the platform SDK
269 self
.__product
= "Microsoft SDK compiler %s" % (self
.__version
+ 6)
271 self
.initialized
= False
273 def initialize(self
):
276 "DISTUTILS_USE_SDK" in os
.environ
277 and "MSSdk" in os
.environ
278 and self
.find_exe("cl.exe")
280 # Assume that the SDK set up everything alright; don't try to be
283 self
.linker
= "link.exe"
288 self
.__paths
= self
.get_msvc_paths("path")
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
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')
305 # extend the MSVC path with the current path
307 for p
in os
.environ
['path'].split(';'):
308 self
.__paths
.append(p
)
311 self
.__paths
= normalize_and_reduce_paths(self
.__paths
)
312 os
.environ
['path'] = ";".join(self
.__paths
)
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
= [
328 self
.compile_options
= ['/nologo', '/O2', '/MD', '/W3', '/GS-', '/DNDEBUG']
329 self
.compile_options_debug
= [
339 self
.ldflags_shared
= ['/DLL', '/nologo', '/INCREMENTAL:NO']
340 if self
.__version
>= 7:
341 self
.ldflags_shared_debug
= ['/DLL', '/nologo', '/INCREMENTAL:no', '/DEBUG']
343 self
.ldflags_shared_debug
= [
350 self
.ldflags_static
= ['/nologo']
352 self
.initialized
= True
354 # -- Worker methods ------------------------------------------------
356 def object_filenames(self
, source_filenames
, strip_dir
=0, output_dir
=''):
357 # Copied from ccompiler.py, extended to return .res as 'object'-file
359 if output_dir
is None:
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
370 raise CompileError("Don't know how to compile %s" % src_name
)
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
))
378 obj_names
.append(os
.path
.join(output_dir
, base
+ self
.obj_extension
))
381 def compile( # noqa: C901
392 if not self
.initialized
:
394 compile_info
= self
._setup
_compile
(
395 output_dir
, macros
, include_dirs
, sources
, depends
, extra_postargs
397 macros
, objects
, extra_postargs
, pp_opts
, build
= compile_info
399 compile_opts
= extra_preargs
or []
400 compile_opts
.append('/c')
402 compile_opts
.extend(self
.compile_options_debug
)
404 compile_opts
.extend(self
.compile_options
)
408 src
, ext
= build
[obj
]
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
)
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
424 output_opt
= "/fo" + obj
426 self
.spawn([self
.rc
] + pp_opts
+ [output_opt
] + [input_opt
])
427 except DistutilsExecError
as msg
:
428 raise CompileError(msg
)
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
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
)
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
])
452 except DistutilsExecError
as msg
:
453 raise CompileError(msg
)
456 # how to handle this file?
458 "Don't know how to compile {} to {}".format(src
, obj
)
461 output_opt
= "/Fo" + obj
467 + [input_opt
, output_opt
]
470 except DistutilsExecError
as msg
:
471 raise CompileError(msg
)
475 def create_static_lib(
476 self
, objects
, output_libname
, output_dir
=None, debug
=0, target_lang
=None
478 if not self
.initialized
:
480 (objects
, output_dir
) = self
._fix
_object
_args
(objects
, output_dir
)
481 output_filename
= self
.library_filename(output_libname
, output_dir
=output_dir
)
483 if self
._need
_link
(objects
, output_filename
):
484 lib_args
= objects
+ ['/OUT:' + output_filename
]
486 pass # XXX what goes here?
488 self
.spawn([self
.lib
] + lib_args
)
489 except DistutilsExecError
as msg
:
492 log
.debug("skipping %s (up-to-date)", output_filename
)
494 def link( # noqa: C901
502 runtime_library_dirs
=None,
510 if not self
.initialized
:
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
516 if runtime_library_dirs
:
518 "I don't know what to do with 'runtime_library_dirs': "
519 + str(runtime_library_dirs
)
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
)
526 if self
._need
_link
(objects
, output_filename
):
527 if target_desc
== CCompiler
.EXECUTABLE
:
529 ldflags
= self
.ldflags_shared_debug
[1:]
531 ldflags
= self
.ldflags_shared
[1:]
534 ldflags
= self
.ldflags_shared_debug
536 ldflags
= self
.ldflags_shared
539 for sym
in export_symbols
or []:
540 export_opts
.append("/EXPORT:" + sym
)
543 ldflags
+ lib_opts
+ export_opts
+ objects
+ ['/OUT:' + output_filename
]
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
)
555 implib_file
= os
.path
.join(
556 os
.path
.dirname(objects
[0]), self
.library_filename(dll_name
)
558 ld_args
.append('/IMPLIB:' + implib_file
)
561 ld_args
[:0] = extra_preargs
563 ld_args
.extend(extra_postargs
)
565 self
.mkpath(os
.path
.dirname(output_filename
))
567 self
.spawn([self
.linker
] + ld_args
)
568 except DistutilsExecError
as msg
:
572 log
.debug("skipping %s (up-to-date)", output_filename
)
574 # -- Miscellaneous methods -----------------------------------------
575 # These are all used by the 'gen_lib_options() function, in
578 def library_dir_option(self
, dir):
579 return "/LIBPATH:" + dir
581 def runtime_library_dir_option(self
, dir):
582 raise DistutilsPlatformError(
583 "don't know how to set runtime library search path for MSVC++"
586 def library_option(self
, lib
):
587 return self
.library_filename(lib
)
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.
593 try_names
= [lib
+ "_d", lib
]
597 for name
in try_names
:
598 libfile
= os
.path
.join(dir, self
.library_filename(name
))
599 if os
.path
.exists(libfile
):
602 # Oops, didn't find it in *any* of 'dirs'
605 # Helper methods for using the MSVC registry settings
607 def find_exe(self
, exe
):
608 """Return path to an MSVC executable program.
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'.
616 for p
in self
.__paths
:
617 fn
= os
.path
.join(os
.path
.abspath(p
), exe
)
618 if os
.path
.isfile(fn
):
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
):
629 def get_msvc_paths(self
, path
, platform
='x86'):
630 """Get a list of devstudio directories (include, lib or path).
632 Return a list of strings. The list will be empty if unable to
633 access the registry or appropriate registry keys not found.
635 if not _can_read_reg
:
638 path
= path
+ " dirs"
639 if self
.__version
>= 7:
640 key
= r
"{}\{:0.1f}\VC\VC_OBJECTS_PLATFORM_INFO\Win32\Directories".format(
646 r
"%s\6.0\Build System\Components\Platforms"
647 r
"\Win32 (%s)\Directories" % (self
.__root
, platform
)
651 d
= read_values(base
, key
)
653 if self
.__version
>= 7:
654 return self
.__macros
.sub(d
[path
]).split(";")
656 return d
[path
].split(";")
657 # MSVC 6 seems to create the registry entries we need only when
659 if self
.__version
== 6:
661 if read_values(base
, r
"%s\6.0" % self
.__root
) is not None:
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."
671 def set_path_env_var(self
, name
):
672 """Set environment variable 'name' to an MSVC path type value.
674 This is equivalent to a SET command prior to execution of spawned
679 p
= self
.get_msvc_paths("library")
681 p
= self
.get_msvc_paths(name
)
683 os
.environ
[name
] = ';'.join(p
)
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
691 # get_build_architecture not really relevant now we support cross-compile
692 from distutils
.msvc9compiler
import MacroExpander
# noqa: F811