Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
keewenaw
GitHub Repository: keewenaw/ethereum-wallet-cracker
Path: blob/main/test/lib/python3.9/site-packages/setuptools/_distutils/_msvccompiler.py
4799 views
1
"""distutils._msvccompiler
2
3
Contains MSVCCompiler, an implementation of the abstract CCompiler class
4
for Microsoft Visual Studio 2015.
5
6
The module is compatible with VS 2015 and later. You can find legacy support
7
for older versions in distutils.msvc9compiler and 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 VS 2005 and VS 2008 by Christian Heimes
14
# ported to VS 2015 by Steve Dower
15
16
import os
17
import subprocess
18
import contextlib
19
import warnings
20
import unittest.mock
21
with contextlib.suppress(ImportError):
22
import winreg
23
24
from distutils.errors import DistutilsExecError, DistutilsPlatformError, \
25
CompileError, LibError, LinkError
26
from distutils.ccompiler import CCompiler, gen_lib_options
27
from distutils import log
28
from distutils.util import get_platform
29
30
from itertools import count
31
32
def _find_vc2015():
33
try:
34
key = winreg.OpenKeyEx(
35
winreg.HKEY_LOCAL_MACHINE,
36
r"Software\Microsoft\VisualStudio\SxS\VC7",
37
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
38
)
39
except OSError:
40
log.debug("Visual C++ is not registered")
41
return None, None
42
43
best_version = 0
44
best_dir = None
45
with key:
46
for i in count():
47
try:
48
v, vc_dir, vt = winreg.EnumValue(key, i)
49
except OSError:
50
break
51
if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
52
try:
53
version = int(float(v))
54
except (ValueError, TypeError):
55
continue
56
if version >= 14 and version > best_version:
57
best_version, best_dir = version, vc_dir
58
return best_version, best_dir
59
60
def _find_vc2017():
61
"""Returns "15, path" based on the result of invoking vswhere.exe
62
If no install is found, returns "None, None"
63
64
The version is returned to avoid unnecessarily changing the function
65
result. It may be ignored when the path is not None.
66
67
If vswhere.exe is not available, by definition, VS 2017 is not
68
installed.
69
"""
70
root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
71
if not root:
72
return None, None
73
74
try:
75
path = subprocess.check_output([
76
os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
77
"-latest",
78
"-prerelease",
79
"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
80
"-property", "installationPath",
81
"-products", "*",
82
], encoding="mbcs", errors="strict").strip()
83
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
84
return None, None
85
86
path = os.path.join(path, "VC", "Auxiliary", "Build")
87
if os.path.isdir(path):
88
return 15, path
89
90
return None, None
91
92
PLAT_SPEC_TO_RUNTIME = {
93
'x86' : 'x86',
94
'x86_amd64' : 'x64',
95
'x86_arm' : 'arm',
96
'x86_arm64' : 'arm64'
97
}
98
99
def _find_vcvarsall(plat_spec):
100
# bpo-38597: Removed vcruntime return value
101
_, best_dir = _find_vc2017()
102
103
if not best_dir:
104
best_version, best_dir = _find_vc2015()
105
106
if not best_dir:
107
log.debug("No suitable Visual C++ version found")
108
return None, None
109
110
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
111
if not os.path.isfile(vcvarsall):
112
log.debug("%s cannot be found", vcvarsall)
113
return None, None
114
115
return vcvarsall, None
116
117
def _get_vc_env(plat_spec):
118
if os.getenv("DISTUTILS_USE_SDK"):
119
return {
120
key.lower(): value
121
for key, value in os.environ.items()
122
}
123
124
vcvarsall, _ = _find_vcvarsall(plat_spec)
125
if not vcvarsall:
126
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
127
128
try:
129
out = subprocess.check_output(
130
'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
131
stderr=subprocess.STDOUT,
132
).decode('utf-16le', errors='replace')
133
except subprocess.CalledProcessError as exc:
134
log.error(exc.output)
135
raise DistutilsPlatformError("Error executing {}"
136
.format(exc.cmd))
137
138
env = {
139
key.lower(): value
140
for key, _, value in
141
(line.partition('=') for line in out.splitlines())
142
if key and value
143
}
144
145
return env
146
147
def _find_exe(exe, paths=None):
148
"""Return path to an MSVC executable program.
149
150
Tries to find the program in several places: first, one of the
151
MSVC program search paths from the registry; next, the directories
152
in the PATH environment variable. If any of those work, return an
153
absolute path that is known to exist. If none of them work, just
154
return the original program name, 'exe'.
155
"""
156
if not paths:
157
paths = os.getenv('path').split(os.pathsep)
158
for p in paths:
159
fn = os.path.join(os.path.abspath(p), exe)
160
if os.path.isfile(fn):
161
return fn
162
return exe
163
164
# A map keyed by get_platform() return values to values accepted by
165
# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
166
# lighter-weight MSVC installs that do not include native 64-bit tools.
167
PLAT_TO_VCVARS = {
168
'win32' : 'x86',
169
'win-amd64' : 'x86_amd64',
170
'win-arm32' : 'x86_arm',
171
'win-arm64' : 'x86_arm64'
172
}
173
174
class MSVCCompiler(CCompiler) :
175
"""Concrete class that implements an interface to Microsoft Visual C++,
176
as defined by the CCompiler abstract class."""
177
178
compiler_type = 'msvc'
179
180
# Just set this so CCompiler's constructor doesn't barf. We currently
181
# don't use the 'set_executables()' bureaucracy provided by CCompiler,
182
# as it really isn't necessary for this sort of single-compiler class.
183
# Would be nice to have a consistent interface with UnixCCompiler,
184
# though, so it's worth thinking about.
185
executables = {}
186
187
# Private class data (need to distinguish C from C++ source for compiler)
188
_c_extensions = ['.c']
189
_cpp_extensions = ['.cc', '.cpp', '.cxx']
190
_rc_extensions = ['.rc']
191
_mc_extensions = ['.mc']
192
193
# Needed for the filename generation methods provided by the
194
# base class, CCompiler.
195
src_extensions = (_c_extensions + _cpp_extensions +
196
_rc_extensions + _mc_extensions)
197
res_extension = '.res'
198
obj_extension = '.obj'
199
static_lib_extension = '.lib'
200
shared_lib_extension = '.dll'
201
static_lib_format = shared_lib_format = '%s%s'
202
exe_extension = '.exe'
203
204
205
def __init__(self, verbose=0, dry_run=0, force=0):
206
super().__init__(verbose, dry_run, force)
207
# target platform (.plat_name is consistent with 'bdist')
208
self.plat_name = None
209
self.initialized = False
210
211
def initialize(self, plat_name=None):
212
# multi-init means we would need to check platform same each time...
213
assert not self.initialized, "don't init multiple times"
214
if plat_name is None:
215
plat_name = get_platform()
216
# sanity check for platforms to prevent obscure errors later.
217
if plat_name not in PLAT_TO_VCVARS:
218
raise DistutilsPlatformError("--plat-name must be one of {}"
219
.format(tuple(PLAT_TO_VCVARS)))
220
221
# Get the vcvarsall.bat spec for the requested platform.
222
plat_spec = PLAT_TO_VCVARS[plat_name]
223
224
vc_env = _get_vc_env(plat_spec)
225
if not vc_env:
226
raise DistutilsPlatformError("Unable to find a compatible "
227
"Visual Studio installation.")
228
229
self._paths = vc_env.get('path', '')
230
paths = self._paths.split(os.pathsep)
231
self.cc = _find_exe("cl.exe", paths)
232
self.linker = _find_exe("link.exe", paths)
233
self.lib = _find_exe("lib.exe", paths)
234
self.rc = _find_exe("rc.exe", paths) # resource compiler
235
self.mc = _find_exe("mc.exe", paths) # message compiler
236
self.mt = _find_exe("mt.exe", paths) # message compiler
237
238
for dir in vc_env.get('include', '').split(os.pathsep):
239
if dir:
240
self.add_include_dir(dir.rstrip(os.sep))
241
242
for dir in vc_env.get('lib', '').split(os.pathsep):
243
if dir:
244
self.add_library_dir(dir.rstrip(os.sep))
245
246
self.preprocess_options = None
247
# bpo-38597: Always compile with dynamic linking
248
# Future releases of Python 3.x will include all past
249
# versions of vcruntime*.dll for compatibility.
250
self.compile_options = [
251
'/nologo', '/O2', '/W3', '/GL', '/DNDEBUG', '/MD'
252
]
253
254
self.compile_options_debug = [
255
'/nologo', '/Od', '/MDd', '/Zi', '/W3', '/D_DEBUG'
256
]
257
258
ldflags = [
259
'/nologo', '/INCREMENTAL:NO', '/LTCG'
260
]
261
262
ldflags_debug = [
263
'/nologo', '/INCREMENTAL:NO', '/LTCG', '/DEBUG:FULL'
264
]
265
266
self.ldflags_exe = [*ldflags, '/MANIFEST:EMBED,ID=1']
267
self.ldflags_exe_debug = [*ldflags_debug, '/MANIFEST:EMBED,ID=1']
268
self.ldflags_shared = [*ldflags, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
269
self.ldflags_shared_debug = [*ldflags_debug, '/DLL', '/MANIFEST:EMBED,ID=2', '/MANIFESTUAC:NO']
270
self.ldflags_static = [*ldflags]
271
self.ldflags_static_debug = [*ldflags_debug]
272
273
self._ldflags = {
274
(CCompiler.EXECUTABLE, None): self.ldflags_exe,
275
(CCompiler.EXECUTABLE, False): self.ldflags_exe,
276
(CCompiler.EXECUTABLE, True): self.ldflags_exe_debug,
277
(CCompiler.SHARED_OBJECT, None): self.ldflags_shared,
278
(CCompiler.SHARED_OBJECT, False): self.ldflags_shared,
279
(CCompiler.SHARED_OBJECT, True): self.ldflags_shared_debug,
280
(CCompiler.SHARED_LIBRARY, None): self.ldflags_static,
281
(CCompiler.SHARED_LIBRARY, False): self.ldflags_static,
282
(CCompiler.SHARED_LIBRARY, True): self.ldflags_static_debug,
283
}
284
285
self.initialized = True
286
287
# -- Worker methods ------------------------------------------------
288
289
def object_filenames(self,
290
source_filenames,
291
strip_dir=0,
292
output_dir=''):
293
ext_map = {
294
**{ext: self.obj_extension for ext in self.src_extensions},
295
**{ext: self.res_extension for ext in self._rc_extensions + self._mc_extensions},
296
}
297
298
output_dir = output_dir or ''
299
300
def make_out_path(p):
301
base, ext = os.path.splitext(p)
302
if strip_dir:
303
base = os.path.basename(base)
304
else:
305
_, base = os.path.splitdrive(base)
306
if base.startswith((os.path.sep, os.path.altsep)):
307
base = base[1:]
308
try:
309
# XXX: This may produce absurdly long paths. We should check
310
# the length of the result and trim base until we fit within
311
# 260 characters.
312
return os.path.join(output_dir, base + ext_map[ext])
313
except LookupError:
314
# Better to raise an exception instead of silently continuing
315
# and later complain about sources and targets having
316
# different lengths
317
raise CompileError("Don't know how to compile {}".format(p))
318
319
return list(map(make_out_path, source_filenames))
320
321
322
def compile(self, sources,
323
output_dir=None, macros=None, include_dirs=None, debug=0,
324
extra_preargs=None, extra_postargs=None, depends=None):
325
326
if not self.initialized:
327
self.initialize()
328
compile_info = self._setup_compile(output_dir, macros, include_dirs,
329
sources, depends, extra_postargs)
330
macros, objects, extra_postargs, pp_opts, build = compile_info
331
332
compile_opts = extra_preargs or []
333
compile_opts.append('/c')
334
if debug:
335
compile_opts.extend(self.compile_options_debug)
336
else:
337
compile_opts.extend(self.compile_options)
338
339
340
add_cpp_opts = False
341
342
for obj in objects:
343
try:
344
src, ext = build[obj]
345
except KeyError:
346
continue
347
if debug:
348
# pass the full pathname to MSVC in debug mode,
349
# this allows the debugger to find the source file
350
# without asking the user to browse for it
351
src = os.path.abspath(src)
352
353
if ext in self._c_extensions:
354
input_opt = "/Tc" + src
355
elif ext in self._cpp_extensions:
356
input_opt = "/Tp" + src
357
add_cpp_opts = True
358
elif ext in self._rc_extensions:
359
# compile .RC to .RES file
360
input_opt = src
361
output_opt = "/fo" + obj
362
try:
363
self.spawn([self.rc] + pp_opts + [output_opt, input_opt])
364
except DistutilsExecError as msg:
365
raise CompileError(msg)
366
continue
367
elif ext in self._mc_extensions:
368
# Compile .MC to .RC file to .RES file.
369
# * '-h dir' specifies the directory for the
370
# generated include file
371
# * '-r dir' specifies the target directory of the
372
# generated RC file and the binary message resource
373
# it includes
374
#
375
# For now (since there are no options to change this),
376
# we use the source-directory for the include file and
377
# the build directory for the RC file and message
378
# resources. This works at least for win32all.
379
h_dir = os.path.dirname(src)
380
rc_dir = os.path.dirname(obj)
381
try:
382
# first compile .MC to .RC and .H file
383
self.spawn([self.mc, '-h', h_dir, '-r', rc_dir, src])
384
base, _ = os.path.splitext(os.path.basename (src))
385
rc_file = os.path.join(rc_dir, base + '.rc')
386
# then compile .RC to .RES file
387
self.spawn([self.rc, "/fo" + obj, rc_file])
388
389
except DistutilsExecError as msg:
390
raise CompileError(msg)
391
continue
392
else:
393
# how to handle this file?
394
raise CompileError("Don't know how to compile {} to {}"
395
.format(src, obj))
396
397
args = [self.cc] + compile_opts + pp_opts
398
if add_cpp_opts:
399
args.append('/EHsc')
400
args.append(input_opt)
401
args.append("/Fo" + obj)
402
args.extend(extra_postargs)
403
404
try:
405
self.spawn(args)
406
except DistutilsExecError as msg:
407
raise CompileError(msg)
408
409
return objects
410
411
412
def create_static_lib(self,
413
objects,
414
output_libname,
415
output_dir=None,
416
debug=0,
417
target_lang=None):
418
419
if not self.initialized:
420
self.initialize()
421
objects, output_dir = self._fix_object_args(objects, output_dir)
422
output_filename = self.library_filename(output_libname,
423
output_dir=output_dir)
424
425
if self._need_link(objects, output_filename):
426
lib_args = objects + ['/OUT:' + output_filename]
427
if debug:
428
pass # XXX what goes here?
429
try:
430
log.debug('Executing "%s" %s', self.lib, ' '.join(lib_args))
431
self.spawn([self.lib] + lib_args)
432
except DistutilsExecError as msg:
433
raise LibError(msg)
434
else:
435
log.debug("skipping %s (up-to-date)", output_filename)
436
437
438
def link(self,
439
target_desc,
440
objects,
441
output_filename,
442
output_dir=None,
443
libraries=None,
444
library_dirs=None,
445
runtime_library_dirs=None,
446
export_symbols=None,
447
debug=0,
448
extra_preargs=None,
449
extra_postargs=None,
450
build_temp=None,
451
target_lang=None):
452
453
if not self.initialized:
454
self.initialize()
455
objects, output_dir = self._fix_object_args(objects, output_dir)
456
fixed_args = self._fix_lib_args(libraries, library_dirs,
457
runtime_library_dirs)
458
libraries, library_dirs, runtime_library_dirs = fixed_args
459
460
if runtime_library_dirs:
461
self.warn("I don't know what to do with 'runtime_library_dirs': "
462
+ str(runtime_library_dirs))
463
464
lib_opts = gen_lib_options(self,
465
library_dirs, runtime_library_dirs,
466
libraries)
467
if output_dir is not None:
468
output_filename = os.path.join(output_dir, output_filename)
469
470
if self._need_link(objects, output_filename):
471
ldflags = self._ldflags[target_desc, debug]
472
473
export_opts = ["/EXPORT:" + sym for sym in (export_symbols or [])]
474
475
ld_args = (ldflags + lib_opts + export_opts +
476
objects + ['/OUT:' + output_filename])
477
478
# The MSVC linker generates .lib and .exp files, which cannot be
479
# suppressed by any linker switches. The .lib files may even be
480
# needed! Make sure they are generated in the temporary build
481
# directory. Since they have different names for debug and release
482
# builds, they can go into the same directory.
483
build_temp = os.path.dirname(objects[0])
484
if export_symbols is not None:
485
(dll_name, dll_ext) = os.path.splitext(
486
os.path.basename(output_filename))
487
implib_file = os.path.join(
488
build_temp,
489
self.library_filename(dll_name))
490
ld_args.append ('/IMPLIB:' + implib_file)
491
492
if extra_preargs:
493
ld_args[:0] = extra_preargs
494
if extra_postargs:
495
ld_args.extend(extra_postargs)
496
497
output_dir = os.path.dirname(os.path.abspath(output_filename))
498
self.mkpath(output_dir)
499
try:
500
log.debug('Executing "%s" %s', self.linker, ' '.join(ld_args))
501
self.spawn([self.linker] + ld_args)
502
except DistutilsExecError as msg:
503
raise LinkError(msg)
504
else:
505
log.debug("skipping %s (up-to-date)", output_filename)
506
507
def spawn(self, cmd):
508
env = dict(os.environ, PATH=self._paths)
509
with self._fallback_spawn(cmd, env) as fallback:
510
return super().spawn(cmd, env=env)
511
return fallback.value
512
513
@contextlib.contextmanager
514
def _fallback_spawn(self, cmd, env):
515
"""
516
Discovered in pypa/distutils#15, some tools monkeypatch the compiler,
517
so the 'env' kwarg causes a TypeError. Detect this condition and
518
restore the legacy, unsafe behavior.
519
"""
520
bag = type('Bag', (), {})()
521
try:
522
yield bag
523
except TypeError as exc:
524
if "unexpected keyword argument 'env'" not in str(exc):
525
raise
526
else:
527
return
528
warnings.warn(
529
"Fallback spawn triggered. Please update distutils monkeypatch.")
530
with unittest.mock.patch.dict('os.environ', env):
531
bag.value = super().spawn(cmd)
532
533
# -- Miscellaneous methods -----------------------------------------
534
# These are all used by the 'gen_lib_options() function, in
535
# ccompiler.py.
536
537
def library_dir_option(self, dir):
538
return "/LIBPATH:" + dir
539
540
def runtime_library_dir_option(self, dir):
541
raise DistutilsPlatformError(
542
"don't know how to set runtime library search path for MSVC")
543
544
def library_option(self, lib):
545
return self.library_filename(lib)
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.isfile(libfile):
558
return libfile
559
else:
560
# Oops, didn't find it in *any* of 'dirs'
561
return None
562
563