Mercurial > cpython-lru_cache-weakref
changeset 77674:ba6ca42919dd
merge heads
| author | Gregory P. Smith <greg@krypto.org> |
|---|---|
| date | Sun, 24 Jun 2012 00:24:31 -0700 |
| parents | 19a6bef57490 (current diff) 8beffdfa29cd (diff) |
| children | e989e7586da6 |
| files | Mac/Tools/fixapplepython23.py |
| diffstat | 8 files changed, 224 insertions(+), 291 deletions(-) [+] |
line wrap: on
line diff
--- a/Doc/library/shutil.rst Sun Jun 24 00:23:47 2012 -0700 +++ b/Doc/library/shutil.rst Sun Jun 24 00:24:31 2012 -0700 @@ -190,14 +190,15 @@ handled by calling a handler specified by *onerror* or, if that is omitted, they raise an exception. - .. warning:: + .. note:: - The default :func:`rmtree` function is susceptible to a symlink attack: - given proper timing and circumstances, attackers can use it to delete - files they wouldn't be able to access otherwise. Thus -- on platforms - that support the necessary fd-based functions -- a safe version of - :func:`rmtree` is used, which isn't vulnerable. In this case - :data:`rmtree_is_safe` is set to True. + On platforms that support the necessary fd-based functions a symlink + attack resistant version of :func:`rmtree` is used by default. On other + platforms, the :func:`rmtree` implementation is susceptible to a + symlink attack: given proper timing and circumstances, attackers can + manipulate symlinks on the filesystem to delete files they wouldn't + be able to access otherwise. Applications can use the :data:`rmtree.avoids_symlink_attacks` function attribute to + determine which case applies. If *onerror* is provided, it must be a callable that accepts three parameters: *function*, *path*, and *excinfo*. @@ -209,16 +210,16 @@ :func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught. .. versionchanged:: 3.3 - Added a safe version that is used automatically if platform supports - fd-based functions. + Added a symlink attack resistant version that is used automatically + if platform supports fd-based functions. -.. data:: rmtree_is_safe + .. data:: rmtree.avoids_symlink_attacks - Indicates whether the current platform and implementation has a symlink - attack-proof version of :func:`rmtree`. Currently this is only true for - platforms supporting fd-based directory access functions. + Indicates whether the current platform and implementation provides a + symlink attack resistant version of :func:`rmtree`. Currently this is + only true for platforms supporting fd-based directory access functions. - .. versionadded:: 3.3 + .. versionadded:: 3.3 .. function:: move(src, dst)
--- a/Doc/whatsnew/3.3.rst Sun Jun 24 00:23:47 2012 -0700 +++ b/Doc/whatsnew/3.3.rst Sun Jun 24 00:24:31 2012 -0700 @@ -1296,6 +1296,11 @@ acts on the symlink itself (or creates one, if relevant). (Contributed by Hynek Schlawack in :issue:`12715`.) +* :func:`~shutil.rmtree` is now resistant to symlink attacks on platforms + which support the new ``dir_fd`` parameter in :func:`os.open` and + :func:`os.unlinkat`. (Contributed by Martin von Löwis and Hynek Schlawack + in :issue:`4489`.) + signal
--- a/Lib/shutil.py Sun Jun 24 00:23:47 2012 -0700 +++ b/Lib/shutil.py Sun Jun 24 00:24:31 2012 -0700 @@ -405,8 +405,9 @@ except os.error: onerror(os.rmdir, path, sys.exc_info()) -rmtree_is_safe = _use_fd_functions = (os.unlink in os.supports_dir_fd and - os.open in os.supports_dir_fd) +_use_fd_functions = (os.unlink in os.supports_dir_fd and + os.open in os.supports_dir_fd) + def rmtree(path, ignore_errors=False, onerror=None): """Recursively delete a directory tree. @@ -449,6 +450,9 @@ else: return _rmtree_unsafe(path, onerror) +# Allow introspection of whether or not the hardening against symlink +# attacks is supported on the current platform +rmtree.avoids_symlink_attacks = _use_fd_functions def _basename(path): # A basename() variant which first strips the trailing slash, if present.
--- a/Lib/test/test_shutil.py Sun Jun 24 00:23:47 2012 -0700 +++ b/Lib/test/test_shutil.py Sun Jun 24 00:24:31 2012 -0700 @@ -487,7 +487,7 @@ def test_rmtree_uses_safe_fd_version_if_available(self): if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd: self.assertTrue(shutil._use_fd_functions) - self.assertTrue(shutil.rmtree_is_safe) + self.assertTrue(shutil.rmtree.avoids_symlink_attacks) tmp_dir = self.mkdtemp() d = os.path.join(tmp_dir, 'a') os.mkdir(d) @@ -502,7 +502,7 @@ shutil._rmtree_safe_fd = real_rmtree else: self.assertFalse(shutil._use_fd_functions) - self.assertFalse(shutil.rmtree_is_safe) + self.assertFalse(shutil.rmtree.avoids_symlink_attacks) def test_rmtree_dont_delete_file(self): # When called on a file instead of a directory, don't delete it.
--- a/Mac/BuildScript/build-installer.py Sun Jun 24 00:23:47 2012 -0700 +++ b/Mac/BuildScript/build-installer.py Sun Jun 24 00:24:31 2012 -0700 @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python """ This script is used to build "official" universal installers on Mac OS X. It requires at least Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK for @@ -12,16 +12,25 @@ Usage: see USAGE variable in the script. """ -import platform, os, sys, getopt, textwrap, shutil, urllib2, stat, time, pwd -import grp +import platform, os, sys, getopt, textwrap, shutil, stat, time, pwd, grp +try: + import urllib2 as urllib_request +except ImportError: + import urllib.request as urllib_request + +STAT_0o755 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR + | stat.S_IRGRP | stat.S_IXGRP + | stat.S_IROTH | stat.S_IXOTH ) + +STAT_0o775 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR + | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP + | stat.S_IROTH | stat.S_IXOTH ) INCLUDE_TIMESTAMP = 1 VERBOSE = 1 from plistlib import Plist -import MacOS - try: from plistlib import writePlist except ImportError: @@ -42,20 +51,35 @@ if ln.startswith(variable): value = ln[len(variable):].strip() return value[1:-1] - raise RuntimeError, "Cannot find variable %s" % variable[:-1] + raise RuntimeError("Cannot find variable %s" % variable[:-1]) + +_cache_getVersion = None def getVersion(): - return grepValue(os.path.join(SRCDIR, 'configure'), 'PACKAGE_VERSION') + global _cache_getVersion + if _cache_getVersion is None: + _cache_getVersion = grepValue( + os.path.join(SRCDIR, 'configure'), 'PACKAGE_VERSION') + return _cache_getVersion def getVersionTuple(): return tuple([int(n) for n in getVersion().split('.')]) +def getVersionMajorMinor(): + return tuple([int(n) for n in getVersion().split('.', 2)]) + +_cache_getFullVersion = None + def getFullVersion(): + global _cache_getFullVersion + if _cache_getFullVersion is not None: + return _cache_getFullVersion fn = os.path.join(SRCDIR, 'Include', 'patchlevel.h') for ln in open(fn): if 'PY_VERSION' in ln: - return ln.split()[-1][1:-1] - raise RuntimeError, "Cannot find full version??" + _cache_getFullVersion = ln.split()[-1][1:-1] + return _cache_getFullVersion + raise RuntimeError("Cannot find full version??") # The directory we'll use to create the build (will be erased and recreated) WORKDIR = "/tmp/_py" @@ -337,7 +361,7 @@ ), ] - if DEPTARGET < '10.4': + if DEPTARGET < '10.4' and not PYTHON_3: result.append( dict( name="PythonSystemFixes", @@ -369,7 +393,7 @@ """ Return the contents of the named file """ - return open(fn, 'rb').read() + return open(fn, 'r').read() def runCommand(commandline): """ @@ -381,7 +405,7 @@ xit = fd.close() if xit is not None: sys.stdout.write(data) - raise RuntimeError, "command failed: %s"%(commandline,) + raise RuntimeError("command failed: %s"%(commandline,)) if VERBOSE: sys.stdout.write(data); sys.stdout.flush() @@ -392,7 +416,7 @@ xit = fd.close() if xit is not None: sys.stdout.write(data) - raise RuntimeError, "command failed: %s"%(commandline,) + raise RuntimeError("command failed: %s"%(commandline,)) return data @@ -461,12 +485,12 @@ for ev in list(os.environ): for prefix in environ_var_prefixes: if ev.startswith(prefix) : - print "INFO: deleting environment variable %s=%s" % ( - ev, os.environ[ev]) + print("INFO: deleting environment variable %s=%s" % ( + ev, os.environ[ev])) del os.environ[ev] os.environ['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin' - print "Setting default PATH: %s"%(os.environ['PATH']) + print("Setting default PATH: %s"%(os.environ['PATH'])) def parseOptions(args=None): @@ -483,18 +507,18 @@ options, args = getopt.getopt(args, '?hb', [ 'build-dir=', 'third-party=', 'sdk-path=' , 'src-dir=', 'dep-target=', 'universal-archs=', 'help' ]) - except getopt.error, msg: - print msg + except getopt.GetoptError: + print(sys.exc_info()[1]) sys.exit(1) if args: - print "Additional arguments" + print("Additional arguments") sys.exit(1) deptarget = None for k, v in options: if k in ('-h', '-?', '--help'): - print USAGE + print(USAGE) sys.exit(0) elif k in ('-d', '--build-dir'): @@ -522,10 +546,10 @@ # target DEPTARGET = default_target_map.get(v, '10.3') else: - raise NotImplementedError, v + raise NotImplementedError(v) else: - raise NotImplementedError, k + raise NotImplementedError(k) SRCDIR=os.path.abspath(SRCDIR) WORKDIR=os.path.abspath(WORKDIR) @@ -534,15 +558,15 @@ CC=target_cc_map[DEPTARGET] - print "Settings:" - print " * Source directory:", SRCDIR - print " * Build directory: ", WORKDIR - print " * SDK location: ", SDKPATH - print " * Third-party source:", DEPSRC - print " * Deployment target:", DEPTARGET - print " * Universal architectures:", ARCHLIST - print " * C compiler:", CC - print "" + print("Settings:") + print(" * Source directory:", SRCDIR) + print(" * Build directory: ", WORKDIR) + print(" * SDK location: ", SDKPATH) + print(" * Third-party source:", DEPSRC) + print(" * Deployment target:", DEPTARGET) + print(" * Universal architectures:", ARCHLIST) + print(" * C compiler:", CC) + print("") @@ -587,7 +611,7 @@ xit = fp.close() if xit is not None: sys.stdout.write(data) - raise RuntimeError, "Cannot extract %s"%(archiveName,) + raise RuntimeError("Cannot extract %s"%(archiveName,)) return os.path.join(builddir, retval) @@ -609,9 +633,9 @@ pass else: if KNOWNSIZES.get(url) == size: - print "Using existing file for", url + print("Using existing file for", url) return - fpIn = urllib2.urlopen(url) + fpIn = urllib_request.urlopen(url) fpOut = open(fname, 'wb') block = fpIn.read(10240) try: @@ -648,15 +672,15 @@ if os.path.exists(sourceArchive): - print "Using local copy of %s"%(name,) + print("Using local copy of %s"%(name,)) else: - print "Did not find local copy of %s"%(name,) - print "Downloading %s"%(name,) + print("Did not find local copy of %s"%(name,)) + print("Downloading %s"%(name,)) downloadURL(url, sourceArchive) - print "Archive for %s stored as %s"%(name, sourceArchive) + print("Archive for %s stored as %s"%(name, sourceArchive)) - print "Extracting archive for %s"%(name,) + print("Extracting archive for %s"%(name,)) buildDir=os.path.join(WORKDIR, '_bld') if not os.path.exists(buildDir): os.mkdir(buildDir) @@ -722,14 +746,14 @@ if 'configure_env' in recipe: configure_args.insert(0, recipe['configure_env']) - print "Running configure for %s"%(name,) + print("Running configure for %s"%(name,)) runCommand(' '.join(configure_args) + ' 2>&1') - print "Running install for %s"%(name,) + print("Running install for %s"%(name,)) runCommand('{ ' + install + ' ;} 2>&1') - print "Done %s"%(name,) - print "" + print("Done %s"%(name,)) + print("") os.chdir(curdir) @@ -737,9 +761,9 @@ """ Build our dependencies into $WORKDIR/libraries/usr/local """ - print "" - print "Building required libraries" - print "" + print("") + print("Building required libraries") + print("") universal = os.path.join(WORKDIR, 'libraries') os.mkdir(universal) os.makedirs(os.path.join(universal, 'usr', 'local', 'lib')) @@ -753,7 +777,7 @@ def buildPythonDocs(): # This stores the documentation as Resources/English.lproj/Documentation # inside the framwork. pydoc and IDLE will pick it up there. - print "Install python documentation" + print("Install python documentation") rootDir = os.path.join(WORKDIR, '_root') buildDir = os.path.join('../../Doc') docdir = os.path.join(rootDir, 'pydocs') @@ -768,7 +792,7 @@ def buildPython(): - print "Building a universal python for %s architectures" % UNIVERSALARCHS + print("Building a universal python for %s architectures" % UNIVERSALARCHS) buildDir = os.path.join(WORKDIR, '_bld', 'python') rootDir = os.path.join(WORKDIR, '_root') @@ -796,7 +820,7 @@ # will find them during its extension import sanity checks. os.environ['DYLD_LIBRARY_PATH'] = os.path.join(WORKDIR, 'libraries', 'usr', 'local', 'lib') - print "Running configure..." + print("Running configure...") runCommand("%s -C --enable-framework --enable-universalsdk=%s " "--with-universal-archs=%s " "%s " @@ -808,19 +832,19 @@ shellQuote(WORKDIR)[1:-1], shellQuote(WORKDIR)[1:-1])) - print "Running make" + print("Running make") runCommand("make") - print "Running make install" + print("Running make install") runCommand("make install DESTDIR=%s"%( shellQuote(rootDir))) - print "Running make frameworkinstallextras" + print("Running make frameworkinstallextras") runCommand("make frameworkinstallextras DESTDIR=%s"%( shellQuote(rootDir))) del os.environ['DYLD_LIBRARY_PATH'] - print "Copying required shared libraries" + print("Copying required shared libraries") if os.path.exists(os.path.join(WORKDIR, 'libraries', 'Library')): runCommand("mv %s/* %s"%( shellQuote(os.path.join( @@ -831,13 +855,13 @@ 'Python.framework', 'Versions', getVersion(), 'lib')))) - print "Fix file modes" + print("Fix file modes") frmDir = os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework') gid = grp.getgrnam('admin').gr_gid for dirpath, dirnames, filenames in os.walk(frmDir): for dn in dirnames: - os.chmod(os.path.join(dirpath, dn), 0775) + os.chmod(os.path.join(dirpath, dn), STAT_0o775) os.chown(os.path.join(dirpath, dn), -1, gid) @@ -918,17 +942,17 @@ # This one is not handy as a template variable data = data.replace('$PYTHONFRAMEWORKINSTALLDIR', '/Library/Frameworks/Python.framework') - fp = open(outPath, 'wb') + fp = open(outPath, 'w') fp.write(data) fp.close() def patchScript(inPath, outPath): data = fileContents(inPath) data = data.replace('@PYVER@', getVersion()) - fp = open(outPath, 'wb') + fp = open(outPath, 'w') fp.write(data) fp.close() - os.chmod(outPath, 0755) + os.chmod(outPath, STAT_0o755) @@ -945,7 +969,7 @@ readme = textwrap.dedent(recipe['readme']) isRequired = recipe.get('required', True) - print "- building package %s"%(pkgname,) + print("- building package %s"%(pkgname,)) # Substitute some variables textvars = dict( @@ -990,7 +1014,7 @@ patchScript(postflight, os.path.join(rsrcDir, 'postflight')) vers = getFullVersion() - major, minor = map(int, getVersion().split('.', 2)) + major, minor = getVersionMajorMinor() pl = Plist( CFBundleGetInfoString="Python.%s %s"%(pkgname, vers,), CFBundleIdentifier='org.python.Python.%s'%(pkgname,), @@ -1027,7 +1051,7 @@ def makeMpkgPlist(path): vers = getFullVersion() - major, minor = map(int, getVersion().split('.', 2)) + major, minor = getVersionMajorMinor() pl = Plist( CFBundleGetInfoString="Python %s"%(vers,), @@ -1209,7 +1233,7 @@ folder = os.path.join(WORKDIR, "_root", "Applications", "Python %s"%( getVersion(),)) - os.chmod(folder, 0755) + os.chmod(folder, STAT_0o755) setIcon(folder, "../Icons/Python Folder.icns") # Create the installer @@ -1222,9 +1246,9 @@ shutil.copy('../../LICENSE', os.path.join(WORKDIR, 'installer', 'License.txt')) fp = open(os.path.join(WORKDIR, 'installer', 'Build.txt'), 'w') - print >> fp, "# BUILD INFO" - print >> fp, "# Date:", time.ctime() - print >> fp, "# By:", pwd.getpwuid(os.getuid()).pw_gecos + fp.write("# BUILD INFO\n") + fp.write("# Date: %s\n" % time.ctime()) + fp.write("# By: %s\n" % pwd.getpwuid(os.getuid()).pw_gecos) fp.close() # And copy it to a DMG
--- a/Mac/Makefile.in Sun Jun 24 00:23:47 2012 -0700 +++ b/Mac/Makefile.in Sun Jun 24 00:24:31 2012 -0700 @@ -43,11 +43,10 @@ CPMAC=/Developer/Tools/CpMac APPTEMPLATE=$(srcdir)/Resources/app -APPSUBDIRS=MacOS Resources +APPSUBDIRS=MacOS Resources compileall=$(srcdir)/../Lib/compileall.py -installapps: install_Python install_pythonw install_PythonLauncher install_IDLE \ - checkapplepython +installapps: install_Python install_pythonw install_PythonLauncher install_IDLE install_pythonw: pythonw $(INSTALL_PROGRAM) $(STRIPFLAG) pythonw "$(DESTDIR)$(prefix)/bin/pythonw$(VERSION)" @@ -196,14 +195,6 @@ "$(DESTDIR)$(prefix)/share/doc/python$(VERSION)/examples/Tools" ; \ chmod -R ugo+rX,go-w "$(DESTDIR)$(prefix)/share/doc/python$(VERSION)/examples/Tools" - -checkapplepython: $(srcdir)/Tools/fixapplepython23.py - @if ! $(RUNSHARED) $(BUILDPYTHON) $(srcdir)/Tools/fixapplepython23.py -n; then \ - echo "* WARNING: Apple-installed Python 2.3 will have trouble building extensions from now on."; \ - echo "* WARNING: Run $(srcdir)/Tools/fixapplepython23.py with \"sudo\" to fix this."; \ - fi - - clean: rm pythonw cd PythonLauncher && make clean
--- a/Mac/README Sun Jun 24 00:23:47 2012 -0700 +++ b/Mac/README Sun Jun 24 00:24:31 2012 -0700 @@ -1,6 +1,13 @@ -============ -MacOSX Notes -============ +========================= +Python on Mac OS X README +========================= + +:Authors: + Jack Jansen (2004-07), + Ronald Oussoren (2010-04), + Ned Deily (2012-06) + +:Version: 3.3.0 This document provides a quick overview of some Mac OS X specific features in the Python distribution. @@ -12,11 +19,11 @@ _`Building and using a framework-based Python on Mac OS X` for more information on frameworks. - If the optional directory argument is specified the framework it installed + If the optional directory argument is specified the framework is installed into that directory. This can be used to install a python framework into your home directory:: - $ configure --enable-framework=/Users/ronald/Library/Frameworks + $ ./configure --enable-framework=/Users/ronald/Library/Frameworks $ make && make install This will install the framework itself in ``/Users/ronald/Library/Frameworks``, @@ -33,9 +40,10 @@ Create a universal binary build of of Python. This can be used with both regular and framework builds. - The optional argument specifies which OSX SDK should be used to perform the - build. This defaults to ``/Developer/SDKs/MacOSX.10.4u.sdk``, specify - ``/`` when building on a 10.5 system, especially when building 64-bit code. + The optional argument specifies which OS X SDK should be used to perform the + build. If xcodebuild is available and configured, this defaults to + the Xcode default MacOS X SDK, otherwise ``/Developer/SDKs/MacOSX.10.4u.sdk`` + if available or ``/`` if not. See the section _`Building and using a universal binary of Python on Mac OS X` for more information. @@ -43,7 +51,9 @@ * ``--with-univeral-archs=VALUE`` Specify the kind of universal binary that should be created. This option is - only valid when ``--enable-universalsdk`` is specified. + only valid when ``--enable-universalsdk`` is specified. The default is + ``32-bit`` if a building with a SDK that supports PPC, otherwise defaults + to ``intel``. Building and using a universal binary of Python on Mac OS X @@ -52,9 +62,14 @@ 1. What is a universal binary ----------------------------- -A universal binary build of Python contains object code for both PPC and i386 -and can therefore run at native speed on both classic powerpc based macs and -the newer intel based macs. +A universal binary build of Python contains object code for more than one +CPU architecture. A universal OS X executable file or library combines the +architecture-specific code into one file and can therefore run at native +speed on all supported architectures. Universal files were introduced in +OS X 10.4 to add support for Intel-based Macs to the existing PowerPC (PPC) +machines. In OS X 10.5 support was extended to 64-bit Intel and 64-bit PPC +architectures. It is possible to build Python with various combinations +of architectures depending on the build tools and OS X version in use. 2. How do I build a universal binary ------------------------------------ @@ -67,35 +82,52 @@ $ make install This flag can be used with a framework build of python, but also with a classic -unix build. Either way you will have to build python on Mac OS X 10.4 (or later) -with Xcode 2.1 (or later). You also have to install the 10.4u SDK when -installing Xcode. +unix build. Universal builds were first supported with OS X 10.4 with Xcode 2.1 +and the 10.4u SDK. Starting with Xcode 3 and OS X 10.5, more configurations are +available. + +2.1 Flavors of universal binaries +................................. -2.1 Flavours of universal binaries -.................................. - -It is possible to build a number of flavours of the universal binary build, -the default is a 32-bit only binary (i386 and ppc). The flavour can be -specified using the option ``--with-universal-archs=VALUE``. The following +It is possible to build a number of flavors of the universal binary build, +the default is a 32-bit only binary (i386 and ppc) in build environments that +support ppc (10.4 with Xcode 2, 10.5 and 10.6 with Xcode 3) or an +Intel-32/-64-bit binary (i386 and X86_64) in build environments that do not +support ppc (Xcode 4 on 10.6 and later systems). The flavor can be specified +using the configure option ``--with-universal-archs=VALUE``. The following values are available: + * ``intel``: ``i386``, ``x86_64`` + * ``32-bit``: ``ppc``, ``i386`` + * ``3-way``: ``i386``, ``x86_64``, ``ppc`` + * ``64-bit``: ``ppc64``, ``x86_64`` * ``all``: ``ppc``, ``ppc64``, ``i386``, ``x86_64`` - * ``3-way``: ``ppc``, ``i386`` and ``x86_64`` +To build a universal binary that includes a 64-bit architecture, you must build +on a system running OS X 10.5 or later. The ``all`` and ``64-bit`` flavors can +only be built with an 10.5 SDK because ``ppc64`` support was only included with +OS X 10.5. Although legacy ``ppc`` support was included with Xcode 3 on OS X +10.6, it was removed in Xcode 4, versions of which were released on OS X 10.6 +and which is the current standard for OS X 10.7 and 10.8. To summarize, the +following combinations of SDKs and universal-archs flavors are available: - * ``intel``: ``i386``, ``x86_64`` + * 10.4u SDK with Xcode 2 supports ``32-bit`` only -To build a universal binary that includes a 64-bit architecture, you must build -on a system running OSX 10.5 or later. The ``all`` flavour can only be built on -OSX 10.5. + * 10.5 SDK with Xcode 3.1.x supports all flavors + + * 10.6 SDK with Xcode 3.2.x supports ``intel``, ``3-way``, and ``32-bit`` + + * 10.6 SDK with Xcode 4 supports ``intel`` only -The makefile for a framework build will install ``python32`` and ``pythonw32`` -binaries when the universal architecures includes at least one 32-bit architecture -(that is, for all flavours but ``64-bit``). + * 10.7 and 10.8 SDKs with Xcode 4 support ``intel`` only + +The makefile for a framework build will also install ``python3.3-32`` +binaries when the universal architecture includes at least one 32-bit +architecture (that is, for all flavors but ``64-bit``). Running a specific archicture ............................. @@ -122,17 +154,17 @@ The main reason is because you want to create GUI programs in Python. With the exception of X11/XDarwin-based GUI toolkits all GUI programs need to be run -from a fullblown MacOSX application (a ".app" bundle). +from a Mac OSX application bundle (".app"). While it is technically possible to create a .app without using frameworks you will have to do the work yourself if you really want this. A second reason for using frameworks is that they put Python-related items in only two places: "/Library/Framework/Python.framework" and -"/Applications/MacPython <VERSION>" where ``<VERSION>`` can be e.g. "2.6", -"3.1", etc.. This simplifies matters for users installing +"/Applications/Python <VERSION>" where ``<VERSION>`` can be e.g. "3.3", +"2.7", etc. This simplifies matters for users installing Python from a binary distribution if they want to get rid of it again. Moreover, -due to the way frameworks work a user without admin privileges can install a +due to the way frameworks work, a user without admin privileges can install a binary distribution in his or her home directory without recompilation. 2. How does a framework Python differ from a normal static Python? @@ -156,10 +188,10 @@ ------------------------------------- This directory contains a Makefile that will create a couple of python-related -applications (fullblown OSX .app applications, that is) in -"/Applications/MacPython <VERSION>", and a hidden helper application Python.app -inside the Python.framework, and unix tools "python" and "pythonw" into -/usr/local/bin. In addition it has a target "installmacsubtree" that installs +applications (full-blown OSX .app applications, that is) in +"/Applications/Python <VERSION>", and a hidden helper application Python.app +inside the Python.framework, and unix tools "python" and "pythonw" into +/usr/local/bin. In addition it has a target "installmacsubtree" that installs the relevant portions of the Mac subtree into the Python.framework. It is normally invoked indirectly through the main Makefile, as the last step @@ -171,17 +203,15 @@ 3. make install -This sequence will put the framework in /Library/Framework/Python.framework, -the applications in "/Applications/MacPython <VERSION>" and the unix tools in -/usr/local/bin. +This sequence will put the framework in ``/Library/Framework/Python.framework``, +the applications in ``/Applications/Python <VERSION>`` and the unix tools in +``/usr/local/bin``. -Installing in another place, for instance $HOME/Library/Frameworks if you have -no admin privileges on your machine, has only been tested very lightly. This -can be done by configuring with --enable-framework=$HOME/Library/Frameworks. -The other two directories, "/Applications/MacPython-<VERSION>" and -/usr/local/bin, will then also be deposited in $HOME. This is sub-optimal for -the unix tools, which you would want in $HOME/bin, but there is no easy way to -fix this right now. +Installing in another place, for instance ``$HOME/Library/Frameworks`` if you +have no admin privileges on your machine, is possible. This can be accomplished +by configuring with ``--enable-framework=$HOME/Library/Frameworks``. +The other two directories will then also be installed in your home directory, +at ``$HOME/Applications/Python-<VERSION>`` and ``$HOME/bin``. If you want to install some part, but not all, read the main Makefile. The frameworkinstall is composed of a couple of sub-targets that install the @@ -189,7 +219,7 @@ There is an extra target frameworkinstallextras that is not part of the normal frameworkinstall which installs the Tools directory into -"/Applications/MacPython <VERSION>", this is useful for binary +"/Applications/Python <VERSION>", this is useful for binary distributions. What do all these programs do? @@ -202,24 +232,35 @@ double-click a .py, .pyc or .pyw file. For the first two it creates a Terminal window and runs the scripts with the normal command-line Python. For the latter it runs the script in the Python.app interpreter so the script can do -GUI-things. Keep the "alt" key depressed while dragging or double-clicking a -script to set runtime options. These options can be set once and for all +GUI-things. Keep the ``Option`` key depressed while dragging or double-clicking +a script to set runtime options. These options can be set persistently through PythonLauncher's preferences dialog. -The commandline scripts /usr/local/bin/python and pythonw can be used to run -non-GUI and GUI python scripts from the command line, respectively. +The program ``pythonx.x`` runs python scripts from the command line. Various +compatibility aliases are also installed, including ``pythonwx.x`` which +in early releases of Python on OS X was required to run GUI programs. In +current releases, the ``pythonx.x`` and ``pythonwx.x`` commands are identical. How do I create a binary distribution? ====================================== -Go to the directory "Mac/OSX/BuildScript". There you'll find a script -"build-installer.py" that does all the work. This will download and build +Download and unpack the source release from http://www.python.org/download/. +Go to the directory ``Mac/BuildScript``. There you will find a script +``build-installer.py`` that does all the work. This will download and build a number of 3rd-party libaries, configures and builds a framework Python, installs it, creates the installer package files and then packs this in a -DMG image. +DMG image. The script also builds an HTML copy of the current Python +documentation set for this release for inclusion in the framework. The +installer package will create links to the documentation for use by IDLE, +pydoc, shell users, and Finder user. -The script will build a universal binary, you'll therefore have to run this +The script will build a universal binary so you'll therefore have to run this script on Mac OS X 10.4 or later and with Xcode 2.1 or later installed. +However, the Python build process itself has several build dependencies not +available out of the box with OS X 10.4 so you may have to install +additional software beyond what is provided with Xcode 2. OS X 10.5 +provides a recent enough system Python (in ``/usr/bin``) to build +the Python documentation set. All of this is normally done completely isolated in /tmp/_py, so it does not use your normal build directory nor does it install into /. @@ -253,7 +294,7 @@ Uninstalling a framework can be done by manually removing all bits that got installed. That's true for both installations from source and installations using the binary installer. -Sadly enough OSX does not have a central uninstaller. +OS X does not provide a central uninstaller. The main bit of a framework install is the framework itself, installed in ``/Library/Frameworks/Python.framework``. This can contain multiple versions @@ -267,14 +308,12 @@ And lastly a framework installation installs files in ``/usr/local/bin``, all of them symbolic links to files in ``/Library/Frameworks/Python.framework/Versions/X.Y/bin``. -Odds and ends -============= + +Resources +========= -Something to take note of is that the ".rsrc" files in the distribution are -not actually resource files, they're AppleSingle encoded resource files. The -macresource module and the Mac/OSX/Makefile cater for this, and create -".rsrc.df.rsrc" files on the fly that are normal datafork-based resource -files. + * http://www.python.org/download/mac/ - Jack Jansen, Jack.Jansen@cwi.nl, 15-Jul-2004. - Ronald Oussoren, RonaldOussoren@mac.com, 30-April-2010 + * http://www.python.org/community/sigs/current/pythonmac-sig/ + + * http://docs.python.org/devguide/ \ No newline at end of file
--- a/Mac/Tools/fixapplepython23.py Sun Jun 24 00:23:47 2012 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -#!/usr/bin/python -"""fixapplepython23 - Fix Apple-installed Python 2.3 (on Mac OS X 10.3) - -Python 2.3 (and 2.3.X for X<5) have the problem that building an extension -for a framework installation may accidentally pick up the framework -of a newer Python, in stead of the one that was used to build the extension. - -This script modifies the Makefile (in .../lib/python2.3/config) to use -the newer method of linking extensions with "-undefined dynamic_lookup" -which fixes this problem. - -The script will first check all prerequisites, and return a zero exit -status also when nothing needs to be fixed. -""" -import sys -import os -import platform - -MAKEFILE='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/Makefile' -CHANGES=(( - 'LDSHARED=\t$(CC) $(LDFLAGS) -bundle -framework $(PYTHONFRAMEWORK)\n', - 'LDSHARED=\t$(CC) $(LDFLAGS) -bundle -undefined dynamic_lookup\n' - ),( - 'BLDSHARED=\t$(CC) $(LDFLAGS) -bundle -framework $(PYTHONFRAMEWORK)\n', - 'BLDSHARED=\t$(CC) $(LDFLAGS) -bundle -undefined dynamic_lookup\n' - ),( - 'CC=\t\tgcc\n', - 'CC=\t\t/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-gcc\n' - ),( - 'CXX=\t\tc++\n', - 'CXX=\t\t/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-g++\n' -)) - -GCC_SCRIPT='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-gcc' -GXX_SCRIPT='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-g++' -SCRIPT="""#!/bin/sh -export MACOSX_DEPLOYMENT_TARGET=10.3 -exec %s "${@}" -""" - -def findline(lines, start): - """return line starting with given string or -1""" - for i in range(len(lines)): - if lines[i][:len(start)] == start: - return i - return -1 - -def fix(makefile, do_apply): - """Fix the Makefile, if required.""" - fixed = False - lines = open(makefile).readlines() - - for old, new in CHANGES: - i = findline(lines, new) - if i >= 0: - # Already fixed - continue - i = findline(lines, old) - if i < 0: - print('fixapplepython23: Python installation not fixed (appears broken)') - print('fixapplepython23: missing line:', old) - return 2 - lines[i] = new - fixed = True - - if fixed: - if do_apply: - print('fixapplepython23: Fix to Apple-installed Python 2.3 applied') - os.rename(makefile, makefile + '~') - open(makefile, 'w').writelines(lines) - return 0 - else: - print('fixapplepython23: Fix to Apple-installed Python 2.3 should be applied') - return 1 - else: - print('fixapplepython23: No fix needed, appears to have been applied before') - return 0 - -def makescript(filename, compiler): - """Create a wrapper script for a compiler""" - dirname = os.path.split(filename)[0] - if not os.access(dirname, os.X_OK): - os.mkdir(dirname, 0o755) - fp = open(filename, 'w') - fp.write(SCRIPT % compiler) - fp.close() - os.chmod(filename, 0o755) - print('fixapplepython23: Created', filename) - -def main(): - # Check for -n option - if len(sys.argv) > 1 and sys.argv[1] == '-n': - do_apply = False - else: - do_apply = True - # First check OS version - if sys.byteorder == 'little': - # All intel macs are fine - print("fixapplypython23: no fix is needed on MacOSX on Intel") - sys.exit(0) - - osver = platform.mac_ver() - if osver != '10.3' and os.ver < '10.3.': - print('fixapplepython23: no fix needed on MacOSX < 10.3') - sys.exit(0) - - if osver >= '10.4': - print('fixapplepython23: no fix needed on MacOSX >= 10.4') - sys.exit(0) - - # Test that a framework Python is indeed installed - if not os.path.exists(MAKEFILE): - print('fixapplepython23: Python framework does not appear to be installed (?), nothing fixed') - sys.exit(0) - # Check that we can actually write the file - if do_apply and not os.access(MAKEFILE, os.W_OK): - print('fixapplepython23: No write permission, please run with "sudo"') - sys.exit(2) - # Create the shell scripts - if do_apply: - if not os.access(GCC_SCRIPT, os.X_OK): - makescript(GCC_SCRIPT, "gcc") - if not os.access(GXX_SCRIPT, os.X_OK): - makescript(GXX_SCRIPT, "g++") - # Finally fix the makefile - rv = fix(MAKEFILE, do_apply) - #sys.exit(rv) - sys.exit(0) - -if __name__ == '__main__': - main()
