1# Autodetecting setup.py script for building the Python extensions
2
3import argparse
4import importlib._bootstrap
5import importlib.machinery
6import importlib.util
7import logging
8import os
9import re
10import shlex
11import sys
12import sysconfig
13import warnings
14from glob import glob, escape
15import _osx_support
16
17
18try:
19    import subprocess
20    del subprocess
21    SUBPROCESS_BOOTSTRAP = False
22except ImportError:
23    # Bootstrap Python: distutils.spawn uses subprocess to build C extensions,
24    # subprocess requires C extensions built by setup.py like _posixsubprocess.
25    #
26    # Use _bootsubprocess which only uses the os module.
27    #
28    # It is dropped from sys.modules as soon as all C extension modules
29    # are built.
30    import _bootsubprocess
31    sys.modules['subprocess'] = _bootsubprocess
32    del _bootsubprocess
33    SUBPROCESS_BOOTSTRAP = True
34
35
36with warnings.catch_warnings():
37    # bpo-41282 (PEP 632) deprecated distutils but setup.py still uses it
38    warnings.filterwarnings(
39        "ignore",
40        "The distutils package is deprecated",
41        DeprecationWarning
42    )
43    warnings.filterwarnings(
44        "ignore",
45        "The distutils.sysconfig module is deprecated, use sysconfig instead",
46        DeprecationWarning
47    )
48
49    from distutils.command.build_ext import build_ext
50    from distutils.command.build_scripts import build_scripts
51    from distutils.command.install import install
52    from distutils.command.install_lib import install_lib
53    from distutils.core import Extension, setup
54    from distutils.errors import CCompilerError, DistutilsError
55    from distutils.spawn import find_executable
56
57
58# This global variable is used to hold the list of modules to be disabled.
59DISABLED_MODULE_LIST = []
60
61# --list-module-names option used by Tools/scripts/generate_module_names.py
62LIST_MODULE_NAMES = False
63
64
65logging.basicConfig(format='%(message)s', level=logging.INFO)
66log = logging.getLogger('setup')
67
68
69def get_platform():
70    # Cross compiling
71    if "_PYTHON_HOST_PLATFORM" in os.environ:
72        return os.environ["_PYTHON_HOST_PLATFORM"]
73
74    # Get value of sys.platform
75    if sys.platform.startswith('osf1'):
76        return 'osf1'
77    return sys.platform
78
79
80CROSS_COMPILING = ("_PYTHON_HOST_PLATFORM" in os.environ)
81HOST_PLATFORM = get_platform()
82MS_WINDOWS = (HOST_PLATFORM == 'win32')
83CYGWIN = (HOST_PLATFORM == 'cygwin')
84MACOS = (HOST_PLATFORM == 'darwin')
85AIX = (HOST_PLATFORM.startswith('aix'))
86VXWORKS = ('vxworks' in HOST_PLATFORM)
87EMSCRIPTEN = HOST_PLATFORM == 'emscripten-wasm32'
88CC = os.environ.get("CC")
89if not CC:
90    CC = sysconfig.get_config_var("CC")
91
92if EMSCRIPTEN:
93    # emcc is a Python script from a different Python interpreter.
94    os.environ.pop("PYTHONPATH", None)
95
96
97SUMMARY = """
98Python is an interpreted, interactive, object-oriented programming
99language. It is often compared to Tcl, Perl, Scheme or Java.
100
101Python combines remarkable power with very clear syntax. It has
102modules, classes, exceptions, very high level dynamic data types, and
103dynamic typing. There are interfaces to many system calls and
104libraries, as well as to various windowing systems (X11, Motif, Tk,
105Mac, MFC). New built-in modules are easily written in C or C++. Python
106is also usable as an extension language for applications that need a
107programmable interface.
108
109The Python implementation is portable: it runs on many brands of UNIX,
110on Windows, DOS, Mac, Amiga... If your favorite system isn't
111listed here, it may still be supported, if there's a C compiler for
112it. Ask around on comp.lang.python -- or just try compiling Python
113yourself.
114"""
115
116CLASSIFIERS = """
117Development Status :: 6 - Mature
118License :: OSI Approved :: Python Software Foundation License
119Natural Language :: English
120Programming Language :: C
121Programming Language :: Python
122Topic :: Software Development
123"""
124
125
126def run_command(cmd):
127    status = os.system(cmd)
128    return os.waitstatus_to_exitcode(status)
129
130
131# Set common compiler and linker flags derived from the Makefile,
132# reserved for building the interpreter and the stdlib modules.
133# See bpo-21121 and bpo-35257
134def set_compiler_flags(compiler_flags, compiler_py_flags_nodist):
135    flags = sysconfig.get_config_var(compiler_flags)
136    py_flags_nodist = sysconfig.get_config_var(compiler_py_flags_nodist)
137    sysconfig.get_config_vars()[compiler_flags] = flags + ' ' + py_flags_nodist
138
139
140def add_dir_to_list(dirlist, dir):
141    """Add the directory 'dir' to the list 'dirlist' (after any relative
142    directories) if:
143
144    1) 'dir' is not already in 'dirlist'
145    2) 'dir' actually exists, and is a directory.
146    """
147    if dir is None or not os.path.isdir(dir) or dir in dirlist:
148        return
149    for i, path in enumerate(dirlist):
150        if not os.path.isabs(path):
151            dirlist.insert(i + 1, dir)
152            return
153    dirlist.insert(0, dir)
154
155
156def sysroot_paths(make_vars, subdirs):
157    """Get the paths of sysroot sub-directories.
158
159    * make_vars: a sequence of names of variables of the Makefile where
160      sysroot may be set.
161    * subdirs: a sequence of names of subdirectories used as the location for
162      headers or libraries.
163    """
164
165    dirs = []
166    for var_name in make_vars:
167        var = sysconfig.get_config_var(var_name)
168        if var is not None:
169            m = re.search(r'--sysroot=([^"]\S*|"[^"]+")', var)
170            if m is not None:
171                sysroot = m.group(1).strip('"')
172                for subdir in subdirs:
173                    if os.path.isabs(subdir):
174                        subdir = subdir[1:]
175                    path = os.path.join(sysroot, subdir)
176                    if os.path.isdir(path):
177                        dirs.append(path)
178                break
179    return dirs
180
181
182MACOS_SDK_ROOT = None
183MACOS_SDK_SPECIFIED = None
184
185def macosx_sdk_root():
186    """Return the directory of the current macOS SDK.
187
188    If no SDK was explicitly configured, call the compiler to find which
189    include files paths are being searched by default.  Use '/' if the
190    compiler is searching /usr/include (meaning system header files are
191    installed) or use the root of an SDK if that is being searched.
192    (The SDK may be supplied via Xcode or via the Command Line Tools).
193    The SDK paths used by Apple-supplied tool chains depend on the
194    setting of various variables; see the xcrun man page for more info.
195    Also sets MACOS_SDK_SPECIFIED for use by macosx_sdk_specified().
196    """
197    global MACOS_SDK_ROOT, MACOS_SDK_SPECIFIED
198
199    # If already called, return cached result.
200    if MACOS_SDK_ROOT:
201        return MACOS_SDK_ROOT
202
203    cflags = sysconfig.get_config_var('CFLAGS')
204    m = re.search(r'-isysroot\s*(\S+)', cflags)
205    if m is not None:
206        MACOS_SDK_ROOT = m.group(1)
207        MACOS_SDK_SPECIFIED = MACOS_SDK_ROOT != '/'
208    else:
209        MACOS_SDK_ROOT = _osx_support._default_sysroot(
210            sysconfig.get_config_var('CC'))
211        MACOS_SDK_SPECIFIED = False
212
213    return MACOS_SDK_ROOT
214
215
216def is_macosx_sdk_path(path):
217    """
218    Returns True if 'path' can be located in a macOS SDK
219    """
220    return ( (path.startswith('/usr/') and not path.startswith('/usr/local'))
221                or path.startswith('/System/Library')
222                or path.startswith('/System/iOSSupport') )
223
224
225def grep_headers_for(function, headers):
226    for header in headers:
227        with open(header, 'r', errors='surrogateescape') as f:
228            if function in f.read():
229                return True
230    return False
231
232
233def find_file(filename, std_dirs, paths):
234    """Searches for the directory where a given file is located,
235    and returns a possibly-empty list of additional directories, or None
236    if the file couldn't be found at all.
237
238    'filename' is the name of a file, such as readline.h or libcrypto.a.
239    'std_dirs' is the list of standard system directories; if the
240        file is found in one of them, no additional directives are needed.
241    'paths' is a list of additional locations to check; if the file is
242        found in one of them, the resulting list will contain the directory.
243    """
244    if MACOS:
245        # Honor the MacOSX SDK setting when one was specified.
246        # An SDK is a directory with the same structure as a real
247        # system, but with only header files and libraries.
248        sysroot = macosx_sdk_root()
249
250    # Check the standard locations
251    for dir_ in std_dirs:
252        f = os.path.join(dir_, filename)
253
254        if MACOS and is_macosx_sdk_path(dir_):
255            f = os.path.join(sysroot, dir_[1:], filename)
256
257        if os.path.exists(f): return []
258
259    # Check the additional directories
260    for dir_ in paths:
261        f = os.path.join(dir_, filename)
262
263        if MACOS and is_macosx_sdk_path(dir_):
264            f = os.path.join(sysroot, dir_[1:], filename)
265
266        if os.path.exists(f):
267            return [dir_]
268
269    # Not found anywhere
270    return None
271
272
273def validate_tzpath():
274    base_tzpath = sysconfig.get_config_var('TZPATH')
275    if not base_tzpath:
276        return
277
278    tzpaths = base_tzpath.split(os.pathsep)
279    bad_paths = [tzpath for tzpath in tzpaths if not os.path.isabs(tzpath)]
280    if bad_paths:
281        raise ValueError('TZPATH must contain only absolute paths, '
282                         + f'found:\n{tzpaths!r}\nwith invalid paths:\n'
283                         + f'{bad_paths!r}')
284
285
286def find_module_file(module, dirlist):
287    """Find a module in a set of possible folders. If it is not found
288    return the unadorned filename"""
289    dirs = find_file(module, [], dirlist)
290    if not dirs:
291        return module
292    if len(dirs) > 1:
293        log.info(f"WARNING: multiple copies of {module} found")
294    return os.path.abspath(os.path.join(dirs[0], module))
295
296
297class PyBuildExt(build_ext):
298
299    def __init__(self, dist):
300        build_ext.__init__(self, dist)
301        self.srcdir = None
302        self.lib_dirs = None
303        self.inc_dirs = None
304        self.config_h_vars = None
305        self.failed = []
306        self.failed_on_import = []
307        self.missing = []
308        self.disabled_configure = []
309        if '-j' in os.environ.get('MAKEFLAGS', ''):
310            self.parallel = True
311
312    def add(self, ext):
313        self.extensions.append(ext)
314
315    def addext(self, ext, *, update_flags=True):
316        """Add extension with Makefile MODULE_{name} support
317        """
318        if update_flags:
319            self.update_extension_flags(ext)
320
321        state = sysconfig.get_config_var(f"MODULE_{ext.name.upper()}_STATE")
322        if state == "yes":
323            self.extensions.append(ext)
324        elif state == "disabled":
325            self.disabled_configure.append(ext.name)
326        elif state == "missing":
327            self.missing.append(ext.name)
328        elif state == "n/a":
329            # not available on current platform
330            pass
331        else:
332            # not migrated to MODULE_{name}_STATE yet.
333            self.announce(
334                f'WARNING: Makefile is missing module variable for "{ext.name}"',
335                level=2
336            )
337            self.extensions.append(ext)
338
339    def update_extension_flags(self, ext):
340        """Update extension flags with module CFLAGS and LDFLAGS
341
342        Reads MODULE_{name}_CFLAGS and _LDFLAGS
343
344        Distutils appends extra args to the compiler arguments. Some flags like
345        -I must appear earlier, otherwise the pre-processor picks up files
346        from system include directories.
347        """
348        upper_name = ext.name.upper()
349        # Parse compiler flags (-I, -D, -U, extra args)
350        cflags = sysconfig.get_config_var(f"MODULE_{upper_name}_CFLAGS")
351        if cflags:
352            for token in shlex.split(cflags):
353                switch = token[0:2]
354                value = token[2:]
355                if switch == '-I':
356                    ext.include_dirs.append(value)
357                elif switch == '-D':
358                    key, _, val = value.partition("=")
359                    if not val:
360                        val = None
361                    ext.define_macros.append((key, val))
362                elif switch == '-U':
363                    ext.undef_macros.append(value)
364                else:
365                    ext.extra_compile_args.append(token)
366
367        # Parse linker flags (-L, -l, extra objects, extra args)
368        ldflags = sysconfig.get_config_var(f"MODULE_{upper_name}_LDFLAGS")
369        if ldflags:
370            for token in shlex.split(ldflags):
371                switch = token[0:2]
372                value = token[2:]
373                if switch == '-L':
374                    ext.library_dirs.append(value)
375                elif switch == '-l':
376                    ext.libraries.append(value)
377                elif (
378                    token[0] != '-' and
379                    token.endswith(('.a', '.o', '.so', '.sl', '.dylib'))
380                ):
381                    ext.extra_objects.append(token)
382                else:
383                    ext.extra_link_args.append(token)
384
385        return ext
386
387    def set_srcdir(self):
388        self.srcdir = sysconfig.get_config_var('srcdir')
389        if not self.srcdir:
390            # Maybe running on Windows but not using CYGWIN?
391            raise ValueError("No source directory; cannot proceed.")
392        self.srcdir = os.path.abspath(self.srcdir)
393
394    def remove_disabled(self):
395        # Remove modules that are present on the disabled list
396        extensions = [ext for ext in self.extensions
397                      if ext.name not in DISABLED_MODULE_LIST]
398        # move ctypes to the end, it depends on other modules
399        ext_map = dict((ext.name, i) for i, ext in enumerate(extensions))
400        if "_ctypes" in ext_map:
401            ctypes = extensions.pop(ext_map["_ctypes"])
402            extensions.append(ctypes)
403        self.extensions = extensions
404
405    def update_sources_depends(self):
406        # Fix up the autodetected modules, prefixing all the source files
407        # with Modules/.
408        # Add dependencies from MODULE_{name}_DEPS variable
409        moddirlist = [
410            # files in Modules/ directory
411            os.path.join(self.srcdir, 'Modules'),
412            # files relative to build base, e.g. libmpdec.a, libexpat.a
413            os.getcwd()
414        ]
415
416        # Fix up the paths for scripts, too
417        self.distribution.scripts = [os.path.join(self.srcdir, filename)
418                                     for filename in self.distribution.scripts]
419
420        # Python header files
421        include_dir = escape(sysconfig.get_path('include'))
422        headers = [sysconfig.get_config_h_filename()]
423        headers.extend(glob(os.path.join(include_dir, "*.h")))
424        headers.extend(glob(os.path.join(include_dir, "cpython", "*.h")))
425        headers.extend(glob(os.path.join(include_dir, "internal", "*.h")))
426
427        for ext in self.extensions:
428            ext.sources = [ find_module_file(filename, moddirlist)
429                            for filename in ext.sources ]
430            # Update dependencies from Makefile
431            makedeps = sysconfig.get_config_var(f"MODULE_{ext.name.upper()}_DEPS")
432            if makedeps:
433                # remove backslashes from line break continuations
434                ext.depends.extend(
435                    dep for dep in makedeps.split() if dep != "\\"
436                )
437            ext.depends = [
438                find_module_file(filename, moddirlist) for filename in ext.depends
439            ]
440            # re-compile extensions if a header file has been changed
441            ext.depends.extend(headers)
442
443    def handle_configured_extensions(self):
444        # The sysconfig variables built by makesetup that list the already
445        # built modules and the disabled modules as configured by the Setup
446        # files.
447        sysconf_built = set(sysconfig.get_config_var('MODBUILT_NAMES').split())
448        sysconf_shared = set(sysconfig.get_config_var('MODSHARED_NAMES').split())
449        sysconf_dis = set(sysconfig.get_config_var('MODDISABLED_NAMES').split())
450
451        mods_built = []
452        mods_disabled = []
453        for ext in self.extensions:
454            # If a module has already been built or has been disabled in the
455            # Setup files, don't build it here.
456            if ext.name in sysconf_built:
457                mods_built.append(ext)
458            if ext.name in sysconf_dis:
459                mods_disabled.append(ext)
460
461        mods_configured = mods_built + mods_disabled
462        if mods_configured:
463            self.extensions = [x for x in self.extensions if x not in
464                               mods_configured]
465            # Remove the shared libraries built by a previous build.
466            for ext in mods_configured:
467                # Don't remove shared extensions which have been built
468                # by Modules/Setup
469                if ext.name in sysconf_shared:
470                    continue
471                fullpath = self.get_ext_fullpath(ext.name)
472                if os.path.lexists(fullpath):
473                    os.unlink(fullpath)
474
475        return mods_built, mods_disabled
476
477    def set_compiler_executables(self):
478        # When you run "make CC=altcc" or something similar, you really want
479        # those environment variables passed into the setup.py phase.  Here's
480        # a small set of useful ones.
481        compiler = os.environ.get('CC')
482        args = {}
483        # unfortunately, distutils doesn't let us provide separate C and C++
484        # compilers
485        if compiler is not None:
486            (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS')
487            args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
488        self.compiler.set_executables(**args)
489
490    def build_extensions(self):
491        self.set_srcdir()
492        self.set_compiler_executables()
493        self.configure_compiler()
494        self.init_inc_lib_dirs()
495
496        # Detect which modules should be compiled
497        self.detect_modules()
498
499        if not LIST_MODULE_NAMES:
500            self.remove_disabled()
501
502        self.update_sources_depends()
503        mods_built, mods_disabled = self.handle_configured_extensions()
504
505        if LIST_MODULE_NAMES:
506            for ext in self.extensions:
507                print(ext.name)
508            for name in self.missing:
509                print(name)
510            return
511
512        build_ext.build_extensions(self)
513
514        if SUBPROCESS_BOOTSTRAP:
515            # Drop our custom subprocess module:
516            # use the newly built subprocess module
517            del sys.modules['subprocess']
518
519        for ext in self.extensions:
520            self.check_extension_import(ext)
521
522        self.summary(mods_built, mods_disabled)
523
524    def summary(self, mods_built, mods_disabled):
525        longest = max([len(e.name) for e in self.extensions], default=0)
526        if self.failed or self.failed_on_import:
527            all_failed = self.failed + self.failed_on_import
528            longest = max(longest, max([len(name) for name in all_failed]))
529
530        def print_three_column(lst):
531            lst.sort(key=str.lower)
532            # guarantee zip() doesn't drop anything
533            while len(lst) % 3:
534                lst.append("")
535            for e, f, g in zip(lst[::3], lst[1::3], lst[2::3]):
536                print("%-*s   %-*s   %-*s" % (longest, e, longest, f,
537                                              longest, g))
538
539        if self.missing:
540            print()
541            print("The necessary bits to build these optional modules were not "
542                  "found:")
543            print_three_column(self.missing)
544            print("To find the necessary bits, look in setup.py in"
545                  " detect_modules() for the module's name.")
546            print()
547
548        if mods_built:
549            print()
550            print("The following modules found by detect_modules() in"
551            " setup.py, have been")
552            print("built by the Makefile instead, as configured by the"
553            " Setup files:")
554            print_three_column([ext.name for ext in mods_built])
555            print()
556
557        if mods_disabled:
558            print()
559            print("The following modules found by detect_modules() in"
560            " setup.py have not")
561            print("been built, they are *disabled* in the Setup files:")
562            print_three_column([ext.name for ext in mods_disabled])
563            print()
564
565        if self.disabled_configure:
566            print()
567            print("The following modules found by detect_modules() in"
568            " setup.py have not")
569            print("been built, they are *disabled* by configure:")
570            print_three_column(self.disabled_configure)
571            print()
572
573        if self.failed:
574            failed = self.failed[:]
575            print()
576            print("Failed to build these modules:")
577            print_three_column(failed)
578            print()
579
580        if self.failed_on_import:
581            failed = self.failed_on_import[:]
582            print()
583            print("Following modules built successfully"
584                  " but were removed because they could not be imported:")
585            print_three_column(failed)
586            print()
587
588        if any('_ssl' in l
589               for l in (self.missing, self.failed, self.failed_on_import)):
590            print()
591            print("Could not build the ssl module!")
592            print("Python requires a OpenSSL 1.1.1 or newer")
593            if sysconfig.get_config_var("OPENSSL_LDFLAGS"):
594                print("Custom linker flags may require --with-openssl-rpath=auto")
595            print()
596
597        if os.environ.get("PYTHONSTRICTEXTENSIONBUILD") and (
598            self.failed or self.failed_on_import or self.missing
599        ):
600            raise RuntimeError("Failed to build some stdlib modules")
601
602    def build_extension(self, ext):
603
604        if ext.name == '_ctypes':
605            if not self.configure_ctypes(ext):
606                self.failed.append(ext.name)
607                return
608
609        try:
610            build_ext.build_extension(self, ext)
611        except (CCompilerError, DistutilsError) as why:
612            self.announce('WARNING: building of extension "%s" failed: %s' %
613                          (ext.name, why))
614            self.failed.append(ext.name)
615            return
616
617    def check_extension_import(self, ext):
618        # Don't try to import an extension that has failed to compile
619        if ext.name in self.failed:
620            self.announce(
621                'WARNING: skipping import check for failed build "%s"' %
622                ext.name, level=1)
623            return
624
625        # Workaround for Mac OS X: The Carbon-based modules cannot be
626        # reliably imported into a command-line Python
627        if 'Carbon' in ext.extra_link_args:
628            self.announce(
629                'WARNING: skipping import check for Carbon-based "%s"' %
630                ext.name)
631            return
632
633        if MACOS and (
634                sys.maxsize > 2**32 and '-arch' in ext.extra_link_args):
635            # Don't bother doing an import check when an extension was
636            # build with an explicit '-arch' flag on OSX. That's currently
637            # only used to build 32-bit only extensions in a 4-way
638            # universal build and loading 32-bit code into a 64-bit
639            # process will fail.
640            self.announce(
641                'WARNING: skipping import check for "%s"' %
642                ext.name)
643            return
644
645        # Workaround for Cygwin: Cygwin currently has fork issues when many
646        # modules have been imported
647        if CYGWIN:
648            self.announce('WARNING: skipping import check for Cygwin-based "%s"'
649                % ext.name)
650            return
651        ext_filename = os.path.join(
652            self.build_lib,
653            self.get_ext_filename(self.get_ext_fullname(ext.name)))
654
655        # If the build directory didn't exist when setup.py was
656        # started, sys.path_importer_cache has a negative result
657        # cached.  Clear that cache before trying to import.
658        sys.path_importer_cache.clear()
659
660        # Don't try to load extensions for cross builds
661        if CROSS_COMPILING:
662            return
663
664        loader = importlib.machinery.ExtensionFileLoader(ext.name, ext_filename)
665        spec = importlib.util.spec_from_file_location(ext.name, ext_filename,
666                                                      loader=loader)
667        try:
668            importlib._bootstrap._load(spec)
669        except ImportError as why:
670            self.failed_on_import.append(ext.name)
671            self.announce('*** WARNING: renaming "%s" since importing it'
672                          ' failed: %s' % (ext.name, why), level=3)
673            assert not self.inplace
674            basename, tail = os.path.splitext(ext_filename)
675            newname = basename + "_failed" + tail
676            if os.path.exists(newname):
677                os.remove(newname)
678            os.rename(ext_filename, newname)
679
680        except:
681            exc_type, why, tb = sys.exc_info()
682            self.announce('*** WARNING: importing extension "%s" '
683                          'failed with %s: %s' % (ext.name, exc_type, why),
684                          level=3)
685            self.failed.append(ext.name)
686
687    def add_multiarch_paths(self):
688        # Debian/Ubuntu multiarch support.
689        # https://wiki.ubuntu.com/MultiarchSpec
690        tmpfile = os.path.join(self.build_temp, 'multiarch')
691        if not os.path.exists(self.build_temp):
692            os.makedirs(self.build_temp)
693        ret = run_command(
694            '%s -print-multiarch > %s 2> /dev/null' % (CC, tmpfile))
695        multiarch_path_component = ''
696        try:
697            if ret == 0:
698                with open(tmpfile) as fp:
699                    multiarch_path_component = fp.readline().strip()
700        finally:
701            os.unlink(tmpfile)
702
703        if multiarch_path_component != '':
704            add_dir_to_list(self.compiler.library_dirs,
705                            '/usr/lib/' + multiarch_path_component)
706            add_dir_to_list(self.compiler.include_dirs,
707                            '/usr/include/' + multiarch_path_component)
708            return
709
710        if not find_executable('dpkg-architecture'):
711            return
712        opt = ''
713        if CROSS_COMPILING:
714            opt = '-t' + sysconfig.get_config_var('HOST_GNU_TYPE')
715        tmpfile = os.path.join(self.build_temp, 'multiarch')
716        if not os.path.exists(self.build_temp):
717            os.makedirs(self.build_temp)
718        ret = run_command(
719            'dpkg-architecture %s -qDEB_HOST_MULTIARCH > %s 2> /dev/null' %
720            (opt, tmpfile))
721        try:
722            if ret == 0:
723                with open(tmpfile) as fp:
724                    multiarch_path_component = fp.readline().strip()
725                add_dir_to_list(self.compiler.library_dirs,
726                                '/usr/lib/' + multiarch_path_component)
727                add_dir_to_list(self.compiler.include_dirs,
728                                '/usr/include/' + multiarch_path_component)
729        finally:
730            os.unlink(tmpfile)
731
732    def add_wrcc_search_dirs(self):
733        # add library search path by wr-cc, the compiler wrapper
734
735        def convert_mixed_path(path):
736            # convert path like C:\folder1\folder2/folder3/folder4
737            # to msys style /c/folder1/folder2/folder3/folder4
738            drive = path[0].lower()
739            left = path[2:].replace("\\", "/")
740            return "/" + drive + left
741
742        def add_search_path(line):
743            # On Windows building machine, VxWorks does
744            # cross builds under msys2 environment.
745            pathsep = (";" if sys.platform == "msys" else ":")
746            for d in line.strip().split("=")[1].split(pathsep):
747                d = d.strip()
748                if sys.platform == "msys":
749                    # On Windows building machine, compiler
750                    # returns mixed style path like:
751                    # C:\folder1\folder2/folder3/folder4
752                    d = convert_mixed_path(d)
753                d = os.path.normpath(d)
754                add_dir_to_list(self.compiler.library_dirs, d)
755
756        tmpfile = os.path.join(self.build_temp, 'wrccpaths')
757        os.makedirs(self.build_temp, exist_ok=True)
758        try:
759            ret = run_command('%s --print-search-dirs >%s' % (CC, tmpfile))
760            if ret:
761                return
762            with open(tmpfile) as fp:
763                # Parse paths in libraries line. The line is like:
764                # On Linux, "libraries: = path1:path2:path3"
765                # On Windows, "libraries: = path1;path2;path3"
766                for line in fp:
767                    if not line.startswith("libraries"):
768                        continue
769                    add_search_path(line)
770        finally:
771            try:
772                os.unlink(tmpfile)
773            except OSError:
774                pass
775
776    def add_cross_compiling_paths(self):
777        tmpfile = os.path.join(self.build_temp, 'ccpaths')
778        if not os.path.exists(self.build_temp):
779            os.makedirs(self.build_temp)
780        # bpo-38472: With a German locale, GCC returns "gcc-Version 9.1.0
781        # (GCC)", whereas it returns "gcc version 9.1.0" with the C locale.
782        ret = run_command('LC_ALL=C %s -E -v - </dev/null 2>%s 1>/dev/null' % (CC, tmpfile))
783        is_gcc = False
784        is_clang = False
785        in_incdirs = False
786        try:
787            if ret == 0:
788                with open(tmpfile) as fp:
789                    for line in fp.readlines():
790                        if line.startswith("gcc version"):
791                            is_gcc = True
792                        elif line.startswith("clang version"):
793                            is_clang = True
794                        elif line.startswith("#include <...>"):
795                            in_incdirs = True
796                        elif line.startswith("End of search list"):
797                            in_incdirs = False
798                        elif (is_gcc or is_clang) and line.startswith("LIBRARY_PATH"):
799                            for d in line.strip().split("=")[1].split(":"):
800                                d = os.path.normpath(d)
801                                if '/gcc/' not in d:
802                                    add_dir_to_list(self.compiler.library_dirs,
803                                                    d)
804                        elif (is_gcc or is_clang) and in_incdirs and '/gcc/' not in line and '/clang/' not in line:
805                            add_dir_to_list(self.compiler.include_dirs,
806                                            line.strip())
807        finally:
808            os.unlink(tmpfile)
809
810        if VXWORKS:
811            self.add_wrcc_search_dirs()
812
813    def add_ldflags_cppflags(self):
814        # Add paths specified in the environment variables LDFLAGS and
815        # CPPFLAGS for header and library files.
816        # We must get the values from the Makefile and not the environment
817        # directly since an inconsistently reproducible issue comes up where
818        # the environment variable is not set even though the value were passed
819        # into configure and stored in the Makefile (issue found on OS X 10.3).
820        for env_var, arg_name, dir_list in (
821                ('LDFLAGS', '-R', self.compiler.runtime_library_dirs),
822                ('LDFLAGS', '-L', self.compiler.library_dirs),
823                ('CPPFLAGS', '-I', self.compiler.include_dirs)):
824            env_val = sysconfig.get_config_var(env_var)
825            if env_val:
826                parser = argparse.ArgumentParser()
827                parser.add_argument(arg_name, dest="dirs", action="append")
828
829                # To prevent argparse from raising an exception about any
830                # options in env_val that it mistakes for known option, we
831                # strip out all double dashes and any dashes followed by a
832                # character that is not for the option we are dealing with.
833                #
834                # Please note that order of the regex is important!  We must
835                # strip out double-dashes first so that we don't end up with
836                # substituting "--Long" to "-Long" and thus lead to "ong" being
837                # used for a library directory.
838                env_val = re.sub(r'(^|\s+)-(-|(?!%s))' % arg_name[1],
839                                 ' ', env_val)
840                options, _ = parser.parse_known_args(env_val.split())
841                if options.dirs:
842                    for directory in reversed(options.dirs):
843                        add_dir_to_list(dir_list, directory)
844
845    def configure_compiler(self):
846        # Ensure that /usr/local is always used, but the local build
847        # directories (i.e. '.' and 'Include') must be first.  See issue
848        # 10520.
849        if not CROSS_COMPILING:
850            add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
851            add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
852        # only change this for cross builds for 3.3, issues on Mageia
853        if CROSS_COMPILING:
854            self.add_cross_compiling_paths()
855        self.add_multiarch_paths()
856        self.add_ldflags_cppflags()
857
858    def init_inc_lib_dirs(self):
859        if (not CROSS_COMPILING and
860                os.path.normpath(sys.base_prefix) != '/usr' and
861                not sysconfig.get_config_var('PYTHONFRAMEWORK')):
862            # OSX note: Don't add LIBDIR and INCLUDEDIR to building a framework
863            # (PYTHONFRAMEWORK is set) to avoid # linking problems when
864            # building a framework with different architectures than
865            # the one that is currently installed (issue #7473)
866            add_dir_to_list(self.compiler.library_dirs,
867                            sysconfig.get_config_var("LIBDIR"))
868            add_dir_to_list(self.compiler.include_dirs,
869                            sysconfig.get_config_var("INCLUDEDIR"))
870
871        system_lib_dirs = ['/lib64', '/usr/lib64', '/lib', '/usr/lib']
872        system_include_dirs = ['/usr/include']
873        # lib_dirs and inc_dirs are used to search for files;
874        # if a file is found in one of those directories, it can
875        # be assumed that no additional -I,-L directives are needed.
876        if not CROSS_COMPILING:
877            self.lib_dirs = self.compiler.library_dirs + system_lib_dirs
878            self.inc_dirs = self.compiler.include_dirs + system_include_dirs
879        else:
880            # Add the sysroot paths. 'sysroot' is a compiler option used to
881            # set the logical path of the standard system headers and
882            # libraries.
883            self.lib_dirs = (self.compiler.library_dirs +
884                             sysroot_paths(('LDFLAGS', 'CC'), system_lib_dirs))
885            self.inc_dirs = (self.compiler.include_dirs +
886                             sysroot_paths(('CPPFLAGS', 'CFLAGS', 'CC'),
887                                           system_include_dirs))
888
889        config_h = sysconfig.get_config_h_filename()
890        with open(config_h) as file:
891            self.config_h_vars = sysconfig.parse_config_h(file)
892
893        # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
894        if HOST_PLATFORM in ['osf1', 'unixware7', 'openunix8']:
895            self.lib_dirs += ['/usr/ccs/lib']
896
897        # HP-UX11iv3 keeps files in lib/hpux folders.
898        if HOST_PLATFORM == 'hp-ux11':
899            self.lib_dirs += ['/usr/lib/hpux64', '/usr/lib/hpux32']
900
901        if MACOS:
902            # This should work on any unixy platform ;-)
903            # If the user has bothered specifying additional -I and -L flags
904            # in OPT and LDFLAGS we might as well use them here.
905            #
906            # NOTE: using shlex.split would technically be more correct, but
907            # also gives a bootstrap problem. Let's hope nobody uses
908            # directories with whitespace in the name to store libraries.
909            cflags, ldflags = sysconfig.get_config_vars(
910                    'CFLAGS', 'LDFLAGS')
911            for item in cflags.split():
912                if item.startswith('-I'):
913                    self.inc_dirs.append(item[2:])
914
915            for item in ldflags.split():
916                if item.startswith('-L'):
917                    self.lib_dirs.append(item[2:])
918
919    def detect_simple_extensions(self):
920        #
921        # The following modules are all pretty straightforward, and compile
922        # on pretty much any POSIXish platform.
923        #
924
925        # array objects
926        self.addext(Extension('array', ['arraymodule.c']))
927
928        # Context Variables
929        self.addext(Extension('_contextvars', ['_contextvarsmodule.c']))
930
931        # math library functions, e.g. sin()
932        self.addext(Extension('math',  ['mathmodule.c']))
933
934        # complex math library functions
935        self.addext(Extension('cmath', ['cmathmodule.c']))
936
937        # libm is needed by delta_new() that uses round() and by accum() that
938        # uses modf().
939        self.addext(Extension('_datetime', ['_datetimemodule.c']))
940        self.addext(Extension('_zoneinfo', ['_zoneinfo.c']))
941        # random number generator implemented in C
942        self.addext(Extension("_random", ["_randommodule.c"]))
943        self.addext(Extension("_bisect", ["_bisectmodule.c"]))
944        self.addext(Extension("_heapq", ["_heapqmodule.c"]))
945        # C-optimized pickle replacement
946        self.addext(Extension("_pickle", ["_pickle.c"]))
947        # _json speedups
948        self.addext(Extension("_json", ["_json.c"]))
949
950        # profiler (_lsprof is for cProfile.py)
951        self.addext(Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']))
952        # static Unicode character database
953        self.addext(Extension('unicodedata', ['unicodedata.c']))
954        self.addext(Extension('_opcode', ['_opcode.c']))
955
956        # asyncio speedups
957        self.addext(Extension("_asyncio", ["_asynciomodule.c"]))
958
959        self.addext(Extension("_queue", ["_queuemodule.c"]))
960        self.addext(Extension("_statistics", ["_statisticsmodule.c"]))
961        self.addext(Extension("_struct", ["_struct.c"]))
962        self.addext(Extension("_typing", ["_typingmodule.c"]))
963
964        # Modules with some UNIX dependencies -- on by default:
965        # (If you have a really backward UNIX, select and socket may not be
966        # supported...)
967
968        # fcntl(2) and ioctl(2)
969        self.addext(Extension('fcntl', ['fcntlmodule.c']))
970        # grp(3)
971        self.addext(Extension('grp', ['grpmodule.c']))
972
973        self.addext(Extension('_socket', ['socketmodule.c']))
974        self.addext(Extension('spwd', ['spwdmodule.c']))
975
976        # select(2); not on ancient System V
977        self.addext(Extension('select', ['selectmodule.c']))
978
979        # Memory-mapped files (also works on Win32).
980        self.addext(Extension('mmap', ['mmapmodule.c']))
981
982        # Lance Ellinghaus's syslog module
983        # syslog daemon interface
984        self.addext(Extension('syslog', ['syslogmodule.c']))
985
986        # Python interface to subinterpreter C-API.
987        self.addext(Extension('_xxsubinterpreters', ['_xxsubinterpretersmodule.c']))
988
989        #
990        # Here ends the simple stuff.  From here on, modules need certain
991        # libraries, are platform-specific, or present other surprises.
992        #
993
994        # Multimedia modules
995        # These don't work for 64-bit platforms!!!
996        # These represent audio samples or images as strings:
997        #
998        # Operations on audio samples
999        # According to #993173, this one should actually work fine on
1000        # 64-bit platforms.
1001        #
1002        # audioop needs libm for floor() in multiple functions.
1003        self.addext(Extension('audioop', ['audioop.c']))
1004
1005        # CSV files
1006        self.addext(Extension('_csv', ['_csv.c']))
1007
1008        # POSIX subprocess module helper.
1009        self.addext(Extension('_posixsubprocess', ['_posixsubprocess.c']))
1010
1011    def detect_test_extensions(self):
1012        # Python C API test module
1013        self.addext(Extension('_testcapi', ['_testcapimodule.c']))
1014
1015        # Python Argument Clinc functional test module
1016        self.addext(Extension('_testclinic', ['_testclinic.c']))
1017
1018        # Python Internal C API test module
1019        self.addext(Extension('_testinternalcapi', ['_testinternalcapi.c']))
1020
1021        # Python PEP-3118 (buffer protocol) test module
1022        self.addext(Extension('_testbuffer', ['_testbuffer.c']))
1023
1024        # Test loading multiple modules from one compiled file (https://bugs.python.org/issue16421)
1025        self.addext(Extension('_testimportmultiple', ['_testimportmultiple.c']))
1026
1027        # Test multi-phase extension module init (PEP 489)
1028        self.addext(Extension('_testmultiphase', ['_testmultiphase.c']))
1029
1030        # Fuzz tests.
1031        self.addext(Extension(
1032            '_xxtestfuzz',
1033            ['_xxtestfuzz/_xxtestfuzz.c', '_xxtestfuzz/fuzzer.c']
1034        ))
1035
1036    def detect_readline_curses(self):
1037        # readline
1038        readline_termcap_library = ""
1039        curses_library = ""
1040        # Cannot use os.popen here in py3k.
1041        tmpfile = os.path.join(self.build_temp, 'readline_termcap_lib')
1042        if not os.path.exists(self.build_temp):
1043            os.makedirs(self.build_temp)
1044        # Determine if readline is already linked against curses or tinfo.
1045        if sysconfig.get_config_var('HAVE_LIBREADLINE'):
1046            if sysconfig.get_config_var('WITH_EDITLINE'):
1047                readline_lib = 'edit'
1048            else:
1049                readline_lib = 'readline'
1050            do_readline = self.compiler.find_library_file(self.lib_dirs,
1051                readline_lib)
1052            if CROSS_COMPILING:
1053                ret = run_command("%s -d %s | grep '(NEEDED)' > %s"
1054                                % (sysconfig.get_config_var('READELF'),
1055                                   do_readline, tmpfile))
1056            elif find_executable('ldd'):
1057                ret = run_command("ldd %s > %s" % (do_readline, tmpfile))
1058            else:
1059                ret = 1
1060            if ret == 0:
1061                with open(tmpfile) as fp:
1062                    for ln in fp:
1063                        if 'curses' in ln:
1064                            readline_termcap_library = re.sub(
1065                                r'.*lib(n?cursesw?)\.so.*', r'\1', ln
1066                            ).rstrip()
1067                            break
1068                        # termcap interface split out from ncurses
1069                        if 'tinfo' in ln:
1070                            readline_termcap_library = 'tinfo'
1071                            break
1072            if os.path.exists(tmpfile):
1073                os.unlink(tmpfile)
1074        else:
1075            do_readline = False
1076        # Issue 7384: If readline is already linked against curses,
1077        # use the same library for the readline and curses modules.
1078        if 'curses' in readline_termcap_library:
1079            curses_library = readline_termcap_library
1080        elif self.compiler.find_library_file(self.lib_dirs, 'ncursesw'):
1081            curses_library = 'ncursesw'
1082        # Issue 36210: OSS provided ncurses does not link on AIX
1083        # Use IBM supplied 'curses' for successful build of _curses
1084        elif AIX and self.compiler.find_library_file(self.lib_dirs, 'curses'):
1085            curses_library = 'curses'
1086        elif self.compiler.find_library_file(self.lib_dirs, 'ncurses'):
1087            curses_library = 'ncurses'
1088        elif self.compiler.find_library_file(self.lib_dirs, 'curses'):
1089            curses_library = 'curses'
1090
1091        if MACOS:
1092            os_release = int(os.uname()[2].split('.')[0])
1093            dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
1094            if (dep_target and
1095                    (tuple(int(n) for n in dep_target.split('.')[0:2])
1096                        < (10, 5) ) ):
1097                os_release = 8
1098            if os_release < 9:
1099                # MacOSX 10.4 has a broken readline. Don't try to build
1100                # the readline module unless the user has installed a fixed
1101                # readline package
1102                if find_file('readline/rlconf.h', self.inc_dirs, []) is None:
1103                    do_readline = False
1104        if do_readline:
1105            readline_libs = [readline_lib]
1106            if readline_termcap_library:
1107                pass # Issue 7384: Already linked against curses or tinfo.
1108            elif curses_library:
1109                readline_libs.append(curses_library)
1110            elif self.compiler.find_library_file(self.lib_dirs +
1111                                                     ['/usr/lib/termcap'],
1112                                                     'termcap'):
1113                readline_libs.append('termcap')
1114            self.add(Extension('readline', ['readline.c'],
1115                               library_dirs=['/usr/lib/termcap'],
1116                               libraries=readline_libs))
1117        else:
1118            self.missing.append('readline')
1119
1120        # Curses support, requiring the System V version of curses, often
1121        # provided by the ncurses library.
1122        curses_defines = []
1123        curses_includes = []
1124        panel_library = 'panel'
1125        if curses_library == 'ncursesw':
1126            curses_defines.append(('HAVE_NCURSESW', '1'))
1127            if not CROSS_COMPILING:
1128                curses_includes.append('/usr/include/ncursesw')
1129            # Bug 1464056: If _curses.so links with ncursesw,
1130            # _curses_panel.so must link with panelw.
1131            panel_library = 'panelw'
1132            if MACOS:
1133                # On OS X, there is no separate /usr/lib/libncursesw nor
1134                # libpanelw.  If we are here, we found a locally-supplied
1135                # version of libncursesw.  There should also be a
1136                # libpanelw.  _XOPEN_SOURCE defines are usually excluded
1137                # for OS X but we need _XOPEN_SOURCE_EXTENDED here for
1138                # ncurses wide char support
1139                curses_defines.append(('_XOPEN_SOURCE_EXTENDED', '1'))
1140        elif MACOS and curses_library == 'ncurses':
1141            # Building with the system-suppied combined libncurses/libpanel
1142            curses_defines.append(('HAVE_NCURSESW', '1'))
1143            curses_defines.append(('_XOPEN_SOURCE_EXTENDED', '1'))
1144
1145        curses_enabled = True
1146        if curses_library.startswith('ncurses'):
1147            curses_libs = [curses_library]
1148            self.add(Extension('_curses', ['_cursesmodule.c'],
1149                               include_dirs=curses_includes,
1150                               define_macros=curses_defines,
1151                               libraries=curses_libs))
1152        elif curses_library == 'curses' and not MACOS:
1153                # OSX has an old Berkeley curses, not good enough for
1154                # the _curses module.
1155            if (self.compiler.find_library_file(self.lib_dirs, 'terminfo')):
1156                curses_libs = ['curses', 'terminfo']
1157            elif (self.compiler.find_library_file(self.lib_dirs, 'termcap')):
1158                curses_libs = ['curses', 'termcap']
1159            else:
1160                curses_libs = ['curses']
1161
1162            self.add(Extension('_curses', ['_cursesmodule.c'],
1163                               define_macros=curses_defines,
1164                               libraries=curses_libs))
1165        else:
1166            curses_enabled = False
1167            self.missing.append('_curses')
1168
1169        # If the curses module is enabled, check for the panel module
1170        # _curses_panel needs some form of ncurses
1171        skip_curses_panel = True if AIX else False
1172        if (curses_enabled and not skip_curses_panel and
1173                self.compiler.find_library_file(self.lib_dirs, panel_library)):
1174            self.add(Extension('_curses_panel', ['_curses_panel.c'],
1175                           include_dirs=curses_includes,
1176                           define_macros=curses_defines,
1177                           libraries=[panel_library, *curses_libs]))
1178        elif not skip_curses_panel:
1179            self.missing.append('_curses_panel')
1180
1181    def detect_crypt(self):
1182        self.addext(Extension('_crypt', ['_cryptmodule.c']))
1183
1184    def detect_dbm_gdbm(self):
1185        # Modules that provide persistent dictionary-like semantics.  You will
1186        # probably want to arrange for at least one of them to be available on
1187        # your machine, though none are defined by default because of library
1188        # dependencies.  The Python module dbm/__init__.py provides an
1189        # implementation independent wrapper for these; dbm/dumb.py provides
1190        # similar functionality (but slower of course) implemented in Python.
1191
1192        dbm_setup_debug = False   # verbose debug prints from this script?
1193        dbm_order = ['gdbm']
1194
1195        # libdb, gdbm and ndbm headers and libraries
1196        have_ndbm_h = sysconfig.get_config_var("HAVE_NDBM_H")
1197        have_gdbm_ndbm_h = sysconfig.get_config_var("HAVE_GDBM_NDBM_H")
1198        have_gdbm_dash_ndbm_h = sysconfig.get_config_var("HAVE_GDBM_DASH_NDBM_H")
1199        have_libndbm = sysconfig.get_config_var("HAVE_LIBNDBM")
1200        have_libgdbm_compat = sysconfig.get_config_var("HAVE_LIBGDBM_COMPAT")
1201        have_libdb = sysconfig.get_config_var("HAVE_LIBDB")
1202
1203        # The standard Unix dbm module:
1204        if not CYGWIN:
1205            config_args = [arg.strip("'")
1206                           for arg in sysconfig.get_config_var("CONFIG_ARGS").split()]
1207            dbm_args = [arg for arg in config_args
1208                        if arg.startswith('--with-dbmliborder=')]
1209            if dbm_args:
1210                dbm_order = [arg.split('=')[-1] for arg in dbm_args][-1].split(":")
1211            else:
1212                dbm_order = "gdbm:ndbm:bdb".split(":")
1213            dbmext = None
1214            for cand in dbm_order:
1215                if cand == "ndbm":
1216                    if have_ndbm_h:
1217                        # Some systems have -lndbm, others have -lgdbm_compat,
1218                        # others don't have either
1219                        if have_libndbm:
1220                            ndbm_libs = ['ndbm']
1221                        elif have_libgdbm_compat:
1222                            ndbm_libs = ['gdbm_compat']
1223                        else:
1224                            ndbm_libs = []
1225                        if dbm_setup_debug: print("building dbm using ndbm")
1226                        dbmext = Extension(
1227                            '_dbm', ['_dbmmodule.c'],
1228                            define_macros=[('USE_NDBM', None)],
1229                            libraries=ndbm_libs
1230                        )
1231                        break
1232                elif cand == "gdbm":
1233                    # dbm_open() is provided by libgdbm_compat, which wraps libgdbm
1234                    if have_libgdbm_compat and (have_gdbm_ndbm_h or have_gdbm_dash_ndbm_h):
1235                        if dbm_setup_debug: print("building dbm using gdbm")
1236                        dbmext = Extension(
1237                            '_dbm', ['_dbmmodule.c'],
1238                            define_macros=[('USE_GDBM_COMPAT', None)],
1239                            libraries=['gdbm_compat']
1240                        )
1241                        break
1242                elif cand == "bdb":
1243                    if have_libdb:
1244                        if dbm_setup_debug: print("building dbm using bdb")
1245                        dbmext = Extension(
1246                            '_dbm', ['_dbmmodule.c'],
1247                            define_macros=[('USE_BERKDB', None)],
1248                            libraries=['db']
1249                        )
1250                        break
1251            if dbmext is not None:
1252                self.add(dbmext)
1253            else:
1254                self.missing.append('_dbm')
1255
1256        # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
1257        self.addext(Extension('_gdbm', ['_gdbmmodule.c']))
1258
1259    def detect_sqlite(self):
1260        sources = [
1261            "_sqlite/blob.c",
1262            "_sqlite/connection.c",
1263            "_sqlite/cursor.c",
1264            "_sqlite/microprotocols.c",
1265            "_sqlite/module.c",
1266            "_sqlite/prepare_protocol.c",
1267            "_sqlite/row.c",
1268            "_sqlite/statement.c",
1269            "_sqlite/util.c",
1270        ]
1271        self.addext(Extension("_sqlite3", sources=sources))
1272
1273    def detect_platform_specific_exts(self):
1274        # Unix-only modules
1275        # Steen Lumholt's termios module
1276        self.addext(Extension('termios', ['termios.c']))
1277        # Jeremy Hylton's rlimit interface
1278        self.addext(Extension('resource', ['resource.c']))
1279        # linux/soundcard.h or sys/soundcard.h
1280        self.addext(Extension('ossaudiodev', ['ossaudiodev.c']))
1281
1282        # macOS-only, needs SystemConfiguration and CoreFoundation framework
1283        self.addext(Extension('_scproxy', ['_scproxy.c']))
1284
1285    def detect_compress_exts(self):
1286        # Andrew Kuchling's zlib module.
1287        self.addext(Extension('zlib', ['zlibmodule.c']))
1288
1289        # Helper module for various ascii-encoders.  Uses zlib for an optimized
1290        # crc32 if we have it.  Otherwise binascii uses its own.
1291        self.addext(Extension('binascii', ['binascii.c']))
1292
1293        # Gustavo Niemeyer's bz2 module.
1294        self.addext(Extension('_bz2', ['_bz2module.c']))
1295
1296        # LZMA compression support.
1297        self.addext(Extension('_lzma', ['_lzmamodule.c']))
1298
1299    def detect_expat_elementtree(self):
1300        # Interface to the Expat XML parser
1301        #
1302        # Expat was written by James Clark and is now maintained by a group of
1303        # developers on SourceForge; see www.libexpat.org for more information.
1304        # The pyexpat module was written by Paul Prescod after a prototype by
1305        # Jack Jansen.  The Expat source is included in Modules/expat/.  Usage
1306        # of a system shared libexpat.so is possible with --with-system-expat
1307        # configure option.
1308        #
1309        # More information on Expat can be found at www.libexpat.org.
1310        #
1311        self.addext(Extension('pyexpat', sources=['pyexpat.c']))
1312
1313        # Fredrik Lundh's cElementTree module.  Note that this also
1314        # uses expat (via the CAPI hook in pyexpat).
1315        self.addext(Extension('_elementtree', sources=['_elementtree.c']))
1316
1317    def detect_multibytecodecs(self):
1318        # Hye-Shik Chang's CJKCodecs modules.
1319        self.addext(Extension('_multibytecodec',
1320                              ['cjkcodecs/multibytecodec.c']))
1321        for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'):
1322            self.addext(Extension(
1323                f'_codecs_{loc}', [f'cjkcodecs/_codecs_{loc}.c']
1324            ))
1325
1326    def detect_multiprocessing(self):
1327        # Richard Oudkerk's multiprocessing module
1328        multiprocessing_srcs = ['_multiprocessing/multiprocessing.c']
1329        if (
1330            sysconfig.get_config_var('HAVE_SEM_OPEN') and not
1331            sysconfig.get_config_var('POSIX_SEMAPHORES_NOT_ENABLED')
1332        ):
1333            multiprocessing_srcs.append('_multiprocessing/semaphore.c')
1334        self.addext(Extension('_multiprocessing', multiprocessing_srcs))
1335        self.addext(Extension('_posixshmem', ['_multiprocessing/posixshmem.c']))
1336
1337    def detect_uuid(self):
1338        # Build the _uuid module if possible
1339        self.addext(Extension('_uuid', ['_uuidmodule.c']))
1340
1341    def detect_modules(self):
1342        # remove dummy extension
1343        self.extensions = []
1344
1345        # Some C extensions are built by entries in Modules/Setup.bootstrap.
1346        # These are extensions are required to bootstrap the interpreter or
1347        # build process.
1348        self.detect_simple_extensions()
1349        self.detect_test_extensions()
1350        self.detect_readline_curses()
1351        self.detect_crypt()
1352        self.detect_openssl_hashlib()
1353        self.detect_hash_builtins()
1354        self.detect_dbm_gdbm()
1355        self.detect_sqlite()
1356        self.detect_platform_specific_exts()
1357        self.detect_nis()
1358        self.detect_compress_exts()
1359        self.detect_expat_elementtree()
1360        self.detect_multibytecodecs()
1361        self.detect_decimal()
1362        self.detect_ctypes()
1363        self.detect_multiprocessing()
1364        self.detect_tkinter()
1365        self.detect_uuid()
1366
1367        # Uncomment the next line if you want to play with xxmodule.c
1368#        self.add(Extension('xx', ['xxmodule.c']))
1369
1370        self.addext(Extension('xxlimited', ['xxlimited.c']))
1371        self.addext(Extension('xxlimited_35', ['xxlimited_35.c']))
1372
1373    def detect_tkinter(self):
1374        self.addext(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c']))
1375
1376    def configure_ctypes(self, ext):
1377        return True
1378
1379    def detect_ctypes(self):
1380        # Thomas Heller's _ctypes module
1381
1382        if (not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and MACOS):
1383            self.use_system_libffi = True
1384        else:
1385            self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS")
1386
1387        include_dirs = []
1388        extra_compile_args = []
1389        extra_link_args = []
1390        sources = ['_ctypes/_ctypes.c',
1391                   '_ctypes/callbacks.c',
1392                   '_ctypes/callproc.c',
1393                   '_ctypes/stgdict.c',
1394                   '_ctypes/cfield.c']
1395
1396        if MACOS:
1397            sources.append('_ctypes/malloc_closure.c')
1398            extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1')
1399            extra_compile_args.append('-DMACOSX')
1400            include_dirs.append('_ctypes/darwin')
1401
1402        elif HOST_PLATFORM == 'sunos5':
1403            # XXX This shouldn't be necessary; it appears that some
1404            # of the assembler code is non-PIC (i.e. it has relocations
1405            # when it shouldn't. The proper fix would be to rewrite
1406            # the assembler code to be PIC.
1407            # This only works with GCC; the Sun compiler likely refuses
1408            # this option. If you want to compile ctypes with the Sun
1409            # compiler, please research a proper solution, instead of
1410            # finding some -z option for the Sun compiler.
1411            extra_link_args.append('-mimpure-text')
1412
1413        ext = Extension('_ctypes',
1414                        include_dirs=include_dirs,
1415                        extra_compile_args=extra_compile_args,
1416                        extra_link_args=extra_link_args,
1417                        libraries=[],
1418                        sources=sources)
1419        self.add(ext)
1420        # function my_sqrt() needs libm for sqrt()
1421        self.addext(Extension('_ctypes_test', ['_ctypes/_ctypes_test.c']))
1422
1423        ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR")
1424        ffi_lib = None
1425
1426        ffi_inc_dirs = self.inc_dirs.copy()
1427        if MACOS:
1428            ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi")
1429
1430            if not ffi_inc:
1431                if os.path.exists(ffi_in_sdk):
1432                    ext.extra_compile_args.append("-DUSING_APPLE_OS_LIBFFI=1")
1433                    ffi_inc = ffi_in_sdk
1434                    ffi_lib = 'ffi'
1435                else:
1436                    # OS X 10.5 comes with libffi.dylib; the include files are
1437                    # in /usr/include/ffi
1438                    ffi_inc_dirs.append('/usr/include/ffi')
1439
1440        if not ffi_inc:
1441            found = find_file('ffi.h', [], ffi_inc_dirs)
1442            if found:
1443                ffi_inc = found[0]
1444        if ffi_inc:
1445            ffi_h = ffi_inc + '/ffi.h'
1446            if not os.path.exists(ffi_h):
1447                ffi_inc = None
1448                print('Header file {} does not exist'.format(ffi_h))
1449        if ffi_lib is None and ffi_inc:
1450            for lib_name in ('ffi', 'ffi_pic'):
1451                if (self.compiler.find_library_file(self.lib_dirs, lib_name)):
1452                    ffi_lib = lib_name
1453                    break
1454
1455        if ffi_inc and ffi_lib:
1456            ffi_headers = glob(os.path.join(ffi_inc, '*.h'))
1457            if grep_headers_for('ffi_prep_cif_var', ffi_headers):
1458                ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1")
1459            if grep_headers_for('ffi_prep_closure_loc', ffi_headers):
1460                ext.extra_compile_args.append("-DHAVE_FFI_PREP_CLOSURE_LOC=1")
1461            if grep_headers_for('ffi_closure_alloc', ffi_headers):
1462                ext.extra_compile_args.append("-DHAVE_FFI_CLOSURE_ALLOC=1")
1463
1464            ext.include_dirs.append(ffi_inc)
1465            ext.libraries.append(ffi_lib)
1466            self.use_system_libffi = True
1467
1468        if sysconfig.get_config_var('HAVE_LIBDL'):
1469            # for dlopen, see bpo-32647
1470            ext.libraries.append('dl')
1471
1472    def detect_decimal(self):
1473        # Stefan Krah's _decimal module
1474        self.addext(
1475            Extension(
1476                '_decimal',
1477                ['_decimal/_decimal.c'],
1478                # Uncomment for extra functionality:
1479                # define_macros=[('EXTRA_FUNCTIONALITY', 1)]
1480            )
1481        )
1482
1483    def detect_openssl_hashlib(self):
1484        self.addext(Extension('_ssl', ['_ssl.c']))
1485        self.addext(Extension('_hashlib', ['_hashopenssl.c']))
1486
1487    def detect_hash_builtins(self):
1488        # By default we always compile these even when OpenSSL is available
1489        # (issue #14693). It's harmless and the object code is tiny
1490        # (40-50 KiB per module, only loaded when actually used).  Modules can
1491        # be disabled via the --with-builtin-hashlib-hashes configure flag.
1492
1493        self.addext(Extension('_md5', ['md5module.c']))
1494        self.addext(Extension('_sha1', ['sha1module.c']))
1495        self.addext(Extension('_sha256', ['sha256module.c']))
1496        self.addext(Extension('_sha512', ['sha512module.c']))
1497        self.addext(Extension('_sha3', ['_sha3/sha3module.c']))
1498        self.addext(Extension('_blake2',
1499            [
1500                '_blake2/blake2module.c',
1501                '_blake2/blake2b_impl.c',
1502                '_blake2/blake2s_impl.c'
1503            ]
1504        ))
1505
1506    def detect_nis(self):
1507        self.addext(Extension('nis', ['nismodule.c']))
1508
1509
1510class PyBuildInstall(install):
1511    # Suppress the warning about installation into the lib_dynload
1512    # directory, which is not in sys.path when running Python during
1513    # installation:
1514    def initialize_options (self):
1515        install.initialize_options(self)
1516        self.warn_dir=0
1517
1518    # Customize subcommands to not install an egg-info file for Python
1519    sub_commands = [('install_lib', install.has_lib),
1520                    ('install_headers', install.has_headers),
1521                    ('install_scripts', install.has_scripts),
1522                    ('install_data', install.has_data)]
1523
1524
1525class PyBuildInstallLib(install_lib):
1526    # Do exactly what install_lib does but make sure correct access modes get
1527    # set on installed directories and files. All installed files with get
1528    # mode 644 unless they are a shared library in which case they will get
1529    # mode 755. All installed directories will get mode 755.
1530
1531    # this is works for EXT_SUFFIX too, which ends with SHLIB_SUFFIX
1532    shlib_suffix = sysconfig.get_config_var("SHLIB_SUFFIX")
1533
1534    def install(self):
1535        outfiles = install_lib.install(self)
1536        self.set_file_modes(outfiles, 0o644, 0o755)
1537        self.set_dir_modes(self.install_dir, 0o755)
1538        return outfiles
1539
1540    def set_file_modes(self, files, defaultMode, sharedLibMode):
1541        if not files: return
1542
1543        for filename in files:
1544            if os.path.islink(filename): continue
1545            mode = defaultMode
1546            if filename.endswith(self.shlib_suffix): mode = sharedLibMode
1547            log.info("changing mode of %s to %o", filename, mode)
1548            if not self.dry_run: os.chmod(filename, mode)
1549
1550    def set_dir_modes(self, dirname, mode):
1551        for dirpath, dirnames, fnames in os.walk(dirname):
1552            if os.path.islink(dirpath):
1553                continue
1554            log.info("changing mode of %s to %o", dirpath, mode)
1555            if not self.dry_run: os.chmod(dirpath, mode)
1556
1557
1558class PyBuildScripts(build_scripts):
1559    def copy_scripts(self):
1560        outfiles, updated_files = build_scripts.copy_scripts(self)
1561        fullversion = '-{0[0]}.{0[1]}'.format(sys.version_info)
1562        minoronly = '.{0[1]}'.format(sys.version_info)
1563        newoutfiles = []
1564        newupdated_files = []
1565        for filename in outfiles:
1566            if filename.endswith('2to3'):
1567                newfilename = filename + fullversion
1568            else:
1569                newfilename = filename + minoronly
1570            log.info(f'renaming {filename} to {newfilename}')
1571            os.rename(filename, newfilename)
1572            newoutfiles.append(newfilename)
1573            if filename in updated_files:
1574                newupdated_files.append(newfilename)
1575        return newoutfiles, newupdated_files
1576
1577
1578def main():
1579    global LIST_MODULE_NAMES
1580
1581    if "--list-module-names" in sys.argv:
1582        LIST_MODULE_NAMES = True
1583        sys.argv.remove("--list-module-names")
1584
1585    set_compiler_flags('CFLAGS', 'PY_CFLAGS_NODIST')
1586    set_compiler_flags('LDFLAGS', 'PY_LDFLAGS_NODIST')
1587
1588    class DummyProcess:
1589        """Hack for parallel build"""
1590        ProcessPoolExecutor = None
1591
1592    sys.modules['concurrent.futures.process'] = DummyProcess
1593    validate_tzpath()
1594
1595    # turn off warnings when deprecated modules are imported
1596    import warnings
1597    warnings.filterwarnings("ignore",category=DeprecationWarning)
1598    setup(# PyPI Metadata (PEP 301)
1599          name = "Python",
1600          version = sys.version.split()[0],
1601          url = "https://www.python.org/%d.%d" % sys.version_info[:2],
1602          maintainer = "Guido van Rossum and the Python community",
1603          maintainer_email = "[email protected]",
1604          description = "A high-level object-oriented programming language",
1605          long_description = SUMMARY.strip(),
1606          license = "PSF license",
1607          classifiers = [x for x in CLASSIFIERS.split("\n") if x],
1608          platforms = ["Many"],
1609
1610          # Build info
1611          cmdclass = {'build_ext': PyBuildExt,
1612                      'build_scripts': PyBuildScripts,
1613                      'install': PyBuildInstall,
1614                      'install_lib': PyBuildInstallLib},
1615          # A dummy module is defined here, because build_ext won't be
1616          # called unless there's at least one extension module defined.
1617          ext_modules=[Extension('_dummy', ['_dummy.c'])],
1618
1619          # If you change the scripts installed here, you also need to
1620          # check the PyBuildScripts command above, and change the links
1621          # created by the bininstall target in Makefile.pre.in
1622          scripts = ["Tools/scripts/pydoc3", "Tools/scripts/idle3",
1623                     "Tools/scripts/2to3"]
1624        )
1625
1626# --install-platlib
1627if __name__ == '__main__':
1628    main()
1629