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