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.
This commit is contained in:
Ned Deily 2013-10-26 03:16:06 -07:00
parent 7c5ba45fd8
commit 70f213ab11
2 changed files with 51 additions and 19 deletions

View File

@ -67,28 +67,28 @@ for each release.
- requires ActiveState Tcl/Tk 8.5.14 (or later) to be installed for building
* Beginning with Python 2.7.6, 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 2.7)::
sudo bash
cd /Library/Frameworks/Python.framework/Versions/2.7
cd ./lib/python2.7/lib-dynload
cp -p _tkinter.so.framework _tkinter.so
cd ./lib/python2.7
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/2.7
cd ./lib/python2.7/lib-dynload
cp -p _tkinter.so.private _tkinter.so
cd ./lib/python2.7
cp -p ./lib-tkinter/builtin/_tkinter.so ./lib-dynload
exit
- recommended build environment:

View File

@ -565,11 +565,11 @@ def checkEnvironment():
]
# 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 @@ def buildPython():
# 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 @@ def buildPython():
'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 @@ def buildPython():
% (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 @@ def buildPython():
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')