Ticket #58594: setup.py

File setup.py, 101.0 KB (added by Themanwithoutaplan, 5 years ago)

setup.py from 3.8.0b1

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