From f87cfce45090d4c71d525edce479f39b10658e58 Mon Sep 17 00:00:00 2001 From: Ned Deily Date: Sat, 26 Oct 2013 03:17:44 -0700 Subject: [PATCH] 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. --- Mac/BuildScript/README.txt | 14 ++++---- Mac/BuildScript/build-installer.py | 56 +++++++++++++++++++++++------- 2 files changed, 51 insertions(+), 19 deletions(-) diff --git a/Mac/BuildScript/README.txt b/Mac/BuildScript/README.txt index e070e609434..74194a7233e 100644 --- a/Mac/BuildScript/README.txt +++ b/Mac/BuildScript/README.txt @@ -68,30 +68,30 @@ for each release. - requires ActiveState Tcl/Tk 8.5.15 (or later) to be installed for building * Beginning with Python 3.4 alpha2, 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. Because this is a new feature, it should be considered somewhat experimental and subject to change prior to the final release of Python 3.4. 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.4):: sudo bash cd /Library/Frameworks/Python.framework/Versions/3.4 - cd ./lib/python3.4/lib-dynload - cp -p _tkinter.so.framework _tkinter.so + cd ./lib/python3.4 + 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.4 - cd ./lib/python3.4/lib-dynload - cp -p _tkinter.so.private _tkinter.so + cd ./lib/python3.4 + 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 ddb067d94fc..69f3ff7ee90 100755 --- a/Mac/BuildScript/build-installer.py +++ b/Mac/BuildScript/build-installer.py @@ -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')