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