Issue #15663: OS X installer builtin Tcl/Tk support
Make it easier for users to make use of the backup _tkinter linked
with the third-party Tcl and Tk frameworks in /Library/Frameworks.
The two tkinter variants are now installed in separate directories
under a new lib-tkinter. This allows per-user selection by
manipulating sys.path, directly or with PYTHONPATH. If this
proves useful, we can supply a more convenient user interface
to supply the paths. For now, this remains somewhat experimental.
diff --git a/Mac/BuildScript/README.txt b/Mac/BuildScript/README.txt
index 9d1f59c..38470c5 100644
--- a/Mac/BuildScript/README.txt
+++ b/Mac/BuildScript/README.txt
@@ -68,28 +68,28 @@
- requires ActiveState Tcl/Tk 8.5.14 (or later) to be installed for building
* Beginning with Python 3.3.3, this installer now includes its own
- private copy of Tcl and Tk 8.5.15 libraries and thus is no longer
+ builtin copy of Tcl and Tk 8.5.15 libraries and thus is no longer
dependent on the buggy releases of Aqua Cocoa Tk 8.5 shipped with
OS X 10.6 or on installing a newer third-party version of Tcl/Tk
in /Library/Frameworks, such as from ActiveState. If it is
necessary to fallback to using a third-party Tcl/Tk because of
- a problem with the private Tcl/Tk, there is a backup version of
+ a problem with the builtin Tcl/Tk, there is a backup version of
the _tkinter extension included which will dynamically link to
Tcl and Tk frameworks in /Library/Frameworks as in previous releases.
To enable (for all users of this Python 3.3)::
sudo bash
cd /Library/Frameworks/Python.framework/Versions/3.3
- cd ./lib/python3.3/lib-dynload
- cp -p _tkinter.so.framework _tkinter.so
+ cd ./lib/python3.3
+ cp -p ./lib-tkinter/library/_tkinter.so ./lib-dynload
exit
- To restore using Python's private versions of Tcl and Tk::
+ To restore using Python's builtin versions of Tcl and Tk::
sudo bash
cd /Library/Frameworks/Python.framework/Versions/3.3
- cd ./lib/python3.3/lib-dynload
- cp -p _tkinter.so.private _tkinter.so
+ cd ./lib/python3.3
+ cp -p ./lib-tkinter/builtin/_tkinter.so ./lib-dynload
exit
- recommended build environment:
diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py
index ddb067d..69f3ff7 100755
--- a/Mac/BuildScript/build-installer.py
+++ b/Mac/BuildScript/build-installer.py
@@ -565,11 +565,11 @@
]
# For 10.6+ builds, we build two versions of _tkinter:
- # - the traditional version (renamed to _tkinter.so.framework) linked
+ # - the traditional version (renamed to _tkinter_library.so) linked
# with /Library/Frameworks/{Tcl,Tk}.framework
- # - the default version linked with our private copies of Tcl and Tk
+ # - the default version linked with our builtin copies of Tcl and Tk
if DEPTARGET > '10.5':
- EXPECTED_SHARED_LIBS['_tkinter.so.framework'] = \
+ EXPECTED_SHARED_LIBS['_tkinter_library.so'] = \
EXPECTED_SHARED_LIBS['_tkinter.so']
EXPECTED_SHARED_LIBS['_tkinter.so'] = [
"/Library/Frameworks/Python.framework/Versions/%s/lib/libtcl%s.dylib"
@@ -966,18 +966,18 @@
# of Tcl and Cocoa Aqua Tk libs because the Apple-supplied Tk 8.5 is
# out-of-date and has critical bugs. Save the _tkinter.so that was
# linked with /Library/Frameworks/{Tck,Tk}.framework and build
- # another _tkinter.so linked with our private Tcl and Tk libs.
+ # another _tkinter.so linked with our builtin Tcl and Tk libs.
if DEPTARGET > '10.5':
runCommand("find build -name '_tkinter.so' "
- " -execdir mv '{}' '{}'.framework \;")
- print("Running make to rebuild _tkinter")
+ " -execdir mv '{}' _tkinter_library.so \;")
+ print("Running make to build builtin _tkinter")
runCommand("make TCLTK_INCLUDES='-I%s/libraries/usr/local/include' "
"TCLTK_LIBS='-L%s/libraries/usr/local/lib -ltcl8.5 -ltk8.5'"%(
shellQuote(WORKDIR)[1:-1],
shellQuote(WORKDIR)[1:-1]))
- # make a backup copy, just in case
+ # make a copy which will be moved to lib-tkinter later
runCommand("find build -name '_tkinter.so' "
- " -execdir cp -p '{}' '{}'.private \;")
+ " -execdir cp -p '{}' _tkinter_builtin.so \;")
print("Running make install")
runCommand("make install DESTDIR=%s"%(
@@ -999,11 +999,31 @@
'Python.framework', 'Versions', getVersion(),
'lib'))))
+ path_to_lib = os.path.join(rootDir, 'Library', 'Frameworks',
+ 'Python.framework', 'Versions',
+ version, 'lib', 'python%s'%(version,))
+
+ # If we made multiple versions of _tkinter, move them to
+ # their own directories under python lib. This allows
+ # users to select which to import by manipulating sys.path
+ # directly or with PYTHONPATH.
+
+ if DEPTARGET > '10.5':
+ TKINTERS = ['builtin', 'library']
+ tkinter_moves = [('_tkinter_' + tkn + '.so',
+ os.path.join(path_to_lib, 'lib-tkinter', tkn))
+ for tkn in TKINTERS]
+ # Create the destination directories under lib-tkinter.
+ # The permissions and uid/gid will be fixed up next.
+ for tkm in tkinter_moves:
+ os.makedirs(tkm[1])
+
print("Fix file modes")
frmDir = os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework')
gid = grp.getgrnam('admin').gr_gid
shared_lib_error = False
+ moves_list = []
for dirpath, dirnames, filenames in os.walk(frmDir):
for dn in dirnames:
os.chmod(os.path.join(dirpath, dn), STAT_0o775)
@@ -1029,9 +1049,25 @@
% (sl, p))
shared_lib_error = True
+ # If this is a _tkinter variant, move it to its own directory
+ # now that we have fixed its permissions and checked that it
+ # was linked properly. The directory was created earlier.
+ # The files are moved after the entire tree has been walked
+ # since the shared library checking depends on the files
+ # having unique names.
+ if DEPTARGET > '10.5':
+ for tkm in tkinter_moves:
+ if fn == tkm[0]:
+ moves_list.append(
+ (p, os.path.join(tkm[1], '_tkinter.so')))
+
if shared_lib_error:
fatal("Unexpected shared library errors.")
+ # Now do the moves.
+ for ml in moves_list:
+ shutil.move(ml[0], ml[1])
+
if PYTHON_3:
LDVERSION=None
VERSION=None
@@ -1061,10 +1097,6 @@
include_path = '-I%s/libraries/usr/local/include' % (WORKDIR,)
lib_path = '-L%s/libraries/usr/local/lib' % (WORKDIR,)
- path_to_lib = os.path.join(rootDir, 'Library', 'Frameworks',
- 'Python.framework', 'Versions',
- version, 'lib', 'python%s'%(version,))
-
# fix Makefile
path = os.path.join(path_to_lib, 'config' + config_suffix, 'Makefile')
fp = open(path, 'r')