This commit is contained in:
ton
2024-10-07 10:13:40 +07:00
parent aa1631742f
commit 3a7d696db6
9729 changed files with 1832837 additions and 161742 deletions

View File

@@ -3,24 +3,27 @@
Contains CCompiler, an abstract base class that defines the interface
for the Distutils compiler abstraction model."""
import sys
import os
import re
import sys
import types
import warnings
from more_itertools import always_iterable
from ._log import log
from ._modified import newer_group
from .dir_util import mkpath
from .errors import (
CompileError,
DistutilsModuleError,
DistutilsPlatformError,
LinkError,
UnknownFileError,
DistutilsPlatformError,
DistutilsModuleError,
)
from .spawn import spawn
from .file_util import move_file
from .dir_util import mkpath
from .dep_util import newer_group
from .util import split_quoted, execute
from ._log import log
from .spawn import spawn
from .util import execute, is_mingw, split_quoted
class CCompiler:
@@ -103,7 +106,7 @@ class CCompiler:
library dirs specific to this compiler class
"""
def __init__(self, verbose=0, dry_run=0, force=0):
def __init__(self, verbose=False, dry_run=False, force=False):
self.dry_run = dry_run
self.force = force
self.verbose = verbose
@@ -168,8 +171,7 @@ class CCompiler:
for key in kwargs:
if key not in self.executables:
raise ValueError(
"unknown executable '%s' for class %s"
% (key, self.__class__.__name__)
f"unknown executable '{key}' for class {self.__class__.__name__}"
)
self.set_executable(key, kwargs[key])
@@ -188,24 +190,28 @@ class CCompiler:
return None
def _check_macro_definitions(self, definitions):
"""Ensures that every element of 'definitions' is a valid macro
definition, ie. either (name,value) 2-tuple or a (name,) tuple. Do
nothing if all definitions are OK, raise TypeError otherwise.
"""
"""Ensure that every element of 'definitions' is valid."""
for defn in definitions:
if not (
isinstance(defn, tuple)
and (
len(defn) in (1, 2)
and (isinstance(defn[1], str) or defn[1] is None)
)
and isinstance(defn[0], str)
):
raise TypeError(
("invalid macro definition '%s': " % defn)
+ "must be tuple (string,), (string, string), or "
+ "(string, None)"
)
self._check_macro_definition(*defn)
def _check_macro_definition(self, defn):
"""
Raise a TypeError if defn is not valid.
A valid definition is either a (name, value) 2-tuple or a (name,) tuple.
"""
if not isinstance(defn, tuple) or not self._is_valid_macro(*defn):
raise TypeError(
f"invalid macro definition '{defn}': "
"must be tuple (string,), (string, string), or (string, None)"
)
@staticmethod
def _is_valid_macro(name, value=None):
"""
A valid macro is a ``name : str`` and a ``value : str | None``.
"""
return isinstance(name, str) and isinstance(value, (str, types.NoneType))
# -- Bookkeeping methods -------------------------------------------
@@ -342,7 +348,7 @@ class CCompiler:
extra = []
# Get the list of expected output (object) files
objects = self.object_filenames(sources, strip_dir=0, output_dir=outdir)
objects = self.object_filenames(sources, strip_dir=False, output_dir=outdir)
assert len(objects) == len(sources)
pp_opts = gen_preprocess_options(macros, incdirs)
@@ -382,7 +388,7 @@ class CCompiler:
raise TypeError("'output_dir' must be a string or None")
if macros is None:
macros = self.macros
macros = list(self.macros)
elif isinstance(macros, list):
macros = macros + (self.macros or [])
else:
@@ -441,14 +447,14 @@ class CCompiler:
fixed versions of all arguments.
"""
if libraries is None:
libraries = self.libraries
libraries = list(self.libraries)
elif isinstance(libraries, (list, tuple)):
libraries = list(libraries) + (self.libraries or [])
else:
raise TypeError("'libraries' (if supplied) must be a list of strings")
if library_dirs is None:
library_dirs = self.library_dirs
library_dirs = list(self.library_dirs)
elif isinstance(library_dirs, (list, tuple)):
library_dirs = list(library_dirs) + (self.library_dirs or [])
else:
@@ -458,14 +464,14 @@ class CCompiler:
library_dirs += self.__class__.library_dirs
if runtime_library_dirs is None:
runtime_library_dirs = self.runtime_library_dirs
runtime_library_dirs = list(self.runtime_library_dirs)
elif isinstance(runtime_library_dirs, (list, tuple)):
runtime_library_dirs = list(runtime_library_dirs) + (
self.runtime_library_dirs or []
)
else:
raise TypeError(
"'runtime_library_dirs' (if supplied) " "must be a list of strings"
"'runtime_library_dirs' (if supplied) must be a list of strings"
)
return (libraries, library_dirs, runtime_library_dirs)
@@ -532,7 +538,7 @@ class CCompiler:
output_dir=None,
macros=None,
include_dirs=None,
debug=0,
debug=False,
extra_preargs=None,
extra_postargs=None,
depends=None,
@@ -609,7 +615,7 @@ class CCompiler:
pass
def create_static_lib(
self, objects, output_libname, output_dir=None, debug=0, target_lang=None
self, objects, output_libname, output_dir=None, debug=False, target_lang=None
):
"""Link a bunch of stuff together to create a static library file.
The "bunch of stuff" consists of the list of object files supplied
@@ -650,7 +656,7 @@ class CCompiler:
library_dirs=None,
runtime_library_dirs=None,
export_symbols=None,
debug=0,
debug=False,
extra_preargs=None,
extra_postargs=None,
build_temp=None,
@@ -712,7 +718,7 @@ class CCompiler:
library_dirs=None,
runtime_library_dirs=None,
export_symbols=None,
debug=0,
debug=False,
extra_preargs=None,
extra_postargs=None,
build_temp=None,
@@ -743,7 +749,7 @@ class CCompiler:
library_dirs=None,
runtime_library_dirs=None,
export_symbols=None,
debug=0,
debug=False,
extra_preargs=None,
extra_postargs=None,
build_temp=None,
@@ -773,7 +779,7 @@ class CCompiler:
libraries=None,
library_dirs=None,
runtime_library_dirs=None,
debug=0,
debug=False,
extra_preargs=None,
extra_postargs=None,
target_lang=None,
@@ -857,10 +863,9 @@ class CCompiler:
if library_dirs is None:
library_dirs = []
fd, fname = tempfile.mkstemp(".c", funcname, text=True)
f = os.fdopen(fd, "w")
try:
with os.fdopen(fd, "w", encoding='utf-8') as f:
for incl in includes:
f.write("""#include "%s"\n""" % incl)
f.write(f"""#include "{incl}"\n""")
if not includes:
# Use "char func(void);" as the prototype to follow
# what autoconf does. This prototype does not match
@@ -870,25 +875,22 @@ class CCompiler:
# know the exact argument types, and the has_function
# interface does not provide that level of information.
f.write(
"""\
f"""\
#ifdef __cplusplus
extern "C"
#endif
char %s(void);
char {funcname}(void);
"""
% funcname
)
f.write(
"""\
int main (int argc, char **argv) {
%s();
f"""\
int main (int argc, char **argv) {{
{funcname}();
return 0;
}
}}
"""
% funcname
)
finally:
f.close()
try:
objects = self.compile([fname], include_dirs=include_dirs)
except CompileError:
@@ -911,7 +913,7 @@ int main (int argc, char **argv) {
os.remove(fn)
return True
def find_library_file(self, dirs, lib, debug=0):
def find_library_file(self, dirs, lib, debug=False):
"""Search the specified list of directories for a static or shared
library file 'lib' and return the full path to that file. If
'debug' true, look for a debugging version (if that makes sense on
@@ -954,7 +956,7 @@ int main (int argc, char **argv) {
# * exe_extension -
# extension for executable files, eg. '' or '.exe'
def object_filenames(self, source_filenames, strip_dir=0, output_dir=''):
def object_filenames(self, source_filenames, strip_dir=False, output_dir=''):
if output_dir is None:
output_dir = ''
return list(
@@ -972,9 +974,7 @@ int main (int argc, char **argv) {
try:
new_ext = self.out_extensions[ext]
except LookupError:
raise UnknownFileError(
"unknown file type '{}' (from '{}')".format(ext, src_name)
)
raise UnknownFileError(f"unknown file type '{ext}' (from '{src_name}')")
if strip_dir:
base = os.path.basename(base)
return os.path.join(output_dir, base + new_ext)
@@ -991,20 +991,24 @@ int main (int argc, char **argv) {
# If abs, chop off leading /
return no_drive[os.path.isabs(no_drive) :]
def shared_object_filename(self, basename, strip_dir=0, output_dir=''):
def shared_object_filename(self, basename, strip_dir=False, output_dir=''):
assert output_dir is not None
if strip_dir:
basename = os.path.basename(basename)
return os.path.join(output_dir, basename + self.shared_lib_extension)
def executable_filename(self, basename, strip_dir=0, output_dir=''):
def executable_filename(self, basename, strip_dir=False, output_dir=''):
assert output_dir is not None
if strip_dir:
basename = os.path.basename(basename)
return os.path.join(output_dir, basename + (self.exe_extension or ''))
def library_filename(
self, libname, lib_type='static', strip_dir=0, output_dir='' # or 'shared'
self,
libname,
lib_type='static',
strip_dir=False,
output_dir='', # or 'shared'
):
assert output_dir is not None
expected = '"static", "shared", "dylib", "xcode_stub"'
@@ -1032,7 +1036,7 @@ int main (int argc, char **argv) {
print(msg)
def warn(self, msg):
sys.stderr.write("warning: %s\n" % msg)
sys.stderr.write(f"warning: {msg}\n")
def execute(self, func, args, msg=None, level=1):
execute(func, args, msg, self.dry_run)
@@ -1056,6 +1060,7 @@ _default_compilers = (
# on a cygwin built python we can use gcc like an ordinary UNIXish
# compiler
('cygwin.*', 'unix'),
('zos', 'zos'),
# OS name mappings
('posix', 'unix'),
('nt', 'msvc'),
@@ -1076,6 +1081,10 @@ def get_default_compiler(osname=None, platform=None):
osname = os.name
if platform is None:
platform = sys.platform
# Mingw is a special case where sys.platform is 'win32' but we
# want to use the 'mingw32' compiler, so check it first
if is_mingw():
return 'mingw32'
for pattern, compiler in _default_compilers:
if (
re.match(pattern, platform) is not None
@@ -1103,6 +1112,7 @@ compiler_class = {
"Mingw32 port of GNU C Compiler for Win32",
),
'bcpp': ('bcppcompiler', 'BCPPCompiler', "Borland C++ Compiler"),
'zos': ('zosccompiler', 'zOSCCompiler', 'IBM XL C/C++ Compilers'),
}
@@ -1115,15 +1125,15 @@ def show_compilers():
# commands that use it.
from distutils.fancy_getopt import FancyGetopt
compilers = []
for compiler in compiler_class.keys():
compilers.append(("compiler=" + compiler, None, compiler_class[compiler][2]))
compilers.sort()
compilers = sorted(
("compiler=" + compiler, None, compiler_class[compiler][2])
for compiler in compiler_class.keys()
)
pretty_printer = FancyGetopt(compilers)
pretty_printer.print_help("List of available compilers:")
def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
def new_compiler(plat=None, compiler=None, verbose=False, dry_run=False, force=False):
"""Generate an instance of some CCompiler subclass for the supplied
platform/compiler combination. 'plat' defaults to 'os.name'
(eg. 'posix', 'nt'), and 'compiler' defaults to the default compiler
@@ -1143,9 +1153,9 @@ def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
(module_name, class_name, long_description) = compiler_class[compiler]
except KeyError:
msg = "don't know how to compile C/C++ code on platform '%s'" % plat
msg = f"don't know how to compile C/C++ code on platform '{plat}'"
if compiler is not None:
msg = msg + " with '%s' compiler" % compiler
msg = msg + f" with '{compiler}' compiler"
raise DistutilsPlatformError(msg)
try:
@@ -1155,12 +1165,12 @@ def new_compiler(plat=None, compiler=None, verbose=0, dry_run=0, force=0):
klass = vars(module)[class_name]
except ImportError:
raise DistutilsModuleError(
"can't compile C/C++ code: unable to load module '%s'" % module_name
f"can't compile C/C++ code: unable to load module '{module_name}'"
)
except KeyError:
raise DistutilsModuleError(
"can't compile C/C++ code: unable to find class '%s' "
"in module '%s'" % (class_name, module_name)
f"can't compile C/C++ code: unable to find class '{class_name}' "
f"in module '{module_name}'"
)
# XXX The None is necessary to preserve backwards compatibility
@@ -1194,23 +1204,22 @@ def gen_preprocess_options(macros, include_dirs):
for macro in macros:
if not (isinstance(macro, tuple) and 1 <= len(macro) <= 2):
raise TypeError(
"bad macro definition '%s': "
"each element of 'macros' list must be a 1- or 2-tuple" % macro
f"bad macro definition '{macro}': "
"each element of 'macros' list must be a 1- or 2-tuple"
)
if len(macro) == 1: # undefine this macro
pp_opts.append("-U%s" % macro[0])
pp_opts.append(f"-U{macro[0]}")
elif len(macro) == 2:
if macro[1] is None: # define with no explicit value
pp_opts.append("-D%s" % macro[0])
pp_opts.append(f"-D{macro[0]}")
else:
# XXX *don't* need to be clever about quoting the
# macro value here, because we're going to avoid the
# shell at all costs when we spawn the command!
pp_opts.append("-D%s=%s" % macro)
pp_opts.append("-D{}={}".format(*macro))
for dir in include_dirs:
pp_opts.append("-I%s" % dir)
pp_opts.extend(f"-I{dir}" for dir in include_dirs)
return pp_opts
@@ -1221,17 +1230,10 @@ def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
directories. Returns a list of command-line options suitable for use
with some compiler (depending on the two format strings passed in).
"""
lib_opts = []
for dir in library_dirs:
lib_opts.append(compiler.library_dir_option(dir))
lib_opts = [compiler.library_dir_option(dir) for dir in library_dirs]
for dir in runtime_library_dirs:
opt = compiler.runtime_library_dir_option(dir)
if isinstance(opt, list):
lib_opts = lib_opts + opt
else:
lib_opts.append(opt)
lib_opts.extend(always_iterable(compiler.runtime_library_dir_option(dir)))
# XXX it's important that we *not* remove redundant library mentions!
# sometimes you really do have to say "-lfoo -lbar -lfoo" in order to
@@ -1247,7 +1249,7 @@ def gen_lib_options(compiler, library_dirs, runtime_library_dirs, libraries):
lib_opts.append(lib_file)
else:
compiler.warn(
"no library file corresponding to " "'%s' found (skipping)" % lib
f"no library file corresponding to '{lib}' found (skipping)"
)
else:
lib_opts.append(compiler.library_option(lib))