• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Autodetecting setup.py script for building the Python extensions
2
3import argparse
4import importlib._bootstrap
5import importlib.machinery
6import importlib.util
7import os
8import re
9import sys
10import sysconfig
11from glob import glob, escape
12import _osx_support
13
14
15try:
16    import subprocess
17    del subprocess
18    SUBPROCESS_BOOTSTRAP = False
19except ImportError:
20    # Bootstrap Python: distutils.spawn uses subprocess to build C extensions,
21    # subprocess requires C extensions built by setup.py like _posixsubprocess.
22    #
23    # Use _bootsubprocess which only uses the os module.
24    #
25    # It is dropped from sys.modules as soon as all C extension modules
26    # are built.
27    import _bootsubprocess
28    sys.modules['subprocess'] = _bootsubprocess
29    del _bootsubprocess
30    SUBPROCESS_BOOTSTRAP = True
31
32
33from distutils import log
34from distutils.command.build_ext import build_ext
35from distutils.command.build_scripts import build_scripts
36from distutils.command.install import install
37from distutils.command.install_lib import install_lib
38from distutils.core import Extension, setup
39from distutils.errors import CCompilerError, DistutilsError
40from distutils.spawn import find_executable
41
42
43# Compile extensions used to test Python?
44TEST_EXTENSIONS = True
45
46# This global variable is used to hold the list of modules to be disabled.
47DISABLED_MODULE_LIST = []
48
49
50def get_platform():
51    # Cross compiling
52    if "_PYTHON_HOST_PLATFORM" in os.environ:
53        return os.environ["_PYTHON_HOST_PLATFORM"]
54
55    # Get value of sys.platform
56    if sys.platform.startswith('osf1'):
57        return 'osf1'
58    return sys.platform
59
60
61CROSS_COMPILING = ("_PYTHON_HOST_PLATFORM" in os.environ)
62HOST_PLATFORM = get_platform()
63MS_WINDOWS = (HOST_PLATFORM == 'win32')
64CYGWIN = (HOST_PLATFORM == 'cygwin')
65MACOS = (HOST_PLATFORM == 'darwin')
66AIX = (HOST_PLATFORM.startswith('aix'))
67VXWORKS = ('vxworks' in HOST_PLATFORM)
68
69
70SUMMARY = """
71Python is an interpreted, interactive, object-oriented programming
72language. It is often compared to Tcl, Perl, Scheme or Java.
73
74Python combines remarkable power with very clear syntax. It has
75modules, classes, exceptions, very high level dynamic data types, and
76dynamic typing. There are interfaces to many system calls and
77libraries, as well as to various windowing systems (X11, Motif, Tk,
78Mac, MFC). New built-in modules are easily written in C or C++. Python
79is also usable as an extension language for applications that need a
80programmable interface.
81
82The Python implementation is portable: it runs on many brands of UNIX,
83on Windows, DOS, Mac, Amiga... If your favorite system isn't
84listed here, it may still be supported, if there's a C compiler for
85it. Ask around on comp.lang.python -- or just try compiling Python
86yourself.
87"""
88
89CLASSIFIERS = """
90Development Status :: 6 - Mature
91License :: OSI Approved :: Python Software Foundation License
92Natural Language :: English
93Programming Language :: C
94Programming Language :: Python
95Topic :: Software Development
96"""
97
98
99def run_command(cmd):
100    status = os.system(cmd)
101    return os.waitstatus_to_exitcode(status)
102
103
104# Set common compiler and linker flags derived from the Makefile,
105# reserved for building the interpreter and the stdlib modules.
106# See bpo-21121 and bpo-35257
107def set_compiler_flags(compiler_flags, compiler_py_flags_nodist):
108    flags = sysconfig.get_config_var(compiler_flags)
109    py_flags_nodist = sysconfig.get_config_var(compiler_py_flags_nodist)
110    sysconfig.get_config_vars()[compiler_flags] = flags + ' ' + py_flags_nodist
111
112
113def add_dir_to_list(dirlist, dir):
114    """Add the directory 'dir' to the list 'dirlist' (after any relative
115    directories) if:
116
117    1) 'dir' is not already in 'dirlist'
118    2) 'dir' actually exists, and is a directory.
119    """
120    if dir is None or not os.path.isdir(dir) or dir in dirlist:
121        return
122    for i, path in enumerate(dirlist):
123        if not os.path.isabs(path):
124            dirlist.insert(i + 1, dir)
125            return
126    dirlist.insert(0, dir)
127
128
129def sysroot_paths(make_vars, subdirs):
130    """Get the paths of sysroot sub-directories.
131
132    * make_vars: a sequence of names of variables of the Makefile where
133      sysroot may be set.
134    * subdirs: a sequence of names of subdirectories used as the location for
135      headers or libraries.
136    """
137
138    dirs = []
139    for var_name in make_vars:
140        var = sysconfig.get_config_var(var_name)
141        if var is not None:
142            m = re.search(r'--sysroot=([^"]\S*|"[^"]+")', var)
143            if m is not None:
144                sysroot = m.group(1).strip('"')
145                for subdir in subdirs:
146                    if os.path.isabs(subdir):
147                        subdir = subdir[1:]
148                    path = os.path.join(sysroot, subdir)
149                    if os.path.isdir(path):
150                        dirs.append(path)
151                break
152    return dirs
153
154
155MACOS_SDK_ROOT = None
156MACOS_SDK_SPECIFIED = None
157
158def macosx_sdk_root():
159    """Return the directory of the current macOS SDK.
160
161    If no SDK was explicitly configured, call the compiler to find which
162    include files paths are being searched by default.  Use '/' if the
163    compiler is searching /usr/include (meaning system header files are
164    installed) or use the root of an SDK if that is being searched.
165    (The SDK may be supplied via Xcode or via the Command Line Tools).
166    The SDK paths used by Apple-supplied tool chains depend on the
167    setting of various variables; see the xcrun man page for more info.
168    Also sets MACOS_SDK_SPECIFIED for use by macosx_sdk_specified().
169    """
170    global MACOS_SDK_ROOT, MACOS_SDK_SPECIFIED
171
172    # If already called, return cached result.
173    if MACOS_SDK_ROOT:
174        return MACOS_SDK_ROOT
175
176    cflags = sysconfig.get_config_var('CFLAGS')
177    m = re.search(r'-isysroot\s*(\S+)', cflags)
178    if m is not None:
179        MACOS_SDK_ROOT = m.group(1)
180        MACOS_SDK_SPECIFIED = MACOS_SDK_ROOT != '/'
181    else:
182        MACOS_SDK_ROOT = _osx_support._default_sysroot(
183            sysconfig.get_config_var('CC'))
184        MACOS_SDK_SPECIFIED = False
185
186    return MACOS_SDK_ROOT
187
188
189def macosx_sdk_specified():
190    """Returns true if an SDK was explicitly configured.
191
192    True if an SDK was selected at configure time, either by specifying
193    --enable-universalsdk=(something other than no or /) or by adding a
194    -isysroot option to CFLAGS.  In some cases, like when making
195    decisions about macOS Tk framework paths, we need to be able to
196    know whether the user explicitly asked to build with an SDK versus
197    the implicit use of an SDK when header files are no longer
198    installed on a running system by the Command Line Tools.
199    """
200    global MACOS_SDK_SPECIFIED
201
202    # If already called, return cached result.
203    if MACOS_SDK_SPECIFIED:
204        return MACOS_SDK_SPECIFIED
205
206    # Find the sdk root and set MACOS_SDK_SPECIFIED
207    macosx_sdk_root()
208    return MACOS_SDK_SPECIFIED
209
210
211def is_macosx_sdk_path(path):
212    """
213    Returns True if 'path' can be located in an OSX SDK
214    """
215    return ( (path.startswith('/usr/') and not path.startswith('/usr/local'))
216                or path.startswith('/System/')
217                or path.startswith('/Library/') )
218
219
220def grep_headers_for(function, headers):
221    for header in headers:
222        with open(header, 'r', errors='surrogateescape') as f:
223            if function in f.read():
224                return True
225    return False
226
227def find_file(filename, std_dirs, paths):
228    """Searches for the directory where a given file is located,
229    and returns a possibly-empty list of additional directories, or None
230    if the file couldn't be found at all.
231
232    'filename' is the name of a file, such as readline.h or libcrypto.a.
233    'std_dirs' is the list of standard system directories; if the
234        file is found in one of them, no additional directives are needed.
235    'paths' is a list of additional locations to check; if the file is
236        found in one of them, the resulting list will contain the directory.
237    """
238    if MACOS:
239        # Honor the MacOSX SDK setting when one was specified.
240        # An SDK is a directory with the same structure as a real
241        # system, but with only header files and libraries.
242        sysroot = macosx_sdk_root()
243
244    # Check the standard locations
245    for dir in std_dirs:
246        f = os.path.join(dir, filename)
247
248        if MACOS and is_macosx_sdk_path(dir):
249            f = os.path.join(sysroot, dir[1:], filename)
250
251        if os.path.exists(f): return []
252
253    # Check the additional directories
254    for dir in paths:
255        f = os.path.join(dir, filename)
256
257        if MACOS and is_macosx_sdk_path(dir):
258            f = os.path.join(sysroot, dir[1:], filename)
259
260        if os.path.exists(f):
261            return [dir]
262
263    # Not found anywhere
264    return None
265
266
267def find_library_file(compiler, libname, std_dirs, paths):
268    result = compiler.find_library_file(std_dirs + paths, libname)
269    if result is None:
270        return None
271
272    if MACOS:
273        sysroot = macosx_sdk_root()
274
275    # Check whether the found file is in one of the standard directories
276    dirname = os.path.dirname(result)
277    for p in std_dirs:
278        # Ensure path doesn't end with path separator
279        p = p.rstrip(os.sep)
280
281        if MACOS and is_macosx_sdk_path(p):
282            # Note that, as of Xcode 7, Apple SDKs may contain textual stub
283            # libraries with .tbd extensions rather than the normal .dylib
284            # shared libraries installed in /.  The Apple compiler tool
285            # chain handles this transparently but it can cause problems
286            # for programs that are being built with an SDK and searching
287            # for specific libraries.  Distutils find_library_file() now
288            # knows to also search for and return .tbd files.  But callers
289            # of find_library_file need to keep in mind that the base filename
290            # of the returned SDK library file might have a different extension
291            # from that of the library file installed on the running system,
292            # for example:
293            #   /Applications/Xcode.app/Contents/Developer/Platforms/
294            #       MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/
295            #       usr/lib/libedit.tbd
296            # vs
297            #   /usr/lib/libedit.dylib
298            if os.path.join(sysroot, p[1:]) == dirname:
299                return [ ]
300
301        if p == dirname:
302            return [ ]
303
304    # Otherwise, it must have been in one of the additional directories,
305    # so we have to figure out which one.
306    for p in paths:
307        # Ensure path doesn't end with path separator
308        p = p.rstrip(os.sep)
309
310        if MACOS and is_macosx_sdk_path(p):
311            if os.path.join(sysroot, p[1:]) == dirname:
312                return [ p ]
313
314        if p == dirname:
315            return [p]
316    else:
317        assert False, "Internal error: Path not found in std_dirs or paths"
318
319def validate_tzpath():
320    base_tzpath = sysconfig.get_config_var('TZPATH')
321    if not base_tzpath:
322        return
323
324    tzpaths = base_tzpath.split(os.pathsep)
325    bad_paths = [tzpath for tzpath in tzpaths if not os.path.isabs(tzpath)]
326    if bad_paths:
327        raise ValueError('TZPATH must contain only absolute paths, '
328                         + f'found:\n{tzpaths!r}\nwith invalid paths:\n'
329                         + f'{bad_paths!r}')
330
331def find_module_file(module, dirlist):
332    """Find a module in a set of possible folders. If it is not found
333    return the unadorned filename"""
334    list = find_file(module, [], dirlist)
335    if not list:
336        return module
337    if len(list) > 1:
338        log.info("WARNING: multiple copies of %s found", module)
339    return os.path.join(list[0], module)
340
341
342class PyBuildExt(build_ext):
343
344    def __init__(self, dist):
345        build_ext.__init__(self, dist)
346        self.srcdir = None
347        self.lib_dirs = None
348        self.inc_dirs = None
349        self.config_h_vars = None
350        self.failed = []
351        self.failed_on_import = []
352        self.missing = []
353        self.disabled_configure = []
354        if '-j' in os.environ.get('MAKEFLAGS', ''):
355            self.parallel = True
356
357    def add(self, ext):
358        self.extensions.append(ext)
359
360    def set_srcdir(self):
361        self.srcdir = sysconfig.get_config_var('srcdir')
362        if not self.srcdir:
363            # Maybe running on Windows but not using CYGWIN?
364            raise ValueError("No source directory; cannot proceed.")
365        self.srcdir = os.path.abspath(self.srcdir)
366
367    def remove_disabled(self):
368        # Remove modules that are present on the disabled list
369        extensions = [ext for ext in self.extensions
370                      if ext.name not in DISABLED_MODULE_LIST]
371        # move ctypes to the end, it depends on other modules
372        ext_map = dict((ext.name, i) for i, ext in enumerate(extensions))
373        if "_ctypes" in ext_map:
374            ctypes = extensions.pop(ext_map["_ctypes"])
375            extensions.append(ctypes)
376        self.extensions = extensions
377
378    def update_sources_depends(self):
379        # Fix up the autodetected modules, prefixing all the source files
380        # with Modules/.
381        moddirlist = [os.path.join(self.srcdir, 'Modules')]
382
383        # Fix up the paths for scripts, too
384        self.distribution.scripts = [os.path.join(self.srcdir, filename)
385                                     for filename in self.distribution.scripts]
386
387        # Python header files
388        headers = [sysconfig.get_config_h_filename()]
389        headers += glob(os.path.join(escape(sysconfig.get_path('include')), "*.h"))
390
391        for ext in self.extensions:
392            ext.sources = [ find_module_file(filename, moddirlist)
393                            for filename in ext.sources ]
394            if ext.depends is not None:
395                ext.depends = [find_module_file(filename, moddirlist)
396                               for filename in ext.depends]
397            else:
398                ext.depends = []
399            # re-compile extensions if a header file has been changed
400            ext.depends.extend(headers)
401
402    def remove_configured_extensions(self):
403        # The sysconfig variables built by makesetup that list the already
404        # built modules and the disabled modules as configured by the Setup
405        # files.
406        sysconf_built = sysconfig.get_config_var('MODBUILT_NAMES').split()
407        sysconf_dis = sysconfig.get_config_var('MODDISABLED_NAMES').split()
408
409        mods_built = []
410        mods_disabled = []
411        for ext in self.extensions:
412            # If a module has already been built or has been disabled in the
413            # Setup files, don't build it here.
414            if ext.name in sysconf_built:
415                mods_built.append(ext)
416            if ext.name in sysconf_dis:
417                mods_disabled.append(ext)
418
419        mods_configured = mods_built + mods_disabled
420        if mods_configured:
421            self.extensions = [x for x in self.extensions if x not in
422                               mods_configured]
423            # Remove the shared libraries built by a previous build.
424            for ext in mods_configured:
425                fullpath = self.get_ext_fullpath(ext.name)
426                if os.path.exists(fullpath):
427                    os.unlink(fullpath)
428
429        return (mods_built, mods_disabled)
430
431    def set_compiler_executables(self):
432        # When you run "make CC=altcc" or something similar, you really want
433        # those environment variables passed into the setup.py phase.  Here's
434        # a small set of useful ones.
435        compiler = os.environ.get('CC')
436        args = {}
437        # unfortunately, distutils doesn't let us provide separate C and C++
438        # compilers
439        if compiler is not None:
440            (ccshared,cflags) = sysconfig.get_config_vars('CCSHARED','CFLAGS')
441            args['compiler_so'] = compiler + ' ' + ccshared + ' ' + cflags
442        self.compiler.set_executables(**args)
443
444    def build_extensions(self):
445        self.set_srcdir()
446
447        # Detect which modules should be compiled
448        self.detect_modules()
449
450        self.remove_disabled()
451
452        self.update_sources_depends()
453        mods_built, mods_disabled = self.remove_configured_extensions()
454        self.set_compiler_executables()
455
456        build_ext.build_extensions(self)
457
458        if SUBPROCESS_BOOTSTRAP:
459            # Drop our custom subprocess module:
460            # use the newly built subprocess module
461            del sys.modules['subprocess']
462
463        for ext in self.extensions:
464            self.check_extension_import(ext)
465
466        self.summary(mods_built, mods_disabled)
467
468    def summary(self, mods_built, mods_disabled):
469        longest = max([len(e.name) for e in self.extensions], default=0)
470        if self.failed or self.failed_on_import:
471            all_failed = self.failed + self.failed_on_import
472            longest = max(longest, max([len(name) for name in all_failed]))
473
474        def print_three_column(lst):
475            lst.sort(key=str.lower)
476            # guarantee zip() doesn't drop anything
477            while len(lst) % 3:
478                lst.append("")
479            for e, f, g in zip(lst[::3], lst[1::3], lst[2::3]):
480                print("%-*s   %-*s   %-*s" % (longest, e, longest, f,
481                                              longest, g))
482
483        if self.missing:
484            print()
485            print("Python build finished successfully!")
486            print("The necessary bits to build these optional modules were not "
487                  "found:")
488            print_three_column(self.missing)
489            print("To find the necessary bits, look in setup.py in"
490                  " detect_modules() for the module's name.")
491            print()
492
493        if mods_built:
494            print()
495            print("The following modules found by detect_modules() in"
496            " setup.py, have been")
497            print("built by the Makefile instead, as configured by the"
498            " Setup files:")
499            print_three_column([ext.name for ext in mods_built])
500            print()
501
502        if mods_disabled:
503            print()
504            print("The following modules found by detect_modules() in"
505            " setup.py have not")
506            print("been built, they are *disabled* in the Setup files:")
507            print_three_column([ext.name for ext in mods_disabled])
508            print()
509
510        if self.disabled_configure:
511            print()
512            print("The following modules found by detect_modules() in"
513            " setup.py have not")
514            print("been built, they are *disabled* by configure:")
515            print_three_column(self.disabled_configure)
516            print()
517
518        if self.failed:
519            failed = self.failed[:]
520            print()
521            print("Failed to build these modules:")
522            print_three_column(failed)
523            print()
524
525        if self.failed_on_import:
526            failed = self.failed_on_import[:]
527            print()
528            print("Following modules built successfully"
529                  " but were removed because they could not be imported:")
530            print_three_column(failed)
531            print()
532
533        if any('_ssl' in l
534               for l in (self.missing, self.failed, self.failed_on_import)):
535            print()
536            print("Could not build the ssl module!")
537            print("Python requires an OpenSSL 1.0.2 or 1.1 compatible "
538                  "libssl with X509_VERIFY_PARAM_set1_host().")
539            print("LibreSSL 2.6.4 and earlier do not provide the necessary "
540                  "APIs, https://github.com/libressl-portable/portable/issues/381")
541            print()
542
543    def build_extension(self, ext):
544
545        if ext.name == '_ctypes':
546            if not self.configure_ctypes(ext):
547                self.failed.append(ext.name)
548                return
549
550        try:
551            build_ext.build_extension(self, ext)
552        except (CCompilerError, DistutilsError) as why:
553            self.announce('WARNING: building of extension "%s" failed: %s' %
554                          (ext.name, why))
555            self.failed.append(ext.name)
556            return
557
558    def check_extension_import(self, ext):
559        # Don't try to import an extension that has failed to compile
560        if ext.name in self.failed:
561            self.announce(
562                'WARNING: skipping import check for failed build "%s"' %
563                ext.name, level=1)
564            return
565
566        # Workaround for Mac OS X: The Carbon-based modules cannot be
567        # reliably imported into a command-line Python
568        if 'Carbon' in ext.extra_link_args:
569            self.announce(
570                'WARNING: skipping import check for Carbon-based "%s"' %
571                ext.name)
572            return
573
574        if MACOS and (
575                sys.maxsize > 2**32 and '-arch' in ext.extra_link_args):
576            # Don't bother doing an import check when an extension was
577            # build with an explicit '-arch' flag on OSX. That's currently
578            # only used to build 32-bit only extensions in a 4-way
579            # universal build and loading 32-bit code into a 64-bit
580            # process will fail.
581            self.announce(
582                'WARNING: skipping import check for "%s"' %
583                ext.name)
584            return
585
586        # Workaround for Cygwin: Cygwin currently has fork issues when many
587        # modules have been imported
588        if CYGWIN:
589            self.announce('WARNING: skipping import check for Cygwin-based "%s"'
590                % ext.name)
591            return
592        ext_filename = os.path.join(
593            self.build_lib,
594            self.get_ext_filename(self.get_ext_fullname(ext.name)))
595
596        # If the build directory didn't exist when setup.py was
597        # started, sys.path_importer_cache has a negative result
598        # cached.  Clear that cache before trying to import.
599        sys.path_importer_cache.clear()
600
601        # Don't try to load extensions for cross builds
602        if CROSS_COMPILING:
603            return
604
605        loader = importlib.machinery.ExtensionFileLoader(ext.name, ext_filename)
606        spec = importlib.util.spec_from_file_location(ext.name, ext_filename,
607                                                      loader=loader)
608        try:
609            importlib._bootstrap._load(spec)
610        except ImportError as why:
611            self.failed_on_import.append(ext.name)
612            self.announce('*** WARNING: renaming "%s" since importing it'
613                          ' failed: %s' % (ext.name, why), level=3)
614            assert not self.inplace
615            basename, tail = os.path.splitext(ext_filename)
616            newname = basename + "_failed" + tail
617            if os.path.exists(newname):
618                os.remove(newname)
619            os.rename(ext_filename, newname)
620
621        except:
622            exc_type, why, tb = sys.exc_info()
623            self.announce('*** WARNING: importing extension "%s" '
624                          'failed with %s: %s' % (ext.name, exc_type, why),
625                          level=3)
626            self.failed.append(ext.name)
627
628    def add_multiarch_paths(self):
629        # Debian/Ubuntu multiarch support.
630        # https://wiki.ubuntu.com/MultiarchSpec
631        cc = sysconfig.get_config_var('CC')
632        tmpfile = os.path.join(self.build_temp, 'multiarch')
633        if not os.path.exists(self.build_temp):
634            os.makedirs(self.build_temp)
635        ret = run_command(
636            '%s -print-multiarch > %s 2> /dev/null' % (cc, tmpfile))
637        multiarch_path_component = ''
638        try:
639            if ret == 0:
640                with open(tmpfile) as fp:
641                    multiarch_path_component = fp.readline().strip()
642        finally:
643            os.unlink(tmpfile)
644
645        if multiarch_path_component != '':
646            add_dir_to_list(self.compiler.library_dirs,
647                            '/usr/lib/' + multiarch_path_component)
648            add_dir_to_list(self.compiler.include_dirs,
649                            '/usr/include/' + multiarch_path_component)
650            return
651
652        if not find_executable('dpkg-architecture'):
653            return
654        opt = ''
655        if CROSS_COMPILING:
656            opt = '-t' + sysconfig.get_config_var('HOST_GNU_TYPE')
657        tmpfile = os.path.join(self.build_temp, 'multiarch')
658        if not os.path.exists(self.build_temp):
659            os.makedirs(self.build_temp)
660        ret = run_command(
661            'dpkg-architecture %s -qDEB_HOST_MULTIARCH > %s 2> /dev/null' %
662            (opt, tmpfile))
663        try:
664            if ret == 0:
665                with open(tmpfile) as fp:
666                    multiarch_path_component = fp.readline().strip()
667                add_dir_to_list(self.compiler.library_dirs,
668                                '/usr/lib/' + multiarch_path_component)
669                add_dir_to_list(self.compiler.include_dirs,
670                                '/usr/include/' + multiarch_path_component)
671        finally:
672            os.unlink(tmpfile)
673
674    def add_cross_compiling_paths(self):
675        cc = sysconfig.get_config_var('CC')
676        tmpfile = os.path.join(self.build_temp, 'ccpaths')
677        if not os.path.exists(self.build_temp):
678            os.makedirs(self.build_temp)
679        ret = run_command('%s -E -v - </dev/null 2>%s 1>/dev/null' % (cc, tmpfile))
680        is_gcc = False
681        is_clang = False
682        in_incdirs = False
683        try:
684            if ret == 0:
685                with open(tmpfile) as fp:
686                    for line in fp.readlines():
687                        if line.startswith("gcc version"):
688                            is_gcc = True
689                        elif line.startswith("clang version"):
690                            is_clang = True
691                        elif line.startswith("#include <...>"):
692                            in_incdirs = True
693                        elif line.startswith("End of search list"):
694                            in_incdirs = False
695                        elif (is_gcc or is_clang) and line.startswith("LIBRARY_PATH"):
696                            for d in line.strip().split("=")[1].split(":"):
697                                d = os.path.normpath(d)
698                                if '/gcc/' not in d:
699                                    add_dir_to_list(self.compiler.library_dirs,
700                                                    d)
701                        elif (is_gcc or is_clang) and in_incdirs and '/gcc/' not in line and '/clang/' not in line:
702                            add_dir_to_list(self.compiler.include_dirs,
703                                            line.strip())
704        finally:
705            os.unlink(tmpfile)
706
707    def add_ldflags_cppflags(self):
708        # Add paths specified in the environment variables LDFLAGS and
709        # CPPFLAGS for header and library files.
710        # We must get the values from the Makefile and not the environment
711        # directly since an inconsistently reproducible issue comes up where
712        # the environment variable is not set even though the value were passed
713        # into configure and stored in the Makefile (issue found on OS X 10.3).
714        for env_var, arg_name, dir_list in (
715                ('LDFLAGS', '-R', self.compiler.runtime_library_dirs),
716                ('LDFLAGS', '-L', self.compiler.library_dirs),
717                ('CPPFLAGS', '-I', self.compiler.include_dirs)):
718            env_val = sysconfig.get_config_var(env_var)
719            if env_val:
720                parser = argparse.ArgumentParser()
721                parser.add_argument(arg_name, dest="dirs", action="append")
722                options, _ = parser.parse_known_args(env_val.split())
723                if options.dirs:
724                    for directory in reversed(options.dirs):
725                        add_dir_to_list(dir_list, directory)
726
727    def configure_compiler(self):
728        # Ensure that /usr/local is always used, but the local build
729        # directories (i.e. '.' and 'Include') must be first.  See issue
730        # 10520.
731        if not CROSS_COMPILING:
732            add_dir_to_list(self.compiler.library_dirs, '/usr/local/lib')
733            add_dir_to_list(self.compiler.include_dirs, '/usr/local/include')
734        # only change this for cross builds for 3.3, issues on Mageia
735        if CROSS_COMPILING:
736            self.add_cross_compiling_paths()
737        self.add_multiarch_paths()
738        self.add_ldflags_cppflags()
739
740    def init_inc_lib_dirs(self):
741        if (not CROSS_COMPILING and
742                os.path.normpath(sys.base_prefix) != '/usr' and
743                not sysconfig.get_config_var('PYTHONFRAMEWORK')):
744            # OSX note: Don't add LIBDIR and INCLUDEDIR to building a framework
745            # (PYTHONFRAMEWORK is set) to avoid # linking problems when
746            # building a framework with different architectures than
747            # the one that is currently installed (issue #7473)
748            add_dir_to_list(self.compiler.library_dirs,
749                            sysconfig.get_config_var("LIBDIR"))
750            add_dir_to_list(self.compiler.include_dirs,
751                            sysconfig.get_config_var("INCLUDEDIR"))
752
753        system_lib_dirs = ['/lib64', '/usr/lib64', '/lib', '/usr/lib']
754        system_include_dirs = ['/usr/include']
755        # lib_dirs and inc_dirs are used to search for files;
756        # if a file is found in one of those directories, it can
757        # be assumed that no additional -I,-L directives are needed.
758        if not CROSS_COMPILING:
759            self.lib_dirs = self.compiler.library_dirs + system_lib_dirs
760            self.inc_dirs = self.compiler.include_dirs + system_include_dirs
761        else:
762            # Add the sysroot paths. 'sysroot' is a compiler option used to
763            # set the logical path of the standard system headers and
764            # libraries.
765            self.lib_dirs = (self.compiler.library_dirs +
766                             sysroot_paths(('LDFLAGS', 'CC'), system_lib_dirs))
767            self.inc_dirs = (self.compiler.include_dirs +
768                             sysroot_paths(('CPPFLAGS', 'CFLAGS', 'CC'),
769                                           system_include_dirs))
770
771        config_h = sysconfig.get_config_h_filename()
772        with open(config_h) as file:
773            self.config_h_vars = sysconfig.parse_config_h(file)
774
775        # OSF/1 and Unixware have some stuff in /usr/ccs/lib (like -ldb)
776        if HOST_PLATFORM in ['osf1', 'unixware7', 'openunix8']:
777            self.lib_dirs += ['/usr/ccs/lib']
778
779        # HP-UX11iv3 keeps files in lib/hpux folders.
780        if HOST_PLATFORM == 'hp-ux11':
781            self.lib_dirs += ['/usr/lib/hpux64', '/usr/lib/hpux32']
782
783        if MACOS:
784            # This should work on any unixy platform ;-)
785            # If the user has bothered specifying additional -I and -L flags
786            # in OPT and LDFLAGS we might as well use them here.
787            #
788            # NOTE: using shlex.split would technically be more correct, but
789            # also gives a bootstrap problem. Let's hope nobody uses
790            # directories with whitespace in the name to store libraries.
791            cflags, ldflags = sysconfig.get_config_vars(
792                    'CFLAGS', 'LDFLAGS')
793            for item in cflags.split():
794                if item.startswith('-I'):
795                    self.inc_dirs.append(item[2:])
796
797            for item in ldflags.split():
798                if item.startswith('-L'):
799                    self.lib_dirs.append(item[2:])
800
801    def detect_simple_extensions(self):
802        #
803        # The following modules are all pretty straightforward, and compile
804        # on pretty much any POSIXish platform.
805        #
806
807        # array objects
808        self.add(Extension('array', ['arraymodule.c']))
809
810        # Context Variables
811        self.add(Extension('_contextvars', ['_contextvarsmodule.c']))
812
813        shared_math = 'Modules/_math.o'
814
815        # math library functions, e.g. sin()
816        self.add(Extension('math',  ['mathmodule.c'],
817                           extra_compile_args=['-DPy_BUILD_CORE_MODULE'],
818                           extra_objects=[shared_math],
819                           depends=['_math.h', shared_math],
820                           libraries=['m']))
821
822        # complex math library functions
823        self.add(Extension('cmath', ['cmathmodule.c'],
824                           extra_compile_args=['-DPy_BUILD_CORE_MODULE'],
825                           extra_objects=[shared_math],
826                           depends=['_math.h', shared_math],
827                           libraries=['m']))
828
829        # time libraries: librt may be needed for clock_gettime()
830        time_libs = []
831        lib = sysconfig.get_config_var('TIMEMODULE_LIB')
832        if lib:
833            time_libs.append(lib)
834
835        # time operations and variables
836        self.add(Extension('time', ['timemodule.c'],
837                           libraries=time_libs))
838        # libm is needed by delta_new() that uses round() and by accum() that
839        # uses modf().
840        self.add(Extension('_datetime', ['_datetimemodule.c'],
841                           libraries=['m']))
842        # zoneinfo module
843        self.add(Extension('_zoneinfo', ['_zoneinfo.c'])),
844        # random number generator implemented in C
845        self.add(Extension("_random", ["_randommodule.c"],
846                           extra_compile_args=['-DPy_BUILD_CORE_MODULE']))
847        # bisect
848        self.add(Extension("_bisect", ["_bisectmodule.c"]))
849        # heapq
850        self.add(Extension("_heapq", ["_heapqmodule.c"]))
851        # C-optimized pickle replacement
852        self.add(Extension("_pickle", ["_pickle.c"],
853                           extra_compile_args=['-DPy_BUILD_CORE_MODULE']))
854        # atexit
855        self.add(Extension("atexit", ["atexitmodule.c"]))
856        # _json speedups
857        self.add(Extension("_json", ["_json.c"],
858                           extra_compile_args=['-DPy_BUILD_CORE_MODULE']))
859
860        # profiler (_lsprof is for cProfile.py)
861        self.add(Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']))
862        # static Unicode character database
863        self.add(Extension('unicodedata', ['unicodedata.c'],
864                           depends=['unicodedata_db.h', 'unicodename_db.h']))
865        # _opcode module
866        self.add(Extension('_opcode', ['_opcode.c']))
867        # asyncio speedups
868        self.add(Extension("_asyncio", ["_asynciomodule.c"],
869                           extra_compile_args=['-DPy_BUILD_CORE_MODULE']))
870        # _abc speedups
871        self.add(Extension("_abc", ["_abc.c"]))
872        # _queue module
873        self.add(Extension("_queue", ["_queuemodule.c"]))
874        # _statistics module
875        self.add(Extension("_statistics", ["_statisticsmodule.c"]))
876
877        # Modules with some UNIX dependencies -- on by default:
878        # (If you have a really backward UNIX, select and socket may not be
879        # supported...)
880
881        # fcntl(2) and ioctl(2)
882        libs = []
883        if (self.config_h_vars.get('FLOCK_NEEDS_LIBBSD', False)):
884            # May be necessary on AIX for flock function
885            libs = ['bsd']
886        self.add(Extension('fcntl', ['fcntlmodule.c'],
887                           libraries=libs))
888        # pwd(3)
889        self.add(Extension('pwd', ['pwdmodule.c']))
890        # grp(3)
891        if not VXWORKS:
892            self.add(Extension('grp', ['grpmodule.c']))
893        # spwd, shadow passwords
894        if (self.config_h_vars.get('HAVE_GETSPNAM', False) or
895                self.config_h_vars.get('HAVE_GETSPENT', False)):
896            self.add(Extension('spwd', ['spwdmodule.c']))
897        # AIX has shadow passwords, but access is not via getspent(), etc.
898        # module support is not expected so it not 'missing'
899        elif not AIX:
900            self.missing.append('spwd')
901
902        # select(2); not on ancient System V
903        self.add(Extension('select', ['selectmodule.c']))
904
905        # Fred Drake's interface to the Python parser
906        self.add(Extension('parser', ['parsermodule.c']))
907
908        # Memory-mapped files (also works on Win32).
909        self.add(Extension('mmap', ['mmapmodule.c']))
910
911        # Lance Ellinghaus's syslog module
912        # syslog daemon interface
913        self.add(Extension('syslog', ['syslogmodule.c']))
914
915        # Python interface to subinterpreter C-API.
916        self.add(Extension('_xxsubinterpreters', ['_xxsubinterpretersmodule.c']))
917
918        #
919        # Here ends the simple stuff.  From here on, modules need certain
920        # libraries, are platform-specific, or present other surprises.
921        #
922
923        # Multimedia modules
924        # These don't work for 64-bit platforms!!!
925        # These represent audio samples or images as strings:
926        #
927        # Operations on audio samples
928        # According to #993173, this one should actually work fine on
929        # 64-bit platforms.
930        #
931        # audioop needs libm for floor() in multiple functions.
932        self.add(Extension('audioop', ['audioop.c'],
933                           libraries=['m']))
934
935        # CSV files
936        self.add(Extension('_csv', ['_csv.c']))
937
938        # POSIX subprocess module helper.
939        self.add(Extension('_posixsubprocess', ['_posixsubprocess.c']))
940
941    def detect_test_extensions(self):
942        # Python C API test module
943        self.add(Extension('_testcapi', ['_testcapimodule.c'],
944                           depends=['testcapi_long.h']))
945
946        # Python Internal C API test module
947        self.add(Extension('_testinternalcapi', ['_testinternalcapi.c'],
948                           extra_compile_args=['-DPy_BUILD_CORE_MODULE']))
949
950        # Python PEP-3118 (buffer protocol) test module
951        self.add(Extension('_testbuffer', ['_testbuffer.c']))
952
953        # Test loading multiple modules from one compiled file (http://bugs.python.org/issue16421)
954        self.add(Extension('_testimportmultiple', ['_testimportmultiple.c']))
955
956        # Test multi-phase extension module init (PEP 489)
957        self.add(Extension('_testmultiphase', ['_testmultiphase.c']))
958
959        # Fuzz tests.
960        self.add(Extension('_xxtestfuzz',
961                           ['_xxtestfuzz/_xxtestfuzz.c',
962                            '_xxtestfuzz/fuzzer.c']))
963
964    def detect_readline_curses(self):
965        # readline
966        do_readline = self.compiler.find_library_file(self.lib_dirs, 'readline')
967        readline_termcap_library = ""
968        curses_library = ""
969        # Cannot use os.popen here in py3k.
970        tmpfile = os.path.join(self.build_temp, 'readline_termcap_lib')
971        if not os.path.exists(self.build_temp):
972            os.makedirs(self.build_temp)
973        # Determine if readline is already linked against curses or tinfo.
974        if do_readline:
975            if CROSS_COMPILING:
976                ret = run_command("%s -d %s | grep '(NEEDED)' > %s"
977                                % (sysconfig.get_config_var('READELF'),
978                                   do_readline, tmpfile))
979            elif find_executable('ldd'):
980                ret = run_command("ldd %s > %s" % (do_readline, tmpfile))
981            else:
982                ret = 1
983            if ret == 0:
984                with open(tmpfile) as fp:
985                    for ln in fp:
986                        if 'curses' in ln:
987                            readline_termcap_library = re.sub(
988                                r'.*lib(n?cursesw?)\.so.*', r'\1', ln
989                            ).rstrip()
990                            break
991                        # termcap interface split out from ncurses
992                        if 'tinfo' in ln:
993                            readline_termcap_library = 'tinfo'
994                            break
995            if os.path.exists(tmpfile):
996                os.unlink(tmpfile)
997        # Issue 7384: If readline is already linked against curses,
998        # use the same library for the readline and curses modules.
999        if 'curses' in readline_termcap_library:
1000            curses_library = readline_termcap_library
1001        elif self.compiler.find_library_file(self.lib_dirs, 'ncursesw'):
1002            curses_library = 'ncursesw'
1003        # Issue 36210: OSS provided ncurses does not link on AIX
1004        # Use IBM supplied 'curses' for successful build of _curses
1005        elif AIX and self.compiler.find_library_file(self.lib_dirs, 'curses'):
1006            curses_library = 'curses'
1007        elif self.compiler.find_library_file(self.lib_dirs, 'ncurses'):
1008            curses_library = 'ncurses'
1009        elif self.compiler.find_library_file(self.lib_dirs, 'curses'):
1010            curses_library = 'curses'
1011
1012        if MACOS:
1013            os_release = int(os.uname()[2].split('.')[0])
1014            dep_target = sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET')
1015            if (dep_target and
1016                    (tuple(int(n) for n in str(dep_target).split('.')[0:2])
1017                        < (10, 5) ) ):
1018                os_release = 8
1019            if os_release < 9:
1020                # MacOSX 10.4 has a broken readline. Don't try to build
1021                # the readline module unless the user has installed a fixed
1022                # readline package
1023                if find_file('readline/rlconf.h', self.inc_dirs, []) is None:
1024                    do_readline = False
1025        if do_readline:
1026            if MACOS and os_release < 9:
1027                # In every directory on the search path search for a dynamic
1028                # library and then a static library, instead of first looking
1029                # for dynamic libraries on the entire path.
1030                # This way a statically linked custom readline gets picked up
1031                # before the (possibly broken) dynamic library in /usr/lib.
1032                readline_extra_link_args = ('-Wl,-search_paths_first',)
1033            else:
1034                readline_extra_link_args = ()
1035
1036            readline_libs = ['readline']
1037            if readline_termcap_library:
1038                pass # Issue 7384: Already linked against curses or tinfo.
1039            elif curses_library:
1040                readline_libs.append(curses_library)
1041            elif self.compiler.find_library_file(self.lib_dirs +
1042                                                     ['/usr/lib/termcap'],
1043                                                     'termcap'):
1044                readline_libs.append('termcap')
1045            self.add(Extension('readline', ['readline.c'],
1046                               library_dirs=['/usr/lib/termcap'],
1047                               extra_link_args=readline_extra_link_args,
1048                               libraries=readline_libs))
1049        else:
1050            self.missing.append('readline')
1051
1052        # Curses support, requiring the System V version of curses, often
1053        # provided by the ncurses library.
1054        curses_defines = []
1055        curses_includes = []
1056        panel_library = 'panel'
1057        if curses_library == 'ncursesw':
1058            curses_defines.append(('HAVE_NCURSESW', '1'))
1059            if not CROSS_COMPILING:
1060                curses_includes.append('/usr/include/ncursesw')
1061            # Bug 1464056: If _curses.so links with ncursesw,
1062            # _curses_panel.so must link with panelw.
1063            panel_library = 'panelw'
1064            if MACOS:
1065                # On OS X, there is no separate /usr/lib/libncursesw nor
1066                # libpanelw.  If we are here, we found a locally-supplied
1067                # version of libncursesw.  There should also be a
1068                # libpanelw.  _XOPEN_SOURCE defines are usually excluded
1069                # for OS X but we need _XOPEN_SOURCE_EXTENDED here for
1070                # ncurses wide char support
1071                curses_defines.append(('_XOPEN_SOURCE_EXTENDED', '1'))
1072        elif MACOS and curses_library == 'ncurses':
1073            # Building with the system-suppied combined libncurses/libpanel
1074            curses_defines.append(('HAVE_NCURSESW', '1'))
1075            curses_defines.append(('_XOPEN_SOURCE_EXTENDED', '1'))
1076
1077        curses_enabled = True
1078        if curses_library.startswith('ncurses'):
1079            curses_libs = [curses_library]
1080            self.add(Extension('_curses', ['_cursesmodule.c'],
1081                               include_dirs=curses_includes,
1082                               define_macros=curses_defines,
1083                               libraries=curses_libs))
1084        elif curses_library == 'curses' and not MACOS:
1085                # OSX has an old Berkeley curses, not good enough for
1086                # the _curses module.
1087            if (self.compiler.find_library_file(self.lib_dirs, 'terminfo')):
1088                curses_libs = ['curses', 'terminfo']
1089            elif (self.compiler.find_library_file(self.lib_dirs, 'termcap')):
1090                curses_libs = ['curses', 'termcap']
1091            else:
1092                curses_libs = ['curses']
1093
1094            self.add(Extension('_curses', ['_cursesmodule.c'],
1095                               define_macros=curses_defines,
1096                               libraries=curses_libs))
1097        else:
1098            curses_enabled = False
1099            self.missing.append('_curses')
1100
1101        # If the curses module is enabled, check for the panel module
1102        # _curses_panel needs some form of ncurses
1103        skip_curses_panel = True if AIX else False
1104        if (curses_enabled and not skip_curses_panel and
1105                self.compiler.find_library_file(self.lib_dirs, panel_library)):
1106            self.add(Extension('_curses_panel', ['_curses_panel.c'],
1107                           include_dirs=curses_includes,
1108                           define_macros=curses_defines,
1109                           libraries=[panel_library, *curses_libs]))
1110        elif not skip_curses_panel:
1111            self.missing.append('_curses_panel')
1112
1113    def detect_crypt(self):
1114        # crypt module.
1115        if VXWORKS:
1116            # bpo-31904: crypt() function is not provided by VxWorks.
1117            # DES_crypt() OpenSSL provides is too weak to implement
1118            # the encryption.
1119            return
1120
1121        if self.compiler.find_library_file(self.lib_dirs, 'crypt'):
1122            libs = ['crypt']
1123        else:
1124            libs = []
1125
1126        self.add(Extension('_crypt', ['_cryptmodule.c'],
1127                               libraries=libs))
1128
1129    def detect_socket(self):
1130        # socket(2)
1131        if not VXWORKS:
1132            kwargs = {'depends': ['socketmodule.h']}
1133            if MACOS:
1134                # Issue #35569: Expose RFC 3542 socket options.
1135                kwargs['extra_compile_args'] = ['-D__APPLE_USE_RFC_3542']
1136
1137            self.add(Extension('_socket', ['socketmodule.c'], **kwargs))
1138        elif self.compiler.find_library_file(self.lib_dirs, 'net'):
1139            libs = ['net']
1140            self.add(Extension('_socket', ['socketmodule.c'],
1141                               depends=['socketmodule.h'],
1142                               libraries=libs))
1143
1144    def detect_dbm_gdbm(self):
1145        # Modules that provide persistent dictionary-like semantics.  You will
1146        # probably want to arrange for at least one of them to be available on
1147        # your machine, though none are defined by default because of library
1148        # dependencies.  The Python module dbm/__init__.py provides an
1149        # implementation independent wrapper for these; dbm/dumb.py provides
1150        # similar functionality (but slower of course) implemented in Python.
1151
1152        # Sleepycat^WOracle Berkeley DB interface.
1153        #  http://www.oracle.com/database/berkeley-db/db/index.html
1154        #
1155        # This requires the Sleepycat^WOracle DB code. The supported versions
1156        # are set below.  Visit the URL above to download
1157        # a release.  Most open source OSes come with one or more
1158        # versions of BerkeleyDB already installed.
1159
1160        max_db_ver = (5, 3)
1161        min_db_ver = (3, 3)
1162        db_setup_debug = False   # verbose debug prints from this script?
1163
1164        def allow_db_ver(db_ver):
1165            """Returns a boolean if the given BerkeleyDB version is acceptable.
1166
1167            Args:
1168              db_ver: A tuple of the version to verify.
1169            """
1170            if not (min_db_ver <= db_ver <= max_db_ver):
1171                return False
1172            return True
1173
1174        def gen_db_minor_ver_nums(major):
1175            if major == 4:
1176                for x in range(max_db_ver[1]+1):
1177                    if allow_db_ver((4, x)):
1178                        yield x
1179            elif major == 3:
1180                for x in (3,):
1181                    if allow_db_ver((3, x)):
1182                        yield x
1183            else:
1184                raise ValueError("unknown major BerkeleyDB version", major)
1185
1186        # construct a list of paths to look for the header file in on
1187        # top of the normal inc_dirs.
1188        db_inc_paths = [
1189            '/usr/include/db4',
1190            '/usr/local/include/db4',
1191            '/opt/sfw/include/db4',
1192            '/usr/include/db3',
1193            '/usr/local/include/db3',
1194            '/opt/sfw/include/db3',
1195            # Fink defaults (http://fink.sourceforge.net/)
1196            '/sw/include/db4',
1197            '/sw/include/db3',
1198        ]
1199        # 4.x minor number specific paths
1200        for x in gen_db_minor_ver_nums(4):
1201            db_inc_paths.append('/usr/include/db4%d' % x)
1202            db_inc_paths.append('/usr/include/db4.%d' % x)
1203            db_inc_paths.append('/usr/local/BerkeleyDB.4.%d/include' % x)
1204            db_inc_paths.append('/usr/local/include/db4%d' % x)
1205            db_inc_paths.append('/pkg/db-4.%d/include' % x)
1206            db_inc_paths.append('/opt/db-4.%d/include' % x)
1207            # MacPorts default (http://www.macports.org/)
1208            db_inc_paths.append('/opt/local/include/db4%d' % x)
1209        # 3.x minor number specific paths
1210        for x in gen_db_minor_ver_nums(3):
1211            db_inc_paths.append('/usr/include/db3%d' % x)
1212            db_inc_paths.append('/usr/local/BerkeleyDB.3.%d/include' % x)
1213            db_inc_paths.append('/usr/local/include/db3%d' % x)
1214            db_inc_paths.append('/pkg/db-3.%d/include' % x)
1215            db_inc_paths.append('/opt/db-3.%d/include' % x)
1216
1217        if CROSS_COMPILING:
1218            db_inc_paths = []
1219
1220        # Add some common subdirectories for Sleepycat DB to the list,
1221        # based on the standard include directories. This way DB3/4 gets
1222        # picked up when it is installed in a non-standard prefix and
1223        # the user has added that prefix into inc_dirs.
1224        std_variants = []
1225        for dn in self.inc_dirs:
1226            std_variants.append(os.path.join(dn, 'db3'))
1227            std_variants.append(os.path.join(dn, 'db4'))
1228            for x in gen_db_minor_ver_nums(4):
1229                std_variants.append(os.path.join(dn, "db4%d"%x))
1230                std_variants.append(os.path.join(dn, "db4.%d"%x))
1231            for x in gen_db_minor_ver_nums(3):
1232                std_variants.append(os.path.join(dn, "db3%d"%x))
1233                std_variants.append(os.path.join(dn, "db3.%d"%x))
1234
1235        db_inc_paths = std_variants + db_inc_paths
1236        db_inc_paths = [p for p in db_inc_paths if os.path.exists(p)]
1237
1238        db_ver_inc_map = {}
1239
1240        if MACOS:
1241            sysroot = macosx_sdk_root()
1242
1243        class db_found(Exception): pass
1244        try:
1245            # See whether there is a Sleepycat header in the standard
1246            # search path.
1247            for d in self.inc_dirs + db_inc_paths:
1248                f = os.path.join(d, "db.h")
1249                if MACOS and is_macosx_sdk_path(d):
1250                    f = os.path.join(sysroot, d[1:], "db.h")
1251
1252                if db_setup_debug: print("db: looking for db.h in", f)
1253                if os.path.exists(f):
1254                    with open(f, 'rb') as file:
1255                        f = file.read()
1256                    m = re.search(br"#define\WDB_VERSION_MAJOR\W(\d+)", f)
1257                    if m:
1258                        db_major = int(m.group(1))
1259                        m = re.search(br"#define\WDB_VERSION_MINOR\W(\d+)", f)
1260                        db_minor = int(m.group(1))
1261                        db_ver = (db_major, db_minor)
1262
1263                        # Avoid 4.6 prior to 4.6.21 due to a BerkeleyDB bug
1264                        if db_ver == (4, 6):
1265                            m = re.search(br"#define\WDB_VERSION_PATCH\W(\d+)", f)
1266                            db_patch = int(m.group(1))
1267                            if db_patch < 21:
1268                                print("db.h:", db_ver, "patch", db_patch,
1269                                      "being ignored (4.6.x must be >= 4.6.21)")
1270                                continue
1271
1272                        if ( (db_ver not in db_ver_inc_map) and
1273                            allow_db_ver(db_ver) ):
1274                            # save the include directory with the db.h version
1275                            # (first occurrence only)
1276                            db_ver_inc_map[db_ver] = d
1277                            if db_setup_debug:
1278                                print("db.h: found", db_ver, "in", d)
1279                        else:
1280                            # we already found a header for this library version
1281                            if db_setup_debug: print("db.h: ignoring", d)
1282                    else:
1283                        # ignore this header, it didn't contain a version number
1284                        if db_setup_debug:
1285                            print("db.h: no version number version in", d)
1286
1287            db_found_vers = list(db_ver_inc_map.keys())
1288            db_found_vers.sort()
1289
1290            while db_found_vers:
1291                db_ver = db_found_vers.pop()
1292                db_incdir = db_ver_inc_map[db_ver]
1293
1294                # check lib directories parallel to the location of the header
1295                db_dirs_to_check = [
1296                    db_incdir.replace("include", 'lib64'),
1297                    db_incdir.replace("include", 'lib'),
1298                ]
1299
1300                if not MACOS:
1301                    db_dirs_to_check = list(filter(os.path.isdir, db_dirs_to_check))
1302
1303                else:
1304                    # Same as other branch, but takes OSX SDK into account
1305                    tmp = []
1306                    for dn in db_dirs_to_check:
1307                        if is_macosx_sdk_path(dn):
1308                            if os.path.isdir(os.path.join(sysroot, dn[1:])):
1309                                tmp.append(dn)
1310                        else:
1311                            if os.path.isdir(dn):
1312                                tmp.append(dn)
1313                    db_dirs_to_check = tmp
1314
1315                    db_dirs_to_check = tmp
1316
1317                # Look for a version specific db-X.Y before an ambiguous dbX
1318                # XXX should we -ever- look for a dbX name?  Do any
1319                # systems really not name their library by version and
1320                # symlink to more general names?
1321                for dblib in (('db-%d.%d' % db_ver),
1322                              ('db%d%d' % db_ver),
1323                              ('db%d' % db_ver[0])):
1324                    dblib_file = self.compiler.find_library_file(
1325                                    db_dirs_to_check + self.lib_dirs, dblib )
1326                    if dblib_file:
1327                        dblib_dir = [ os.path.abspath(os.path.dirname(dblib_file)) ]
1328                        raise db_found
1329                    else:
1330                        if db_setup_debug: print("db lib: ", dblib, "not found")
1331
1332        except db_found:
1333            if db_setup_debug:
1334                print("bsddb using BerkeleyDB lib:", db_ver, dblib)
1335                print("bsddb lib dir:", dblib_dir, " inc dir:", db_incdir)
1336            dblibs = [dblib]
1337            # Only add the found library and include directories if they aren't
1338            # already being searched. This avoids an explicit runtime library
1339            # dependency.
1340            if db_incdir in self.inc_dirs:
1341                db_incs = None
1342            else:
1343                db_incs = [db_incdir]
1344            if dblib_dir[0] in self.lib_dirs:
1345                dblib_dir = None
1346        else:
1347            if db_setup_debug: print("db: no appropriate library found")
1348            db_incs = None
1349            dblibs = []
1350            dblib_dir = None
1351
1352        dbm_setup_debug = False   # verbose debug prints from this script?
1353        dbm_order = ['gdbm']
1354        # The standard Unix dbm module:
1355        if not CYGWIN:
1356            config_args = [arg.strip("'")
1357                           for arg in sysconfig.get_config_var("CONFIG_ARGS").split()]
1358            dbm_args = [arg for arg in config_args
1359                        if arg.startswith('--with-dbmliborder=')]
1360            if dbm_args:
1361                dbm_order = [arg.split('=')[-1] for arg in dbm_args][-1].split(":")
1362            else:
1363                dbm_order = "ndbm:gdbm:bdb".split(":")
1364            dbmext = None
1365            for cand in dbm_order:
1366                if cand == "ndbm":
1367                    if find_file("ndbm.h", self.inc_dirs, []) is not None:
1368                        # Some systems have -lndbm, others have -lgdbm_compat,
1369                        # others don't have either
1370                        if self.compiler.find_library_file(self.lib_dirs,
1371                                                               'ndbm'):
1372                            ndbm_libs = ['ndbm']
1373                        elif self.compiler.find_library_file(self.lib_dirs,
1374                                                             'gdbm_compat'):
1375                            ndbm_libs = ['gdbm_compat']
1376                        else:
1377                            ndbm_libs = []
1378                        if dbm_setup_debug: print("building dbm using ndbm")
1379                        dbmext = Extension('_dbm', ['_dbmmodule.c'],
1380                                           define_macros=[
1381                                               ('HAVE_NDBM_H',None),
1382                                               ],
1383                                           libraries=ndbm_libs)
1384                        break
1385
1386                elif cand == "gdbm":
1387                    if self.compiler.find_library_file(self.lib_dirs, 'gdbm'):
1388                        gdbm_libs = ['gdbm']
1389                        if self.compiler.find_library_file(self.lib_dirs,
1390                                                               'gdbm_compat'):
1391                            gdbm_libs.append('gdbm_compat')
1392                        if find_file("gdbm/ndbm.h", self.inc_dirs, []) is not None:
1393                            if dbm_setup_debug: print("building dbm using gdbm")
1394                            dbmext = Extension(
1395                                '_dbm', ['_dbmmodule.c'],
1396                                define_macros=[
1397                                    ('HAVE_GDBM_NDBM_H', None),
1398                                    ],
1399                                libraries = gdbm_libs)
1400                            break
1401                        if find_file("gdbm-ndbm.h", self.inc_dirs, []) is not None:
1402                            if dbm_setup_debug: print("building dbm using gdbm")
1403                            dbmext = Extension(
1404                                '_dbm', ['_dbmmodule.c'],
1405                                define_macros=[
1406                                    ('HAVE_GDBM_DASH_NDBM_H', None),
1407                                    ],
1408                                libraries = gdbm_libs)
1409                            break
1410                elif cand == "bdb":
1411                    if dblibs:
1412                        if dbm_setup_debug: print("building dbm using bdb")
1413                        dbmext = Extension('_dbm', ['_dbmmodule.c'],
1414                                           library_dirs=dblib_dir,
1415                                           runtime_library_dirs=dblib_dir,
1416                                           include_dirs=db_incs,
1417                                           define_macros=[
1418                                               ('HAVE_BERKDB_H', None),
1419                                               ('DB_DBM_HSEARCH', None),
1420                                               ],
1421                                           libraries=dblibs)
1422                        break
1423            if dbmext is not None:
1424                self.add(dbmext)
1425            else:
1426                self.missing.append('_dbm')
1427
1428        # Anthony Baxter's gdbm module.  GNU dbm(3) will require -lgdbm:
1429        if ('gdbm' in dbm_order and
1430            self.compiler.find_library_file(self.lib_dirs, 'gdbm')):
1431            self.add(Extension('_gdbm', ['_gdbmmodule.c'],
1432                               libraries=['gdbm']))
1433        else:
1434            self.missing.append('_gdbm')
1435
1436    def detect_sqlite(self):
1437        # The sqlite interface
1438        sqlite_setup_debug = False   # verbose debug prints from this script?
1439
1440        # We hunt for #define SQLITE_VERSION "n.n.n"
1441        # We need to find >= sqlite version 3.3.9, for sqlite3_prepare_v2
1442        sqlite_incdir = sqlite_libdir = None
1443        sqlite_inc_paths = [ '/usr/include',
1444                             '/usr/include/sqlite',
1445                             '/usr/include/sqlite3',
1446                             '/usr/local/include',
1447                             '/usr/local/include/sqlite',
1448                             '/usr/local/include/sqlite3',
1449                             ]
1450        if CROSS_COMPILING:
1451            sqlite_inc_paths = []
1452        MIN_SQLITE_VERSION_NUMBER = (3, 7, 2)
1453        MIN_SQLITE_VERSION = ".".join([str(x)
1454                                    for x in MIN_SQLITE_VERSION_NUMBER])
1455
1456        # Scan the default include directories before the SQLite specific
1457        # ones. This allows one to override the copy of sqlite on OSX,
1458        # where /usr/include contains an old version of sqlite.
1459        if MACOS:
1460            sysroot = macosx_sdk_root()
1461
1462        for d_ in self.inc_dirs + sqlite_inc_paths:
1463            d = d_
1464            if MACOS and is_macosx_sdk_path(d):
1465                d = os.path.join(sysroot, d[1:])
1466
1467            f = os.path.join(d, "sqlite3.h")
1468            if os.path.exists(f):
1469                if sqlite_setup_debug: print("sqlite: found %s"%f)
1470                with open(f) as file:
1471                    incf = file.read()
1472                m = re.search(
1473                    r'\s*.*#\s*.*define\s.*SQLITE_VERSION\W*"([\d\.]*)"', incf)
1474                if m:
1475                    sqlite_version = m.group(1)
1476                    sqlite_version_tuple = tuple([int(x)
1477                                        for x in sqlite_version.split(".")])
1478                    if sqlite_version_tuple >= MIN_SQLITE_VERSION_NUMBER:
1479                        # we win!
1480                        if sqlite_setup_debug:
1481                            print("%s/sqlite3.h: version %s"%(d, sqlite_version))
1482                        sqlite_incdir = d
1483                        break
1484                    else:
1485                        if sqlite_setup_debug:
1486                            print("%s: version %s is too old, need >= %s"%(d,
1487                                        sqlite_version, MIN_SQLITE_VERSION))
1488                elif sqlite_setup_debug:
1489                    print("sqlite: %s had no SQLITE_VERSION"%(f,))
1490
1491        if sqlite_incdir:
1492            sqlite_dirs_to_check = [
1493                os.path.join(sqlite_incdir, '..', 'lib64'),
1494                os.path.join(sqlite_incdir, '..', 'lib'),
1495                os.path.join(sqlite_incdir, '..', '..', 'lib64'),
1496                os.path.join(sqlite_incdir, '..', '..', 'lib'),
1497            ]
1498            sqlite_libfile = self.compiler.find_library_file(
1499                                sqlite_dirs_to_check + self.lib_dirs, 'sqlite3')
1500            if sqlite_libfile:
1501                sqlite_libdir = [os.path.abspath(os.path.dirname(sqlite_libfile))]
1502
1503        if sqlite_incdir and sqlite_libdir:
1504            sqlite_srcs = ['_sqlite/cache.c',
1505                '_sqlite/connection.c',
1506                '_sqlite/cursor.c',
1507                '_sqlite/microprotocols.c',
1508                '_sqlite/module.c',
1509                '_sqlite/prepare_protocol.c',
1510                '_sqlite/row.c',
1511                '_sqlite/statement.c',
1512                '_sqlite/util.c', ]
1513
1514            sqlite_defines = []
1515            if not MS_WINDOWS:
1516                sqlite_defines.append(('MODULE_NAME', '"sqlite3"'))
1517            else:
1518                sqlite_defines.append(('MODULE_NAME', '\\"sqlite3\\"'))
1519
1520            # Enable support for loadable extensions in the sqlite3 module
1521            # if --enable-loadable-sqlite-extensions configure option is used.
1522            if '--enable-loadable-sqlite-extensions' not in sysconfig.get_config_var("CONFIG_ARGS"):
1523                sqlite_defines.append(("SQLITE_OMIT_LOAD_EXTENSION", "1"))
1524
1525            if MACOS:
1526                # In every directory on the search path search for a dynamic
1527                # library and then a static library, instead of first looking
1528                # for dynamic libraries on the entire path.
1529                # This way a statically linked custom sqlite gets picked up
1530                # before the dynamic library in /usr/lib.
1531                sqlite_extra_link_args = ('-Wl,-search_paths_first',)
1532            else:
1533                sqlite_extra_link_args = ()
1534
1535            include_dirs = ["Modules/_sqlite"]
1536            # Only include the directory where sqlite was found if it does
1537            # not already exist in set include directories, otherwise you
1538            # can end up with a bad search path order.
1539            if sqlite_incdir not in self.compiler.include_dirs:
1540                include_dirs.append(sqlite_incdir)
1541            # avoid a runtime library path for a system library dir
1542            if sqlite_libdir and sqlite_libdir[0] in self.lib_dirs:
1543                sqlite_libdir = None
1544            self.add(Extension('_sqlite3', sqlite_srcs,
1545                               define_macros=sqlite_defines,
1546                               include_dirs=include_dirs,
1547                               library_dirs=sqlite_libdir,
1548                               extra_link_args=sqlite_extra_link_args,
1549                               libraries=["sqlite3",]))
1550        else:
1551            self.missing.append('_sqlite3')
1552
1553    def detect_platform_specific_exts(self):
1554        # Unix-only modules
1555        if not MS_WINDOWS:
1556            if not VXWORKS:
1557                # Steen Lumholt's termios module
1558                self.add(Extension('termios', ['termios.c']))
1559                # Jeremy Hylton's rlimit interface
1560            self.add(Extension('resource', ['resource.c']))
1561        else:
1562            self.missing.extend(['resource', 'termios'])
1563
1564        # Platform-specific libraries
1565        if HOST_PLATFORM.startswith(('linux', 'freebsd', 'gnukfreebsd')):
1566            self.add(Extension('ossaudiodev', ['ossaudiodev.c']))
1567        elif not AIX:
1568            self.missing.append('ossaudiodev')
1569
1570        if MACOS:
1571            self.add(Extension('_scproxy', ['_scproxy.c'],
1572                               extra_link_args=[
1573                                   '-framework', 'SystemConfiguration',
1574                                   '-framework', 'CoreFoundation']))
1575
1576    def detect_compress_exts(self):
1577        # Andrew Kuchling's zlib module.  Note that some versions of zlib
1578        # 1.1.3 have security problems.  See CERT Advisory CA-2002-07:
1579        # http://www.cert.org/advisories/CA-2002-07.html
1580        #
1581        # zlib 1.1.4 is fixed, but at least one vendor (RedHat) has decided to
1582        # patch its zlib 1.1.3 package instead of upgrading to 1.1.4.  For
1583        # now, we still accept 1.1.3, because we think it's difficult to
1584        # exploit this in Python, and we'd rather make it RedHat's problem
1585        # than our problem <wink>.
1586        #
1587        # You can upgrade zlib to version 1.1.4 yourself by going to
1588        # http://www.gzip.org/zlib/
1589        zlib_inc = find_file('zlib.h', [], self.inc_dirs)
1590        have_zlib = False
1591        if zlib_inc is not None:
1592            zlib_h = zlib_inc[0] + '/zlib.h'
1593            version = '"0.0.0"'
1594            version_req = '"1.1.3"'
1595            if MACOS and is_macosx_sdk_path(zlib_h):
1596                zlib_h = os.path.join(macosx_sdk_root(), zlib_h[1:])
1597            with open(zlib_h) as fp:
1598                while 1:
1599                    line = fp.readline()
1600                    if not line:
1601                        break
1602                    if line.startswith('#define ZLIB_VERSION'):
1603                        version = line.split()[2]
1604                        break
1605            if version >= version_req:
1606                if (self.compiler.find_library_file(self.lib_dirs, 'z')):
1607                    if MACOS:
1608                        zlib_extra_link_args = ('-Wl,-search_paths_first',)
1609                    else:
1610                        zlib_extra_link_args = ()
1611                    self.add(Extension('zlib', ['zlibmodule.c'],
1612                                       libraries=['z'],
1613                                       extra_link_args=zlib_extra_link_args))
1614                    have_zlib = True
1615                else:
1616                    self.missing.append('zlib')
1617            else:
1618                self.missing.append('zlib')
1619        else:
1620            self.missing.append('zlib')
1621
1622        # Helper module for various ascii-encoders.  Uses zlib for an optimized
1623        # crc32 if we have it.  Otherwise binascii uses its own.
1624        if have_zlib:
1625            extra_compile_args = ['-DUSE_ZLIB_CRC32']
1626            libraries = ['z']
1627            extra_link_args = zlib_extra_link_args
1628        else:
1629            extra_compile_args = []
1630            libraries = []
1631            extra_link_args = []
1632        self.add(Extension('binascii', ['binascii.c'],
1633                           extra_compile_args=extra_compile_args,
1634                           libraries=libraries,
1635                           extra_link_args=extra_link_args))
1636
1637        # Gustavo Niemeyer's bz2 module.
1638        if (self.compiler.find_library_file(self.lib_dirs, 'bz2')):
1639            if MACOS:
1640                bz2_extra_link_args = ('-Wl,-search_paths_first',)
1641            else:
1642                bz2_extra_link_args = ()
1643            self.add(Extension('_bz2', ['_bz2module.c'],
1644                               libraries=['bz2'],
1645                               extra_link_args=bz2_extra_link_args))
1646        else:
1647            self.missing.append('_bz2')
1648
1649        # LZMA compression support.
1650        if self.compiler.find_library_file(self.lib_dirs, 'lzma'):
1651            self.add(Extension('_lzma', ['_lzmamodule.c'],
1652                               libraries=['lzma']))
1653        else:
1654            self.missing.append('_lzma')
1655
1656    def detect_expat_elementtree(self):
1657        # Interface to the Expat XML parser
1658        #
1659        # Expat was written by James Clark and is now maintained by a group of
1660        # developers on SourceForge; see www.libexpat.org for more information.
1661        # The pyexpat module was written by Paul Prescod after a prototype by
1662        # Jack Jansen.  The Expat source is included in Modules/expat/.  Usage
1663        # of a system shared libexpat.so is possible with --with-system-expat
1664        # configure option.
1665        #
1666        # More information on Expat can be found at www.libexpat.org.
1667        #
1668        if '--with-system-expat' in sysconfig.get_config_var("CONFIG_ARGS"):
1669            expat_inc = []
1670            define_macros = []
1671            extra_compile_args = []
1672            expat_lib = ['expat']
1673            expat_sources = []
1674            expat_depends = []
1675        else:
1676            expat_inc = [os.path.join(self.srcdir, 'Modules', 'expat')]
1677            define_macros = [
1678                ('HAVE_EXPAT_CONFIG_H', '1'),
1679                # bpo-30947: Python uses best available entropy sources to
1680                # call XML_SetHashSalt(), expat entropy sources are not needed
1681                ('XML_POOR_ENTROPY', '1'),
1682            ]
1683            extra_compile_args = []
1684            expat_lib = []
1685            expat_sources = ['expat/xmlparse.c',
1686                             'expat/xmlrole.c',
1687                             'expat/xmltok.c']
1688            expat_depends = ['expat/ascii.h',
1689                             'expat/asciitab.h',
1690                             'expat/expat.h',
1691                             'expat/expat_config.h',
1692                             'expat/expat_external.h',
1693                             'expat/internal.h',
1694                             'expat/latin1tab.h',
1695                             'expat/utf8tab.h',
1696                             'expat/xmlrole.h',
1697                             'expat/xmltok.h',
1698                             'expat/xmltok_impl.h'
1699                             ]
1700
1701            cc = sysconfig.get_config_var('CC').split()[0]
1702            ret = run_command(
1703                      '"%s" -Werror -Wno-unreachable-code -E -xc /dev/null >/dev/null 2>&1' % cc)
1704            if ret == 0:
1705                extra_compile_args.append('-Wno-unreachable-code')
1706
1707        self.add(Extension('pyexpat',
1708                           define_macros=define_macros,
1709                           extra_compile_args=extra_compile_args,
1710                           include_dirs=expat_inc,
1711                           libraries=expat_lib,
1712                           sources=['pyexpat.c'] + expat_sources,
1713                           depends=expat_depends))
1714
1715        # Fredrik Lundh's cElementTree module.  Note that this also
1716        # uses expat (via the CAPI hook in pyexpat).
1717
1718        if os.path.isfile(os.path.join(self.srcdir, 'Modules', '_elementtree.c')):
1719            define_macros.append(('USE_PYEXPAT_CAPI', None))
1720            self.add(Extension('_elementtree',
1721                               define_macros=define_macros,
1722                               include_dirs=expat_inc,
1723                               libraries=expat_lib,
1724                               sources=['_elementtree.c'],
1725                               depends=['pyexpat.c', *expat_sources,
1726                                        *expat_depends]))
1727        else:
1728            self.missing.append('_elementtree')
1729
1730    def detect_multibytecodecs(self):
1731        # Hye-Shik Chang's CJKCodecs modules.
1732        self.add(Extension('_multibytecodec',
1733                           ['cjkcodecs/multibytecodec.c']))
1734        for loc in ('kr', 'jp', 'cn', 'tw', 'hk', 'iso2022'):
1735            self.add(Extension('_codecs_%s' % loc,
1736                               ['cjkcodecs/_codecs_%s.c' % loc]))
1737
1738    def detect_multiprocessing(self):
1739        # Richard Oudkerk's multiprocessing module
1740        if MS_WINDOWS:
1741            multiprocessing_srcs = ['_multiprocessing/multiprocessing.c',
1742                                    '_multiprocessing/semaphore.c']
1743
1744        else:
1745            multiprocessing_srcs = ['_multiprocessing/multiprocessing.c']
1746            if (sysconfig.get_config_var('HAVE_SEM_OPEN') and not
1747                sysconfig.get_config_var('POSIX_SEMAPHORES_NOT_ENABLED')):
1748                multiprocessing_srcs.append('_multiprocessing/semaphore.c')
1749            if (sysconfig.get_config_var('HAVE_SHM_OPEN') and
1750                sysconfig.get_config_var('HAVE_SHM_UNLINK')):
1751                posixshmem_srcs = ['_multiprocessing/posixshmem.c']
1752                libs = []
1753                if sysconfig.get_config_var('SHM_NEEDS_LIBRT'):
1754                    # need to link with librt to get shm_open()
1755                    libs.append('rt')
1756                self.add(Extension('_posixshmem', posixshmem_srcs,
1757                                   define_macros={},
1758                                   libraries=libs,
1759                                   include_dirs=["Modules/_multiprocessing"]))
1760
1761        self.add(Extension('_multiprocessing', multiprocessing_srcs,
1762                           include_dirs=["Modules/_multiprocessing"]))
1763
1764    def detect_uuid(self):
1765        # Build the _uuid module if possible
1766        uuid_incs = find_file("uuid.h", self.inc_dirs, ["/usr/include/uuid"])
1767        if uuid_incs is not None:
1768            if self.compiler.find_library_file(self.lib_dirs, 'uuid'):
1769                uuid_libs = ['uuid']
1770            else:
1771                uuid_libs = []
1772            self.add(Extension('_uuid', ['_uuidmodule.c'],
1773                               libraries=uuid_libs,
1774                               include_dirs=uuid_incs))
1775        else:
1776            self.missing.append('_uuid')
1777
1778    def detect_modules(self):
1779        self.configure_compiler()
1780        self.init_inc_lib_dirs()
1781
1782        self.detect_simple_extensions()
1783        if TEST_EXTENSIONS:
1784            self.detect_test_extensions()
1785        self.detect_readline_curses()
1786        self.detect_crypt()
1787        self.detect_socket()
1788        self.detect_openssl_hashlib()
1789        self.detect_hash_builtins()
1790        self.detect_dbm_gdbm()
1791        self.detect_sqlite()
1792        self.detect_platform_specific_exts()
1793        self.detect_nis()
1794        self.detect_compress_exts()
1795        self.detect_expat_elementtree()
1796        self.detect_multibytecodecs()
1797        self.detect_decimal()
1798        self.detect_ctypes()
1799        self.detect_multiprocessing()
1800        if not self.detect_tkinter():
1801            self.missing.append('_tkinter')
1802        self.detect_uuid()
1803
1804##         # Uncomment these lines if you want to play with xxmodule.c
1805##         self.add(Extension('xx', ['xxmodule.c']))
1806
1807        if 'd' not in sysconfig.get_config_var('ABIFLAGS'):
1808            self.add(Extension('xxlimited', ['xxlimited.c'],
1809                               define_macros=[('Py_LIMITED_API', '0x03050000')]))
1810
1811    def detect_tkinter_explicitly(self):
1812        # Build _tkinter using explicit locations for Tcl/Tk.
1813        #
1814        # This is enabled when both arguments are given to ./configure:
1815        #
1816        #     --with-tcltk-includes="-I/path/to/tclincludes \
1817        #                            -I/path/to/tkincludes"
1818        #     --with-tcltk-libs="-L/path/to/tcllibs -ltclm.n \
1819        #                        -L/path/to/tklibs -ltkm.n"
1820        #
1821        # These values can also be specified or overridden via make:
1822        #    make TCLTK_INCLUDES="..." TCLTK_LIBS="..."
1823        #
1824        # This can be useful for building and testing tkinter with multiple
1825        # versions of Tcl/Tk.  Note that a build of Tk depends on a particular
1826        # build of Tcl so you need to specify both arguments and use care when
1827        # overriding.
1828
1829        # The _TCLTK variables are created in the Makefile sharedmods target.
1830        tcltk_includes = os.environ.get('_TCLTK_INCLUDES')
1831        tcltk_libs = os.environ.get('_TCLTK_LIBS')
1832        if not (tcltk_includes and tcltk_libs):
1833            # Resume default configuration search.
1834            return False
1835
1836        extra_compile_args = tcltk_includes.split()
1837        extra_link_args = tcltk_libs.split()
1838        self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
1839                           define_macros=[('WITH_APPINIT', 1)],
1840                           extra_compile_args = extra_compile_args,
1841                           extra_link_args = extra_link_args))
1842        return True
1843
1844    def detect_tkinter_darwin(self):
1845        # Build default _tkinter on macOS using Tcl and Tk frameworks.
1846        #
1847        # The macOS native Tk (AKA Aqua Tk) and Tcl are most commonly
1848        # built and installed as macOS framework bundles.  However,
1849        # for several reasons, we cannot take full advantage of the
1850        # Apple-supplied compiler chain's -framework options here.
1851        # Instead, we need to find and pass to the compiler the
1852        # absolute paths of the Tcl and Tk headers files we want to use
1853        # and the absolute path to the directory containing the Tcl
1854        # and Tk frameworks for linking.
1855        #
1856        # We want to handle here two common use cases on macOS:
1857        # 1. Build and link with system-wide third-party or user-built
1858        #    Tcl and Tk frameworks installed in /Library/Frameworks.
1859        # 2. Build and link using a user-specified macOS SDK so that the
1860        #    built Python can be exported to other systems.  In this case,
1861        #    search only the SDK's /Library/Frameworks (normally empty)
1862        #    and /System/Library/Frameworks.
1863        #
1864        # Any other use case should be able to be handled explicitly by
1865        # using the options described above in detect_tkinter_explicitly().
1866        # In particular it would be good to handle here the case where
1867        # you want to build and link with a framework build of Tcl and Tk
1868        # that is not in /Library/Frameworks, say, in your private
1869        # $HOME/Library/Frameworks directory or elsewhere. It turns
1870        # out to be difficult to make that work automatically here
1871        # without bringing into play more tools and magic. That case
1872        # can be handled using a recipe with the right arguments
1873        # to detect_tkinter_explicitly().
1874        #
1875        # Note also that the fallback case here is to try to use the
1876        # Apple-supplied Tcl and Tk frameworks in /System/Library but
1877        # be forewarned that they are deprecated by Apple and typically
1878        # out-of-date and buggy; their use should be avoided if at
1879        # all possible by installing a newer version of Tcl and Tk in
1880        # /Library/Frameworks before building Python without
1881        # an explicit SDK or by configuring build arguments explicitly.
1882
1883        from os.path import join, exists
1884
1885        sysroot = macosx_sdk_root() # path to the SDK or '/'
1886
1887        if macosx_sdk_specified():
1888            # Use case #2: an SDK other than '/' was specified.
1889            # Only search there.
1890            framework_dirs = [
1891                join(sysroot, 'Library', 'Frameworks'),
1892                join(sysroot, 'System', 'Library', 'Frameworks'),
1893            ]
1894        else:
1895            # Use case #1: no explicit SDK selected.
1896            # Search the local system-wide /Library/Frameworks,
1897            # not the one in the default SDK, otherwise fall back to
1898            # /System/Library/Frameworks whose header files may be in
1899            # the default SDK or, on older systems, actually installed.
1900            framework_dirs = [
1901                join('/', 'Library', 'Frameworks'),
1902                join(sysroot, 'System', 'Library', 'Frameworks'),
1903            ]
1904
1905        # Find the directory that contains the Tcl.framework and
1906        # Tk.framework bundles.
1907        for F in framework_dirs:
1908            # both Tcl.framework and Tk.framework should be present
1909            for fw in 'Tcl', 'Tk':
1910                if not exists(join(F, fw + '.framework')):
1911                    break
1912            else:
1913                # ok, F is now directory with both frameworks. Continue
1914                # building
1915                break
1916        else:
1917            # Tk and Tcl frameworks not found. Normal "unix" tkinter search
1918            # will now resume.
1919            return False
1920
1921        include_dirs = [
1922            join(F, fw + '.framework', H)
1923            for fw in ('Tcl', 'Tk')
1924            for H in ('Headers',)
1925        ]
1926
1927        # Add the base framework directory as well
1928        compile_args = ['-F', F]
1929
1930        # Do not build tkinter for archs that this Tk was not built with.
1931        cflags = sysconfig.get_config_vars('CFLAGS')[0]
1932        archs = re.findall(r'-arch\s+(\w+)', cflags)
1933
1934        tmpfile = os.path.join(self.build_temp, 'tk.arch')
1935        if not os.path.exists(self.build_temp):
1936            os.makedirs(self.build_temp)
1937
1938        run_command(
1939            "file {}/Tk.framework/Tk | grep 'for architecture' > {}".format(F, tmpfile)
1940        )
1941        with open(tmpfile) as fp:
1942            detected_archs = []
1943            for ln in fp:
1944                a = ln.split()[-1]
1945                if a in archs:
1946                    detected_archs.append(ln.split()[-1])
1947        os.unlink(tmpfile)
1948
1949        arch_args = []
1950        for a in detected_archs:
1951            arch_args.append('-arch')
1952            arch_args.append(a)
1953
1954        compile_args += arch_args
1955        link_args = [','.join(['-Wl', '-F', F, '-framework', 'Tcl', '-framework', 'Tk']), *arch_args]
1956
1957        # The X11/xlib.h file bundled in the Tk sources can cause function
1958        # prototype warnings from the compiler. Since we cannot easily fix
1959        # that, suppress the warnings here instead.
1960        if '-Wstrict-prototypes' in cflags.split():
1961            compile_args.append('-Wno-strict-prototypes')
1962
1963        self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
1964                           define_macros=[('WITH_APPINIT', 1)],
1965                           include_dirs=include_dirs,
1966                           libraries=[],
1967                           extra_compile_args=compile_args,
1968                           extra_link_args=link_args))
1969        return True
1970
1971    def detect_tkinter(self):
1972        # The _tkinter module.
1973
1974        # Check whether --with-tcltk-includes and --with-tcltk-libs were
1975        # configured or passed into the make target.  If so, use these values
1976        # to build tkinter and bypass the searches for Tcl and TK in standard
1977        # locations.
1978        if self.detect_tkinter_explicitly():
1979            return True
1980
1981        # Rather than complicate the code below, detecting and building
1982        # AquaTk is a separate method. Only one Tkinter will be built on
1983        # Darwin - either AquaTk, if it is found, or X11 based Tk.
1984        if (MACOS and self.detect_tkinter_darwin()):
1985            return True
1986
1987        # Assume we haven't found any of the libraries or include files
1988        # The versions with dots are used on Unix, and the versions without
1989        # dots on Windows, for detection by cygwin.
1990        tcllib = tklib = tcl_includes = tk_includes = None
1991        for version in ['8.6', '86', '8.5', '85', '8.4', '84', '8.3', '83',
1992                        '8.2', '82', '8.1', '81', '8.0', '80']:
1993            tklib = self.compiler.find_library_file(self.lib_dirs,
1994                                                        'tk' + version)
1995            tcllib = self.compiler.find_library_file(self.lib_dirs,
1996                                                         'tcl' + version)
1997            if tklib and tcllib:
1998                # Exit the loop when we've found the Tcl/Tk libraries
1999                break
2000
2001        # Now check for the header files
2002        if tklib and tcllib:
2003            # Check for the include files on Debian and {Free,Open}BSD, where
2004            # they're put in /usr/include/{tcl,tk}X.Y
2005            dotversion = version
2006            if '.' not in dotversion and "bsd" in HOST_PLATFORM.lower():
2007                # OpenBSD and FreeBSD use Tcl/Tk library names like libtcl83.a,
2008                # but the include subdirs are named like .../include/tcl8.3.
2009                dotversion = dotversion[:-1] + '.' + dotversion[-1]
2010            tcl_include_sub = []
2011            tk_include_sub = []
2012            for dir in self.inc_dirs:
2013                tcl_include_sub += [dir + os.sep + "tcl" + dotversion]
2014                tk_include_sub += [dir + os.sep + "tk" + dotversion]
2015            tk_include_sub += tcl_include_sub
2016            tcl_includes = find_file('tcl.h', self.inc_dirs, tcl_include_sub)
2017            tk_includes = find_file('tk.h', self.inc_dirs, tk_include_sub)
2018
2019        if (tcllib is None or tklib is None or
2020            tcl_includes is None or tk_includes is None):
2021            self.announce("INFO: Can't locate Tcl/Tk libs and/or headers", 2)
2022            return False
2023
2024        # OK... everything seems to be present for Tcl/Tk.
2025
2026        include_dirs = []
2027        libs = []
2028        defs = []
2029        added_lib_dirs = []
2030        for dir in tcl_includes + tk_includes:
2031            if dir not in include_dirs:
2032                include_dirs.append(dir)
2033
2034        # Check for various platform-specific directories
2035        if HOST_PLATFORM == 'sunos5':
2036            include_dirs.append('/usr/openwin/include')
2037            added_lib_dirs.append('/usr/openwin/lib')
2038        elif os.path.exists('/usr/X11R6/include'):
2039            include_dirs.append('/usr/X11R6/include')
2040            added_lib_dirs.append('/usr/X11R6/lib64')
2041            added_lib_dirs.append('/usr/X11R6/lib')
2042        elif os.path.exists('/usr/X11R5/include'):
2043            include_dirs.append('/usr/X11R5/include')
2044            added_lib_dirs.append('/usr/X11R5/lib')
2045        else:
2046            # Assume default location for X11
2047            include_dirs.append('/usr/X11/include')
2048            added_lib_dirs.append('/usr/X11/lib')
2049
2050        # If Cygwin, then verify that X is installed before proceeding
2051        if CYGWIN:
2052            x11_inc = find_file('X11/Xlib.h', [], include_dirs)
2053            if x11_inc is None:
2054                return False
2055
2056        # Check for BLT extension
2057        if self.compiler.find_library_file(self.lib_dirs + added_lib_dirs,
2058                                               'BLT8.0'):
2059            defs.append( ('WITH_BLT', 1) )
2060            libs.append('BLT8.0')
2061        elif self.compiler.find_library_file(self.lib_dirs + added_lib_dirs,
2062                                                'BLT'):
2063            defs.append( ('WITH_BLT', 1) )
2064            libs.append('BLT')
2065
2066        # Add the Tcl/Tk libraries
2067        libs.append('tk'+ version)
2068        libs.append('tcl'+ version)
2069
2070        # Finally, link with the X11 libraries (not appropriate on cygwin)
2071        if not CYGWIN:
2072            libs.append('X11')
2073
2074        # XXX handle these, but how to detect?
2075        # *** Uncomment and edit for PIL (TkImaging) extension only:
2076        #       -DWITH_PIL -I../Extensions/Imaging/libImaging  tkImaging.c \
2077        # *** Uncomment and edit for TOGL extension only:
2078        #       -DWITH_TOGL togl.c \
2079        # *** Uncomment these for TOGL extension only:
2080        #       -lGL -lGLU -lXext -lXmu \
2081
2082        self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
2083                           define_macros=[('WITH_APPINIT', 1)] + defs,
2084                           include_dirs=include_dirs,
2085                           libraries=libs,
2086                           library_dirs=added_lib_dirs))
2087        return True
2088
2089    def configure_ctypes(self, ext):
2090        return True
2091
2092    def detect_ctypes(self):
2093        # Thomas Heller's _ctypes module
2094
2095        if (not sysconfig.get_config_var("LIBFFI_INCLUDEDIR") and MACOS):
2096            self.use_system_libffi = True
2097        else:
2098            self.use_system_libffi = '--with-system-ffi' in sysconfig.get_config_var("CONFIG_ARGS")
2099
2100        include_dirs = []
2101        extra_compile_args = ['-DPy_BUILD_CORE_MODULE']
2102        extra_link_args = []
2103        sources = ['_ctypes/_ctypes.c',
2104                   '_ctypes/callbacks.c',
2105                   '_ctypes/callproc.c',
2106                   '_ctypes/stgdict.c',
2107                   '_ctypes/cfield.c']
2108        depends = ['_ctypes/ctypes.h']
2109
2110        if MACOS:
2111            sources.append('_ctypes/malloc_closure.c')
2112            extra_compile_args.append('-DUSING_MALLOC_CLOSURE_DOT_C=1')
2113            extra_compile_args.append('-DMACOSX')
2114            include_dirs.append('_ctypes/darwin')
2115
2116        elif HOST_PLATFORM == 'sunos5':
2117            # XXX This shouldn't be necessary; it appears that some
2118            # of the assembler code is non-PIC (i.e. it has relocations
2119            # when it shouldn't. The proper fix would be to rewrite
2120            # the assembler code to be PIC.
2121            # This only works with GCC; the Sun compiler likely refuses
2122            # this option. If you want to compile ctypes with the Sun
2123            # compiler, please research a proper solution, instead of
2124            # finding some -z option for the Sun compiler.
2125            extra_link_args.append('-mimpure-text')
2126
2127        elif HOST_PLATFORM.startswith('hp-ux'):
2128            extra_link_args.append('-fPIC')
2129
2130        ext = Extension('_ctypes',
2131                        include_dirs=include_dirs,
2132                        extra_compile_args=extra_compile_args,
2133                        extra_link_args=extra_link_args,
2134                        libraries=[],
2135                        sources=sources,
2136                        depends=depends)
2137        self.add(ext)
2138        if TEST_EXTENSIONS:
2139            # function my_sqrt() needs libm for sqrt()
2140            self.add(Extension('_ctypes_test',
2141                               sources=['_ctypes/_ctypes_test.c'],
2142                               libraries=['m']))
2143
2144        ffi_inc = sysconfig.get_config_var("LIBFFI_INCLUDEDIR")
2145        ffi_lib = None
2146
2147        ffi_inc_dirs = self.inc_dirs.copy()
2148        if MACOS:
2149            ffi_in_sdk = os.path.join(macosx_sdk_root(), "usr/include/ffi")
2150
2151            if not ffi_inc:
2152                if os.path.exists(ffi_in_sdk):
2153                    ext.extra_compile_args.append("-DUSING_APPLE_OS_LIBFFI=1")
2154                    ffi_inc = ffi_in_sdk
2155                    ffi_lib = 'ffi'
2156                else:
2157                    # OS X 10.5 comes with libffi.dylib; the include files are
2158                    # in /usr/include/ffi
2159                    ffi_inc_dirs.append('/usr/include/ffi')
2160
2161        if not ffi_inc:
2162            found = find_file('ffi.h', [], ffi_inc_dirs)
2163            if found:
2164                ffi_inc = found[0]
2165        if ffi_inc:
2166            ffi_h = ffi_inc + '/ffi.h'
2167            if not os.path.exists(ffi_h):
2168                ffi_inc = None
2169                print('Header file {} does not exist'.format(ffi_h))
2170        if ffi_lib is None and ffi_inc:
2171            for lib_name in ('ffi', 'ffi_pic'):
2172                if (self.compiler.find_library_file(self.lib_dirs, lib_name)):
2173                    ffi_lib = lib_name
2174                    break
2175
2176        if ffi_inc and ffi_lib:
2177            ffi_headers = glob(os.path.join(ffi_inc, '*.h'))
2178            if grep_headers_for('ffi_prep_cif_var', ffi_headers):
2179                ext.extra_compile_args.append("-DHAVE_FFI_PREP_CIF_VAR=1")
2180            if grep_headers_for('ffi_prep_closure_loc', ffi_headers):
2181                ext.extra_compile_args.append("-DHAVE_FFI_PREP_CLOSURE_LOC=1")
2182            if grep_headers_for('ffi_closure_alloc', ffi_headers):
2183                ext.extra_compile_args.append("-DHAVE_FFI_CLOSURE_ALLOC=1")
2184
2185            ext.include_dirs.append(ffi_inc)
2186            ext.libraries.append(ffi_lib)
2187            self.use_system_libffi = True
2188
2189        if sysconfig.get_config_var('HAVE_LIBDL'):
2190            # for dlopen, see bpo-32647
2191            ext.libraries.append('dl')
2192
2193    def detect_decimal(self):
2194        # Stefan Krah's _decimal module
2195        extra_compile_args = []
2196        undef_macros = []
2197        if '--with-system-libmpdec' in sysconfig.get_config_var("CONFIG_ARGS"):
2198            include_dirs = []
2199            libraries = [':libmpdec.so.2']
2200            sources = ['_decimal/_decimal.c']
2201            depends = ['_decimal/docstrings.h']
2202        else:
2203            include_dirs = [os.path.abspath(os.path.join(self.srcdir,
2204                                                         'Modules',
2205                                                         '_decimal',
2206                                                         'libmpdec'))]
2207            libraries = ['m']
2208            sources = [
2209              '_decimal/_decimal.c',
2210              '_decimal/libmpdec/basearith.c',
2211              '_decimal/libmpdec/constants.c',
2212              '_decimal/libmpdec/context.c',
2213              '_decimal/libmpdec/convolute.c',
2214              '_decimal/libmpdec/crt.c',
2215              '_decimal/libmpdec/difradix2.c',
2216              '_decimal/libmpdec/fnt.c',
2217              '_decimal/libmpdec/fourstep.c',
2218              '_decimal/libmpdec/io.c',
2219              '_decimal/libmpdec/mpalloc.c',
2220              '_decimal/libmpdec/mpdecimal.c',
2221              '_decimal/libmpdec/numbertheory.c',
2222              '_decimal/libmpdec/sixstep.c',
2223              '_decimal/libmpdec/transpose.c',
2224              ]
2225            depends = [
2226              '_decimal/docstrings.h',
2227              '_decimal/libmpdec/basearith.h',
2228              '_decimal/libmpdec/bits.h',
2229              '_decimal/libmpdec/constants.h',
2230              '_decimal/libmpdec/convolute.h',
2231              '_decimal/libmpdec/crt.h',
2232              '_decimal/libmpdec/difradix2.h',
2233              '_decimal/libmpdec/fnt.h',
2234              '_decimal/libmpdec/fourstep.h',
2235              '_decimal/libmpdec/io.h',
2236              '_decimal/libmpdec/mpalloc.h',
2237              '_decimal/libmpdec/mpdecimal.h',
2238              '_decimal/libmpdec/numbertheory.h',
2239              '_decimal/libmpdec/sixstep.h',
2240              '_decimal/libmpdec/transpose.h',
2241              '_decimal/libmpdec/typearith.h',
2242              '_decimal/libmpdec/umodarith.h',
2243              ]
2244
2245        config = {
2246          'x64':     [('CONFIG_64','1'), ('ASM','1')],
2247          'uint128': [('CONFIG_64','1'), ('ANSI','1'), ('HAVE_UINT128_T','1')],
2248          'ansi64':  [('CONFIG_64','1'), ('ANSI','1')],
2249          'ppro':    [('CONFIG_32','1'), ('PPRO','1'), ('ASM','1')],
2250          'ansi32':  [('CONFIG_32','1'), ('ANSI','1')],
2251          'ansi-legacy': [('CONFIG_32','1'), ('ANSI','1'),
2252                          ('LEGACY_COMPILER','1')],
2253          'universal':   [('UNIVERSAL','1')]
2254        }
2255
2256        cc = sysconfig.get_config_var('CC')
2257        sizeof_size_t = sysconfig.get_config_var('SIZEOF_SIZE_T')
2258        machine = os.environ.get('PYTHON_DECIMAL_WITH_MACHINE')
2259
2260        if machine:
2261            # Override automatic configuration to facilitate testing.
2262            define_macros = config[machine]
2263        elif MACOS:
2264            # Universal here means: build with the same options Python
2265            # was built with.
2266            define_macros = config['universal']
2267        elif sizeof_size_t == 8:
2268            if sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X64'):
2269                define_macros = config['x64']
2270            elif sysconfig.get_config_var('HAVE_GCC_UINT128_T'):
2271                define_macros = config['uint128']
2272            else:
2273                define_macros = config['ansi64']
2274        elif sizeof_size_t == 4:
2275            ppro = sysconfig.get_config_var('HAVE_GCC_ASM_FOR_X87')
2276            if ppro and ('gcc' in cc or 'clang' in cc) and \
2277               not 'sunos' in HOST_PLATFORM:
2278                # solaris: problems with register allocation.
2279                # icc >= 11.0 works as well.
2280                define_macros = config['ppro']
2281                extra_compile_args.append('-Wno-unknown-pragmas')
2282            else:
2283                define_macros = config['ansi32']
2284        else:
2285            raise DistutilsError("_decimal: unsupported architecture")
2286
2287        # Workarounds for toolchain bugs:
2288        if sysconfig.get_config_var('HAVE_IPA_PURE_CONST_BUG'):
2289            # Some versions of gcc miscompile inline asm:
2290            # http://gcc.gnu.org/bugzilla/show_bug.cgi?id=46491
2291            # http://gcc.gnu.org/ml/gcc/2010-11/msg00366.html
2292            extra_compile_args.append('-fno-ipa-pure-const')
2293        if sysconfig.get_config_var('HAVE_GLIBC_MEMMOVE_BUG'):
2294            # _FORTIFY_SOURCE wrappers for memmove and bcopy are incorrect:
2295            # http://sourceware.org/ml/libc-alpha/2010-12/msg00009.html
2296            undef_macros.append('_FORTIFY_SOURCE')
2297
2298        # Uncomment for extra functionality:
2299        #define_macros.append(('EXTRA_FUNCTIONALITY', 1))
2300        self.add(Extension('_decimal',
2301                           include_dirs=include_dirs,
2302                           libraries=libraries,
2303                           define_macros=define_macros,
2304                           undef_macros=undef_macros,
2305                           extra_compile_args=extra_compile_args,
2306                           sources=sources,
2307                           depends=depends))
2308
2309    def detect_openssl_hashlib(self):
2310        # Detect SSL support for the socket module (via _ssl)
2311        config_vars = sysconfig.get_config_vars()
2312
2313        def split_var(name, sep):
2314            # poor man's shlex, the re module is not available yet.
2315            value = config_vars.get(name)
2316            if not value:
2317                return ()
2318            # This trick works because ax_check_openssl uses --libs-only-L,
2319            # --libs-only-l, and --cflags-only-I.
2320            value = ' ' + value
2321            sep = ' ' + sep
2322            return [v.strip() for v in value.split(sep) if v.strip()]
2323
2324        openssl_includes = split_var('OPENSSL_INCLUDES', '-I')
2325        openssl_libdirs = split_var('OPENSSL_LDFLAGS', '-L')
2326        openssl_libs = split_var('OPENSSL_LIBS', '-l')
2327        if not openssl_libs:
2328            # libssl and libcrypto not found
2329            self.missing.extend(['_ssl', '_hashlib'])
2330            return None, None
2331
2332        # Find OpenSSL includes
2333        ssl_incs = find_file(
2334            'openssl/ssl.h', self.inc_dirs, openssl_includes
2335        )
2336        if ssl_incs is None:
2337            self.missing.extend(['_ssl', '_hashlib'])
2338            return None, None
2339
2340        # OpenSSL 1.0.2 uses Kerberos for KRB5 ciphers
2341        krb5_h = find_file(
2342            'krb5.h', self.inc_dirs,
2343            ['/usr/kerberos/include']
2344        )
2345        if krb5_h:
2346            ssl_incs.extend(krb5_h)
2347
2348        if config_vars.get("HAVE_X509_VERIFY_PARAM_SET1_HOST"):
2349            self.add(Extension(
2350                '_ssl', ['_ssl.c'],
2351                include_dirs=openssl_includes,
2352                library_dirs=openssl_libdirs,
2353                libraries=openssl_libs,
2354                depends=['socketmodule.h', '_ssl/debughelpers.c'])
2355            )
2356        else:
2357            self.missing.append('_ssl')
2358
2359        self.add(Extension('_hashlib', ['_hashopenssl.c'],
2360                           depends=['hashlib.h'],
2361                           include_dirs=openssl_includes,
2362                           library_dirs=openssl_libdirs,
2363                           libraries=openssl_libs))
2364
2365    def detect_hash_builtins(self):
2366        # By default we always compile these even when OpenSSL is available
2367        # (issue #14693). It's harmless and the object code is tiny
2368        # (40-50 KiB per module, only loaded when actually used).  Modules can
2369        # be disabled via the --with-builtin-hashlib-hashes configure flag.
2370        supported = {"md5", "sha1", "sha256", "sha512", "sha3", "blake2"}
2371
2372        configured = sysconfig.get_config_var("PY_BUILTIN_HASHLIB_HASHES")
2373        configured = configured.strip('"').lower()
2374        configured = {
2375            m.strip() for m in configured.split(",")
2376        }
2377
2378        self.disabled_configure.extend(
2379            sorted(supported.difference(configured))
2380        )
2381
2382        if "sha256" in configured:
2383            self.add(Extension(
2384                '_sha256', ['sha256module.c'],
2385                extra_compile_args=['-DPy_BUILD_CORE_MODULE'],
2386                depends=['hashlib.h']
2387            ))
2388
2389        if "sha512" in configured:
2390            self.add(Extension(
2391                '_sha512', ['sha512module.c'],
2392                extra_compile_args=['-DPy_BUILD_CORE_MODULE'],
2393                depends=['hashlib.h']
2394            ))
2395
2396        if "md5" in configured:
2397            self.add(Extension(
2398                '_md5', ['md5module.c'],
2399                depends=['hashlib.h']
2400            ))
2401
2402        if "sha1" in configured:
2403            self.add(Extension(
2404                '_sha1', ['sha1module.c'],
2405                depends=['hashlib.h']
2406            ))
2407
2408        if "blake2" in configured:
2409            blake2_deps = glob(
2410                os.path.join(escape(self.srcdir), 'Modules/_blake2/impl/*')
2411            )
2412            blake2_deps.append('hashlib.h')
2413            self.add(Extension(
2414                '_blake2',
2415                [
2416                    '_blake2/blake2module.c',
2417                    '_blake2/blake2b_impl.c',
2418                    '_blake2/blake2s_impl.c'
2419                ],
2420                depends=blake2_deps
2421            ))
2422
2423        if "sha3" in configured:
2424            sha3_deps = glob(
2425                os.path.join(escape(self.srcdir), 'Modules/_sha3/kcp/*')
2426            )
2427            sha3_deps.append('hashlib.h')
2428            self.add(Extension(
2429                '_sha3',
2430                ['_sha3/sha3module.c'],
2431                depends=sha3_deps
2432            ))
2433
2434    def detect_nis(self):
2435        if MS_WINDOWS or CYGWIN or HOST_PLATFORM == 'qnx6':
2436            self.missing.append('nis')
2437            return
2438
2439        libs = []
2440        library_dirs = []
2441        includes_dirs = []
2442
2443        # bpo-32521: glibc has deprecated Sun RPC for some time. Fedora 28
2444        # moved headers and libraries to libtirpc and libnsl. The headers
2445        # are in tircp and nsl sub directories.
2446        rpcsvc_inc = find_file(
2447            'rpcsvc/yp_prot.h', self.inc_dirs,
2448            [os.path.join(inc_dir, 'nsl') for inc_dir in self.inc_dirs]
2449        )
2450        rpc_inc = find_file(
2451            'rpc/rpc.h', self.inc_dirs,
2452            [os.path.join(inc_dir, 'tirpc') for inc_dir in self.inc_dirs]
2453        )
2454        if rpcsvc_inc is None or rpc_inc is None:
2455            # not found
2456            self.missing.append('nis')
2457            return
2458        includes_dirs.extend(rpcsvc_inc)
2459        includes_dirs.extend(rpc_inc)
2460
2461        if self.compiler.find_library_file(self.lib_dirs, 'nsl'):
2462            libs.append('nsl')
2463        else:
2464            # libnsl-devel: check for libnsl in nsl/ subdirectory
2465            nsl_dirs = [os.path.join(lib_dir, 'nsl') for lib_dir in self.lib_dirs]
2466            libnsl = self.compiler.find_library_file(nsl_dirs, 'nsl')
2467            if libnsl is not None:
2468                library_dirs.append(os.path.dirname(libnsl))
2469                libs.append('nsl')
2470
2471        if self.compiler.find_library_file(self.lib_dirs, 'tirpc'):
2472            libs.append('tirpc')
2473
2474        self.add(Extension('nis', ['nismodule.c'],
2475                           libraries=libs,
2476                           library_dirs=library_dirs,
2477                           include_dirs=includes_dirs))
2478
2479
2480class PyBuildInstall(install):
2481    # Suppress the warning about installation into the lib_dynload
2482    # directory, which is not in sys.path when running Python during
2483    # installation:
2484    def initialize_options (self):
2485        install.initialize_options(self)
2486        self.warn_dir=0
2487
2488    # Customize subcommands to not install an egg-info file for Python
2489    sub_commands = [('install_lib', install.has_lib),
2490                    ('install_headers', install.has_headers),
2491                    ('install_scripts', install.has_scripts),
2492                    ('install_data', install.has_data)]
2493
2494
2495class PyBuildInstallLib(install_lib):
2496    # Do exactly what install_lib does but make sure correct access modes get
2497    # set on installed directories and files. All installed files with get
2498    # mode 644 unless they are a shared library in which case they will get
2499    # mode 755. All installed directories will get mode 755.
2500
2501    # this is works for EXT_SUFFIX too, which ends with SHLIB_SUFFIX
2502    shlib_suffix = sysconfig.get_config_var("SHLIB_SUFFIX")
2503
2504    def install(self):
2505        outfiles = install_lib.install(self)
2506        self.set_file_modes(outfiles, 0o644, 0o755)
2507        self.set_dir_modes(self.install_dir, 0o755)
2508        return outfiles
2509
2510    def set_file_modes(self, files, defaultMode, sharedLibMode):
2511        if not files: return
2512
2513        for filename in files:
2514            if os.path.islink(filename): continue
2515            mode = defaultMode
2516            if filename.endswith(self.shlib_suffix): mode = sharedLibMode
2517            log.info("changing mode of %s to %o", filename, mode)
2518            if not self.dry_run: os.chmod(filename, mode)
2519
2520    def set_dir_modes(self, dirname, mode):
2521        for dirpath, dirnames, fnames in os.walk(dirname):
2522            if os.path.islink(dirpath):
2523                continue
2524            log.info("changing mode of %s to %o", dirpath, mode)
2525            if not self.dry_run: os.chmod(dirpath, mode)
2526
2527
2528class PyBuildScripts(build_scripts):
2529    def copy_scripts(self):
2530        outfiles, updated_files = build_scripts.copy_scripts(self)
2531        fullversion = '-{0[0]}.{0[1]}'.format(sys.version_info)
2532        minoronly = '.{0[1]}'.format(sys.version_info)
2533        newoutfiles = []
2534        newupdated_files = []
2535        for filename in outfiles:
2536            if filename.endswith('2to3'):
2537                newfilename = filename + fullversion
2538            else:
2539                newfilename = filename + minoronly
2540            log.info('renaming %s to %s', filename, newfilename)
2541            os.rename(filename, newfilename)
2542            newoutfiles.append(newfilename)
2543            if filename in updated_files:
2544                newupdated_files.append(newfilename)
2545        return newoutfiles, newupdated_files
2546
2547
2548def main():
2549    set_compiler_flags('CFLAGS', 'PY_CFLAGS_NODIST')
2550    set_compiler_flags('LDFLAGS', 'PY_LDFLAGS_NODIST')
2551
2552    class DummyProcess:
2553        """Hack for parallel build"""
2554        ProcessPoolExecutor = None
2555
2556    sys.modules['concurrent.futures.process'] = DummyProcess
2557    validate_tzpath()
2558
2559    # turn off warnings when deprecated modules are imported
2560    import warnings
2561    warnings.filterwarnings("ignore",category=DeprecationWarning)
2562    setup(# PyPI Metadata (PEP 301)
2563          name = "Python",
2564          version = sys.version.split()[0],
2565          url = "http://www.python.org/%d.%d" % sys.version_info[:2],
2566          maintainer = "Guido van Rossum and the Python community",
2567          maintainer_email = "python-dev@python.org",
2568          description = "A high-level object-oriented programming language",
2569          long_description = SUMMARY.strip(),
2570          license = "PSF license",
2571          classifiers = [x for x in CLASSIFIERS.split("\n") if x],
2572          platforms = ["Many"],
2573
2574          # Build info
2575          cmdclass = {'build_ext': PyBuildExt,
2576                      'build_scripts': PyBuildScripts,
2577                      'install': PyBuildInstall,
2578                      'install_lib': PyBuildInstallLib},
2579          # The struct module is defined here, because build_ext won't be
2580          # called unless there's at least one extension module defined.
2581          ext_modules=[Extension('_struct', ['_struct.c'])],
2582
2583          # If you change the scripts installed here, you also need to
2584          # check the PyBuildScripts command above, and change the links
2585          # created by the bininstall target in Makefile.pre.in
2586          scripts = ["Tools/scripts/pydoc3", "Tools/scripts/idle3",
2587                     "Tools/scripts/2to3"]
2588        )
2589
2590# --install-platlib
2591if __name__ == '__main__':
2592    main()
2593