Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ca066bd

Browse filesBrowse files
gh-81057: Vendor a Subset of distutils for the c-analyzer Tool (gh-102505)
distutils was removed in November. However, the c-analyzer relies on it. To solve that here, we vendor the parts the tool needs so it can be run against 3.12+. (Also see gh-92584.) Note that we may end up removing this code later in favor of a solution in common with the peg_generator tool (which also relies on distutils). At the least, the copy here makes sure the c-analyzer tool works on 3.12+ in the meantime.
1 parent cf6e7c5 commit ca066bd
Copy full SHA for ca066bd

File tree

Expand file treeCollapse file tree

15 files changed

+2301
-0
lines changed
Filter options
Expand file treeCollapse file tree

15 files changed

+2301
-0
lines changed

‎Tools/c-analyzer/distutils/README

Copy file name to clipboard
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
This is a partial copy of distutils as it was removed in 0faa0ba240e.
2+
It only includes the parts needed by the C parser.

‎Tools/c-analyzer/distutils/__init__.py

Copy file name to clipboardExpand all lines: Tools/c-analyzer/distutils/__init__.py
Whitespace-only changes.
+203Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
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 DistutilsPlatformError
21+
from distutils.ccompiler import CCompiler
22+
from distutils import log
23+
24+
from itertools import count
25+
26+
def _find_vc2015():
27+
try:
28+
key = winreg.OpenKeyEx(
29+
winreg.HKEY_LOCAL_MACHINE,
30+
r"Software\Microsoft\VisualStudio\SxS\VC7",
31+
access=winreg.KEY_READ | winreg.KEY_WOW64_32KEY
32+
)
33+
except OSError:
34+
log.debug("Visual C++ is not registered")
35+
return None, None
36+
37+
best_version = 0
38+
best_dir = None
39+
with key:
40+
for i in count():
41+
try:
42+
v, vc_dir, vt = winreg.EnumValue(key, i)
43+
except OSError:
44+
break
45+
if v and vt == winreg.REG_SZ and os.path.isdir(vc_dir):
46+
try:
47+
version = int(float(v))
48+
except (ValueError, TypeError):
49+
continue
50+
if version >= 14 and version > best_version:
51+
best_version, best_dir = version, vc_dir
52+
return best_version, best_dir
53+
54+
def _find_vc2017():
55+
"""Returns "15, path" based on the result of invoking vswhere.exe
56+
If no install is found, returns "None, None"
57+
58+
The version is returned to avoid unnecessarily changing the function
59+
result. It may be ignored when the path is not None.
60+
61+
If vswhere.exe is not available, by definition, VS 2017 is not
62+
installed.
63+
"""
64+
root = os.environ.get("ProgramFiles(x86)") or os.environ.get("ProgramFiles")
65+
if not root:
66+
return None, None
67+
68+
try:
69+
path = subprocess.check_output([
70+
os.path.join(root, "Microsoft Visual Studio", "Installer", "vswhere.exe"),
71+
"-latest",
72+
"-prerelease",
73+
"-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64",
74+
"-property", "installationPath",
75+
"-products", "*",
76+
], encoding="mbcs", errors="strict").strip()
77+
except (subprocess.CalledProcessError, OSError, UnicodeDecodeError):
78+
return None, None
79+
80+
path = os.path.join(path, "VC", "Auxiliary", "Build")
81+
if os.path.isdir(path):
82+
return 15, path
83+
84+
return None, None
85+
86+
PLAT_SPEC_TO_RUNTIME = {
87+
'x86' : 'x86',
88+
'x86_amd64' : 'x64',
89+
'x86_arm' : 'arm',
90+
'x86_arm64' : 'arm64'
91+
}
92+
93+
def _find_vcvarsall(plat_spec):
94+
# bpo-38597: Removed vcruntime return value
95+
_, best_dir = _find_vc2017()
96+
97+
if not best_dir:
98+
best_version, best_dir = _find_vc2015()
99+
100+
if not best_dir:
101+
log.debug("No suitable Visual C++ version found")
102+
return None, None
103+
104+
vcvarsall = os.path.join(best_dir, "vcvarsall.bat")
105+
if not os.path.isfile(vcvarsall):
106+
log.debug("%s cannot be found", vcvarsall)
107+
return None, None
108+
109+
return vcvarsall, None
110+
111+
def _get_vc_env(plat_spec):
112+
if os.getenv("DISTUTILS_USE_SDK"):
113+
return {
114+
key.lower(): value
115+
for key, value in os.environ.items()
116+
}
117+
118+
vcvarsall, _ = _find_vcvarsall(plat_spec)
119+
if not vcvarsall:
120+
raise DistutilsPlatformError("Unable to find vcvarsall.bat")
121+
122+
try:
123+
out = subprocess.check_output(
124+
'cmd /u /c "{}" {} && set'.format(vcvarsall, plat_spec),
125+
stderr=subprocess.STDOUT,
126+
).decode('utf-16le', errors='replace')
127+
except subprocess.CalledProcessError as exc:
128+
log.error(exc.output)
129+
raise DistutilsPlatformError("Error executing {}"
130+
.format(exc.cmd))
131+
132+
env = {
133+
key.lower(): value
134+
for key, _, value in
135+
(line.partition('=') for line in out.splitlines())
136+
if key and value
137+
}
138+
139+
return env
140+
141+
def _find_exe(exe, paths=None):
142+
"""Return path to an MSVC executable program.
143+
144+
Tries to find the program in several places: first, one of the
145+
MSVC program search paths from the registry; next, the directories
146+
in the PATH environment variable. If any of those work, return an
147+
absolute path that is known to exist. If none of them work, just
148+
return the original program name, 'exe'.
149+
"""
150+
if not paths:
151+
paths = os.getenv('path').split(os.pathsep)
152+
for p in paths:
153+
fn = os.path.join(os.path.abspath(p), exe)
154+
if os.path.isfile(fn):
155+
return fn
156+
return exe
157+
158+
# A map keyed by get_platform() return values to values accepted by
159+
# 'vcvarsall.bat'. Always cross-compile from x86 to work with the
160+
# lighter-weight MSVC installs that do not include native 64-bit tools.
161+
PLAT_TO_VCVARS = {
162+
'win32' : 'x86',
163+
'win-amd64' : 'x86_amd64',
164+
'win-arm32' : 'x86_arm',
165+
'win-arm64' : 'x86_arm64'
166+
}
167+
168+
class MSVCCompiler(CCompiler) :
169+
"""Concrete class that implements an interface to Microsoft Visual C++,
170+
as defined by the CCompiler abstract class."""
171+
172+
compiler_type = 'msvc'
173+
174+
# Just set this so CCompiler's constructor doesn't barf. We currently
175+
# don't use the 'set_executables()' bureaucracy provided by CCompiler,
176+
# as it really isn't necessary for this sort of single-compiler class.
177+
# Would be nice to have a consistent interface with UnixCCompiler,
178+
# though, so it's worth thinking about.
179+
executables = {}
180+
181+
# Private class data (need to distinguish C from C++ source for compiler)
182+
_c_extensions = ['.c']
183+
_cpp_extensions = ['.cc', '.cpp', '.cxx']
184+
_rc_extensions = ['.rc']
185+
_mc_extensions = ['.mc']
186+
187+
# Needed for the filename generation methods provided by the
188+
# base class, CCompiler.
189+
src_extensions = (_c_extensions + _cpp_extensions +
190+
_rc_extensions + _mc_extensions)
191+
res_extension = '.res'
192+
obj_extension = '.obj'
193+
static_lib_extension = '.lib'
194+
shared_lib_extension = '.dll'
195+
static_lib_format = shared_lib_format = '%s%s'
196+
exe_extension = '.exe'
197+
198+
199+
def __init__(self, verbose=0, dry_run=0, force=0):
200+
CCompiler.__init__ (self, verbose, dry_run, force)
201+
# target platform (.plat_name is consistent with 'bdist')
202+
self.plat_name = None
203+
self.initialized = False
+109Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
"""distutils.bcppcompiler
2+
3+
Contains BorlandCCompiler, an implementation of the abstract CCompiler class
4+
for the Borland C++ compiler.
5+
"""
6+
7+
# This implementation by Lyle Johnson, based on the original msvccompiler.py
8+
# module and using the directions originally published by Gordon Williams.
9+
10+
# XXX looks like there's a LOT of overlap between these two classes:
11+
# someone should sit down and factor out the common code as
12+
# WindowsCCompiler! --GPW
13+
14+
15+
import os
16+
from distutils.errors import DistutilsExecError, CompileError
17+
from distutils.ccompiler import \
18+
CCompiler, gen_preprocess_options
19+
from distutils.dep_util import newer
20+
21+
class BCPPCompiler(CCompiler) :
22+
"""Concrete class that implements an interface to the Borland C/C++
23+
compiler, as defined by the CCompiler abstract class.
24+
"""
25+
26+
compiler_type = 'bcpp'
27+
28+
# Just set this so CCompiler's constructor doesn't barf. We currently
29+
# don't use the 'set_executables()' bureaucracy provided by CCompiler,
30+
# as it really isn't necessary for this sort of single-compiler class.
31+
# Would be nice to have a consistent interface with UnixCCompiler,
32+
# though, so it's worth thinking about.
33+
executables = {}
34+
35+
# Private class data (need to distinguish C from C++ source for compiler)
36+
_c_extensions = ['.c']
37+
_cpp_extensions = ['.cc', '.cpp', '.cxx']
38+
39+
# Needed for the filename generation methods provided by the
40+
# base class, CCompiler.
41+
src_extensions = _c_extensions + _cpp_extensions
42+
obj_extension = '.obj'
43+
static_lib_extension = '.lib'
44+
shared_lib_extension = '.dll'
45+
static_lib_format = shared_lib_format = '%s%s'
46+
exe_extension = '.exe'
47+
48+
49+
def __init__ (self,
50+
verbose=0,
51+
dry_run=0,
52+
force=0):
53+
54+
CCompiler.__init__ (self, verbose, dry_run, force)
55+
56+
# These executables are assumed to all be in the path.
57+
# Borland doesn't seem to use any special registry settings to
58+
# indicate their installation locations.
59+
60+
self.cc = "bcc32.exe"
61+
self.linker = "ilink32.exe"
62+
self.lib = "tlib.exe"
63+
64+
self.preprocess_options = None
65+
self.compile_options = ['/tWM', '/O2', '/q', '/g0']
66+
self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0']
67+
68+
self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x']
69+
self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']
70+
self.ldflags_static = []
71+
self.ldflags_exe = ['/Gn', '/q', '/x']
72+
self.ldflags_exe_debug = ['/Gn', '/q', '/x','/r']
73+
74+
75+
# -- Worker methods ------------------------------------------------
76+
77+
def preprocess (self,
78+
source,
79+
output_file=None,
80+
macros=None,
81+
include_dirs=None,
82+
extra_preargs=None,
83+
extra_postargs=None):
84+
85+
(_, macros, include_dirs) = \
86+
self._fix_compile_args(None, macros, include_dirs)
87+
pp_opts = gen_preprocess_options(macros, include_dirs)
88+
pp_args = ['cpp32.exe'] + pp_opts
89+
if output_file is not None:
90+
pp_args.append('-o' + output_file)
91+
if extra_preargs:
92+
pp_args[:0] = extra_preargs
93+
if extra_postargs:
94+
pp_args.extend(extra_postargs)
95+
pp_args.append(source)
96+
97+
# We need to preprocess: either we're being forced to, or the
98+
# source file is newer than the target (or the target doesn't
99+
# exist).
100+
if self.force or output_file is None or newer(source, output_file):
101+
if output_file:
102+
self.mkpath(os.path.dirname(output_file))
103+
try:
104+
self.spawn(pp_args)
105+
except DistutilsExecError as msg:
106+
print(msg)
107+
raise CompileError(msg)
108+
109+
# preprocess()

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.