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')