summaryrefslogtreecommitdiffstats
path: root/setup.py
diff options
context:
space:
mode:
authorErlend Egeberg Aasland <erlend.aasland@innova.no>2022-03-31 10:19:08 (GMT)
committerGitHub <noreply@github.com>2022-03-31 10:19:08 (GMT)
commitb36d222110d0d6d84dc8e973ca87d976c2423f5d (patch)
tree400ef6d69aad09d5e95ad89b64f56c60959bf175 /setup.py
parent7fc39a21cb85163a456eab91b52e5fe85e7f7e3e (diff)
downloadcpython-b36d222110d0d6d84dc8e973ca87d976c2423f5d.zip
cpython-b36d222110d0d6d84dc8e973ca87d976c2423f5d.tar.gz
cpython-b36d222110d0d6d84dc8e973ca87d976c2423f5d.tar.bz2
bpo-45847: Port _tkinter to PY_STDLIB_MOD (GH-31698)
- Remove ``--with-tclk-*`` options from `configure` - Use pkg-config to detect `_tkinter` dependencies (Tcl/Tk, X11) - Manual override via environment variables `TCLTK_CFLAGS` and `TCLTK_LIBS`
Diffstat (limited to 'setup.py')
-rw-r--r--setup.py381
1 files changed, 2 insertions, 379 deletions
diff --git a/setup.py b/setup.py
index 070ae98..a1a24ce 100644
--- a/setup.py
+++ b/setup.py
@@ -213,28 +213,6 @@ def macosx_sdk_root():
return MACOS_SDK_ROOT
-def macosx_sdk_specified():
- """Returns true if an SDK was explicitly configured.
-
- True if an SDK was selected at configure time, either by specifying
- --enable-universalsdk=(something other than no or /) or by adding a
- -isysroot option to CFLAGS. In some cases, like when making
- decisions about macOS Tk framework paths, we need to be able to
- know whether the user explicitly asked to build with an SDK versus
- the implicit use of an SDK when header files are no longer
- installed on a running system by the Command Line Tools.
- """
- global MACOS_SDK_SPECIFIED
-
- # If already called, return cached result.
- if MACOS_SDK_SPECIFIED:
- return MACOS_SDK_SPECIFIED
-
- # Find the sdk root and set MACOS_SDK_SPECIFIED
- macosx_sdk_root()
- return MACOS_SDK_SPECIFIED
-
-
def is_macosx_sdk_path(path):
"""
Returns True if 'path' can be located in a macOS SDK
@@ -292,59 +270,6 @@ def find_file(filename, std_dirs, paths):
return None
-def find_library_file(compiler, libname, std_dirs, paths):
- result = compiler.find_library_file(std_dirs + paths, libname)
- if result is None:
- return None
-
- if MACOS:
- sysroot = macosx_sdk_root()
-
- # Check whether the found file is in one of the standard directories
- dirname = os.path.dirname(result)
- for p in std_dirs:
- # Ensure path doesn't end with path separator
- p = p.rstrip(os.sep)
-
- if MACOS and is_macosx_sdk_path(p):
- # Note that, as of Xcode 7, Apple SDKs may contain textual stub
- # libraries with .tbd extensions rather than the normal .dylib
- # shared libraries installed in /. The Apple compiler tool
- # chain handles this transparently but it can cause problems
- # for programs that are being built with an SDK and searching
- # for specific libraries. Distutils find_library_file() now
- # knows to also search for and return .tbd files. But callers
- # of find_library_file need to keep in mind that the base filename
- # of the returned SDK library file might have a different extension
- # from that of the library file installed on the running system,
- # for example:
- # /Applications/Xcode.app/Contents/Developer/Platforms/
- # MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/
- # usr/lib/libedit.tbd
- # vs
- # /usr/lib/libedit.dylib
- if os.path.join(sysroot, p[1:]) == dirname:
- return [ ]
-
- if p == dirname:
- return [ ]
-
- # Otherwise, it must have been in one of the additional directories,
- # so we have to figure out which one.
- for p in paths:
- # Ensure path doesn't end with path separator
- p = p.rstrip(os.sep)
-
- if MACOS and is_macosx_sdk_path(p):
- if os.path.join(sysroot, p[1:]) == dirname:
- return [ p ]
-
- if p == dirname:
- return [p]
- else:
- assert False, "Internal error: Path not found in std_dirs or paths"
-
-
def validate_tzpath():
base_tzpath = sysconfig.get_config_var('TZPATH')
if not base_tzpath:
@@ -1433,8 +1358,7 @@ class PyBuildExt(build_ext):
self.detect_decimal()
self.detect_ctypes()
self.detect_multiprocessing()
- if not self.detect_tkinter():
- self.missing.append('_tkinter')
+ self.detect_tkinter()
self.detect_uuid()
# Uncomment the next line if you want to play with xxmodule.c
@@ -1443,309 +1367,8 @@ class PyBuildExt(build_ext):
self.addext(Extension('xxlimited', ['xxlimited.c']))
self.addext(Extension('xxlimited_35', ['xxlimited_35.c']))
- def detect_tkinter_fromenv(self):
- # Build _tkinter using the Tcl/Tk locations specified by
- # the _TCLTK_INCLUDES and _TCLTK_LIBS environment variables.
- # This method is meant to be invoked by detect_tkinter().
- #
- # The variables can be set via one of the following ways.
- #
- # - Automatically, at configuration time, by using pkg-config.
- # The tool is called by the configure script.
- # Additional pkg-config configuration paths can be set via the
- # PKG_CONFIG_PATH environment variable.
- #
- # PKG_CONFIG_PATH=".../lib/pkgconfig" ./configure ...
- #
- # - Explicitly, at configuration time by setting both
- # --with-tcltk-includes and --with-tcltk-libs.
- #
- # ./configure ... \
- # --with-tcltk-includes="-I/path/to/tclincludes \
- # -I/path/to/tkincludes"
- # --with-tcltk-libs="-L/path/to/tcllibs -ltclm.n \
- # -L/path/to/tklibs -ltkm.n"
- #
- # - Explicitly, at compile time, by passing TCLTK_INCLUDES and
- # TCLTK_LIBS to the make target.
- # This will override any configuration-time option.
- #
- # make TCLTK_INCLUDES="..." TCLTK_LIBS="..."
- #
- # This can be useful for building and testing tkinter with multiple
- # versions of Tcl/Tk. Note that a build of Tk depends on a particular
- # build of Tcl so you need to specify both arguments and use care when
- # overriding.
-
- # The _TCLTK variables are created in the Makefile sharedmods target.
- tcltk_includes = os.environ.get('_TCLTK_INCLUDES')
- tcltk_libs = os.environ.get('_TCLTK_LIBS')
- if not (tcltk_includes and tcltk_libs):
- # Resume default configuration search.
- return False
-
- extra_compile_args = tcltk_includes.split()
- extra_link_args = tcltk_libs.split()
- self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
- define_macros=[('WITH_APPINIT', 1)],
- extra_compile_args = extra_compile_args,
- extra_link_args = extra_link_args))
- return True
-
- def detect_tkinter_darwin(self):
- # Build default _tkinter on macOS using Tcl and Tk frameworks.
- # This method is meant to be invoked by detect_tkinter().
- #
- # The macOS native Tk (AKA Aqua Tk) and Tcl are most commonly
- # built and installed as macOS framework bundles. However,
- # for several reasons, we cannot take full advantage of the
- # Apple-supplied compiler chain's -framework options here.
- # Instead, we need to find and pass to the compiler the
- # absolute paths of the Tcl and Tk headers files we want to use
- # and the absolute path to the directory containing the Tcl
- # and Tk frameworks for linking.
- #
- # We want to handle here two common use cases on macOS:
- # 1. Build and link with system-wide third-party or user-built
- # Tcl and Tk frameworks installed in /Library/Frameworks.
- # 2. Build and link using a user-specified macOS SDK so that the
- # built Python can be exported to other systems. In this case,
- # search only the SDK's /Library/Frameworks (normally empty)
- # and /System/Library/Frameworks.
- #
- # Any other use cases are handled either by detect_tkinter_fromenv(),
- # or detect_tkinter(). The former handles non-standard locations of
- # Tcl/Tk, defined via the _TCLTK_INCLUDES and _TCLTK_LIBS environment
- # variables. The latter handles any Tcl/Tk versions installed in
- # standard Unix directories.
- #
- # It would be desirable to also handle here the case where
- # you want to build and link with a framework build of Tcl and Tk
- # that is not in /Library/Frameworks, say, in your private
- # $HOME/Library/Frameworks directory or elsewhere. It turns
- # out to be difficult to make that work automatically here
- # without bringing into play more tools and magic. That case
- # can be handled using a recipe with the right arguments
- # to detect_tkinter_fromenv().
- #
- # Note also that the fallback case here is to try to use the
- # Apple-supplied Tcl and Tk frameworks in /System/Library but
- # be forewarned that they are deprecated by Apple and typically
- # out-of-date and buggy; their use should be avoided if at
- # all possible by installing a newer version of Tcl and Tk in
- # /Library/Frameworks before building Python without
- # an explicit SDK or by configuring build arguments explicitly.
-
- from os.path import join, exists
-
- sysroot = macosx_sdk_root() # path to the SDK or '/'
-
- if macosx_sdk_specified():
- # Use case #2: an SDK other than '/' was specified.
- # Only search there.
- framework_dirs = [
- join(sysroot, 'Library', 'Frameworks'),
- join(sysroot, 'System', 'Library', 'Frameworks'),
- ]
- else:
- # Use case #1: no explicit SDK selected.
- # Search the local system-wide /Library/Frameworks,
- # not the one in the default SDK, otherwise fall back to
- # /System/Library/Frameworks whose header files may be in
- # the default SDK or, on older systems, actually installed.
- framework_dirs = [
- join('/', 'Library', 'Frameworks'),
- join(sysroot, 'System', 'Library', 'Frameworks'),
- ]
-
- # Find the directory that contains the Tcl.framework and
- # Tk.framework bundles.
- for F in framework_dirs:
- # both Tcl.framework and Tk.framework should be present
- for fw in 'Tcl', 'Tk':
- if not exists(join(F, fw + '.framework')):
- break
- else:
- # ok, F is now directory with both frameworks. Continue
- # building
- break
- else:
- # Tk and Tcl frameworks not found. Normal "unix" tkinter search
- # will now resume.
- return False
-
- include_dirs = [
- join(F, fw + '.framework', H)
- for fw in ('Tcl', 'Tk')
- for H in ('Headers',)
- ]
-
- # Add the base framework directory as well
- compile_args = ['-F', F]
-
- # Do not build tkinter for archs that this Tk was not built with.
- cflags = sysconfig.get_config_vars('CFLAGS')[0]
- archs = re.findall(r'-arch\s+(\w+)', cflags)
-
- tmpfile = os.path.join(self.build_temp, 'tk.arch')
- if not os.path.exists(self.build_temp):
- os.makedirs(self.build_temp)
-
- run_command(
- "file {}/Tk.framework/Tk | grep 'for architecture' > {}".format(F, tmpfile)
- )
- with open(tmpfile) as fp:
- detected_archs = []
- for ln in fp:
- a = ln.split()[-1]
- if a in archs:
- detected_archs.append(ln.split()[-1])
- os.unlink(tmpfile)
-
- arch_args = []
- for a in detected_archs:
- arch_args.append('-arch')
- arch_args.append(a)
-
- compile_args += arch_args
- link_args = [','.join(['-Wl', '-F', F, '-framework', 'Tcl', '-framework', 'Tk']), *arch_args]
-
- # The X11/xlib.h file bundled in the Tk sources can cause function
- # prototype warnings from the compiler. Since we cannot easily fix
- # that, suppress the warnings here instead.
- if '-Wstrict-prototypes' in cflags.split():
- compile_args.append('-Wno-strict-prototypes')
-
- self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
- define_macros=[('WITH_APPINIT', 1)],
- include_dirs=include_dirs,
- libraries=[],
- extra_compile_args=compile_args,
- extra_link_args=link_args))
- return True
-
def detect_tkinter(self):
- # The _tkinter module.
- #
- # Detection of Tcl/Tk is attempted in the following order:
- # - Through environment variables.
- # - Platform specific detection of Tcl/Tk (currently only macOS).
- # - Search of various standard Unix header/library paths.
- #
- # Detection stops at the first successful method.
-
- # Check for Tcl and Tk at the locations indicated by _TCLTK_INCLUDES
- # and _TCLTK_LIBS environment variables.
- if self.detect_tkinter_fromenv():
- return True
-
- # Rather than complicate the code below, detecting and building
- # AquaTk is a separate method. Only one Tkinter will be built on
- # Darwin - either AquaTk, if it is found, or X11 based Tk.
- if (MACOS and self.detect_tkinter_darwin()):
- return True
-
- # Assume we haven't found any of the libraries or include files
- # The versions with dots are used on Unix, and the versions without
- # dots on Windows, for detection by cygwin.
- tcllib = tklib = tcl_includes = tk_includes = None
- for version in ['8.6', '86', '8.5', '85', '8.4', '84', '8.3', '83',
- '8.2', '82', '8.1', '81', '8.0', '80']:
- tklib = self.compiler.find_library_file(self.lib_dirs,
- 'tk' + version)
- tcllib = self.compiler.find_library_file(self.lib_dirs,
- 'tcl' + version)
- if tklib and tcllib:
- # Exit the loop when we've found the Tcl/Tk libraries
- break
-
- # Now check for the header files
- if tklib and tcllib:
- # Check for the include files on Debian and {Free,Open}BSD, where
- # they're put in /usr/include/{tcl,tk}X.Y
- dotversion = version
- if '.' not in dotversion and "bsd" in HOST_PLATFORM.lower():
- # OpenBSD and FreeBSD use Tcl/Tk library names like libtcl83.a,
- # but the include subdirs are named like .../include/tcl8.3.
- dotversion = dotversion[:-1] + '.' + dotversion[-1]
- tcl_include_sub = []
- tk_include_sub = []
- for dir in self.inc_dirs:
- tcl_include_sub += [dir + os.sep + "tcl" + dotversion]
- tk_include_sub += [dir + os.sep + "tk" + dotversion]
- tk_include_sub += tcl_include_sub
- tcl_includes = find_file('tcl.h', self.inc_dirs, tcl_include_sub)
- tk_includes = find_file('tk.h', self.inc_dirs, tk_include_sub)
-
- if (tcllib is None or tklib is None or
- tcl_includes is None or tk_includes is None):
- self.announce("INFO: Can't locate Tcl/Tk libs and/or headers", 2)
- return False
-
- # OK... everything seems to be present for Tcl/Tk.
-
- include_dirs = []
- libs = []
- defs = []
- added_lib_dirs = []
- for dir in tcl_includes + tk_includes:
- if dir not in include_dirs:
- include_dirs.append(dir)
-
- # Check for various platform-specific directories
- if HOST_PLATFORM == 'sunos5':
- include_dirs.append('/usr/openwin/include')
- added_lib_dirs.append('/usr/openwin/lib')
- elif os.path.exists('/usr/X11R6/include'):
- include_dirs.append('/usr/X11R6/include')
- added_lib_dirs.append('/usr/X11R6/lib64')
- added_lib_dirs.append('/usr/X11R6/lib')
- elif os.path.exists('/usr/X11R5/include'):
- include_dirs.append('/usr/X11R5/include')
- added_lib_dirs.append('/usr/X11R5/lib')
- else:
- # Assume default location for X11
- include_dirs.append('/usr/X11/include')
- added_lib_dirs.append('/usr/X11/lib')
-
- # If Cygwin, then verify that X is installed before proceeding
- if CYGWIN:
- x11_inc = find_file('X11/Xlib.h', [], include_dirs)
- if x11_inc is None:
- return False
-
- # Check for BLT extension
- if self.compiler.find_library_file(self.lib_dirs + added_lib_dirs,
- 'BLT8.0'):
- defs.append( ('WITH_BLT', 1) )
- libs.append('BLT8.0')
- elif self.compiler.find_library_file(self.lib_dirs + added_lib_dirs,
- 'BLT'):
- defs.append( ('WITH_BLT', 1) )
- libs.append('BLT')
-
- # Add the Tcl/Tk libraries
- libs.append('tk'+ version)
- libs.append('tcl'+ version)
-
- # Finally, link with the X11 libraries (not appropriate on cygwin)
- if not CYGWIN:
- libs.append('X11')
-
- # XXX handle these, but how to detect?
- # *** Uncomment and edit for PIL (TkImaging) extension only:
- # -DWITH_PIL -I../Extensions/Imaging/libImaging tkImaging.c \
- # *** Uncomment and edit for TOGL extension only:
- # -DWITH_TOGL togl.c \
- # *** Uncomment these for TOGL extension only:
- # -lGL -lGLU -lXext -lXmu \
-
- self.add(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c'],
- define_macros=[('WITH_APPINIT', 1)] + defs,
- include_dirs=include_dirs,
- libraries=libs,
- library_dirs=added_lib_dirs))
- return True
+ self.addext(Extension('_tkinter', ['_tkinter.c', 'tkappinit.c']))
def configure_ctypes(self, ext):
return True