summaryrefslogtreecommitdiffstats
path: root/Mac
diff options
context:
space:
mode:
Diffstat (limited to 'Mac')
-rw-r--r--Mac/BuildScript/README.txt151
-rwxr-xr-xMac/BuildScript/build-installer.py500
-rw-r--r--Mac/BuildScript/ncurses-5.5.patch36
-rw-r--r--Mac/BuildScript/resources/ReadMe.txt28
-rw-r--r--Mac/BuildScript/resources/Welcome.rtf8
-rwxr-xr-xMac/BuildScript/scripts/postflight.documentation9
-rwxr-xr-xMac/BuildScript/scripts/postflight.framework14
-rw-r--r--Mac/Makefile.in19
-rw-r--r--Mac/README206
-rw-r--r--Mac/Tools/fixapplepython23.py131
-rw-r--r--Mac/Tools/pythonw.c48
11 files changed, 643 insertions, 507 deletions
diff --git a/Mac/BuildScript/README.txt b/Mac/BuildScript/README.txt
index de2f5cb..fa04b97 100644
--- a/Mac/BuildScript/README.txt
+++ b/Mac/BuildScript/README.txt
@@ -8,70 +8,125 @@ $DESTROOT, massages that installation to remove .pyc files and such, creates
an Installer package from the installation plus other files in ``resources``
and ``scripts`` and placed that on a ``.dmg`` disk image.
-As of Python 2.7.x and 3.2, PSF practice is to build two installer variants
-for each release:
+As of Python 3.3.0, PSF practice is to build two installer variants
+for each release.
1. 32-bit-only, i386 and PPC universal, capable on running on all machines
- supported by Mac OS X 10.3.9 through (at least) 10.6::
+ supported by Mac OS X 10.5 through (at least) 10.8::
- python build-installer.py \
- --sdk-path=/Developer/SDKs/MacOSX10.4u.sdk \
+ /usr/bin/python build-installer.py \
+ --sdk-path=/Developer/SDKs/MacOSX10.5.sdk \
--universal-archs=32-bit \
- --dep-target=10.3
- # These are the current default options
+ --dep-target=10.5
- builds the following third-party libraries
- * Bzip2
- * Zlib 1.2.3
- * GNU Readline (GPL)
- * SQLite 3
- * NCurses
- * Oracle Sleepycat DB 4.8 (Python 2.x only)
+ * NCurses 5.9 (http://bugs.python.org/issue15037)
+ * SQLite 3.7.13
+ * XZ 5.0.3
+
+ - uses system-supplied versions of third-party libraries
+
+ * readline module links with Apple BSD editline (libedit)
- requires ActiveState ``Tcl/Tk 8.4`` (currently 8.4.19) to be installed for building
- - current target build environment:
-
- * Mac OS X 10.5.8 PPC or Intel
- * Xcode 3.1.4 (or later)
- * ``MacOSX10.4u`` SDK (later SDKs do not support PPC G3 processors)
- * ``MACOSX_DEPLOYMENT_TARGET=10.3``
- * Apple ``gcc-4.0``
- * Python 2.n (n >= 4) for documentation build with Sphinx
+ - recommended build environment:
+
+ * Mac OS X 10.5.8 Intel or PPC
+ * Xcode 3.1.4
+ * ``MacOSX10.5`` SDK
+ * ``MACOSX_DEPLOYMENT_TARGET=10.5``
+ * Apple ``gcc-4.2``
+ * system Python 2.5 for documentation build with Sphinx
- alternate build environments:
- * Mac OS X 10.4.11 with Xcode 2.5
- * Mac OS X 10.6.6 with Xcode 3.2.5
+ * Mac OS X 10.6.8 with Xcode 3.2.6
- need to change ``/System/Library/Frameworks/{Tcl,Tk}.framework/Version/Current`` to ``8.4``
+ * Note Xcode 4.* does not support building for PPC so cannot be used for this build
2. 64-bit / 32-bit, x86_64 and i386 universal, for OS X 10.6 (and later)::
- python build-installer.py \
+ /usr/bin/python build-installer.py \
--sdk-path=/Developer/SDKs/MacOSX10.6.sdk \
--universal-archs=intel \
--dep-target=10.6
+ - builds the following third-party libraries
+
+ * NCurses 5.9 (http://bugs.python.org/issue15037)
+ * SQLite 3.7.13
+ * XZ 5.0.3
+
- uses system-supplied versions of third-party libraries
-
+
* readline module links with Apple BSD editline (libedit)
- * builds Oracle Sleepycat DB 4.8 (Python 2.x only)
- requires ActiveState Tcl/Tk 8.5.9 (or later) to be installed for building
- - current target build environment:
-
- * Mac OS X 10.6.6 (or later)
- * Xcode 3.2.5 (or later)
+ - recommended build environment:
+
+ * Mac OS X 10.6.8 (or later)
+ * Xcode 3.2.6
* ``MacOSX10.6`` SDK
* ``MACOSX_DEPLOYMENT_TARGET=10.6``
* Apple ``gcc-4.2``
- * Python 2.n (n >= 4) for documentation build with Sphinx
+ * system Python 2.6 for documentation build with Sphinx
- alternate build environments:
- * none
+ * none. Xcode 4.x currently supplies two C compilers.
+ ``llvm-gcc-4.2.1`` has been found to miscompile Python 3.3.x and
+ produce a non-functional Python executable. As it appears to be
+ considered a migration aid by Apple and is not likely to be fixed,
+ its use should be avoided. The other compiler, ``clang``, has been
+ undergoing rapid development. While it appears to have become
+ production-ready in the most recent Xcode 4 releases (Xcode 4.4.1
+ as of this writing), there are still some open issues when
+ building Python and there has not yet been the level of exposure in
+ production environments that the Xcode 3 gcc-4.2 compiler has had.
+
+
+* For Python 2.7.x and 3.2.x, the 32-bit-only installer was configured to
+ support Mac OS X 10.3.9 through (at least) 10.6. Because it is
+ believed that there are few systems still running OS X 10.3 or 10.4
+ and because it has become increasingly difficult to test and
+ support the differences in these earlier systems, as of Python 3.3.0 the PSF
+ 32-bit installer no longer supports them. For reference in building such
+ an installer yourself, the details are::
+
+ /usr/bin/python build-installer.py \
+ --sdk-path=/Developer/SDKs/MacOSX10.4u.sdk \
+ --universal-archs=32-bit \
+ --dep-target=10.3
+
+ - builds the following third-party libraries
+
+ * Bzip2
+ * NCurses
+ * GNU Readline (GPL)
+ * SQLite 3
+ * XZ
+ * Zlib 1.2.3
+ * Oracle Sleepycat DB 4.8 (Python 2.x only)
+
+ - requires ActiveState ``Tcl/Tk 8.4`` (currently 8.4.19) to be installed for building
+
+ - recommended build environment:
+
+ * Mac OS X 10.5.8 PPC or Intel
+ * Xcode 3.1.4 (or later)
+ * ``MacOSX10.4u`` SDK (later SDKs do not support PPC G3 processors)
+ * ``MACOSX_DEPLOYMENT_TARGET=10.3``
+ * Apple ``gcc-4.0``
+ * system Python 2.5 for documentation build with Sphinx
+
+ - alternate build environments:
+
+ * Mac OS X 10.6.8 with Xcode 3.2.6
+ - need to change ``/System/Library/Frameworks/{Tcl,Tk}.framework/Version/Current`` to ``8.4``
+
General Prerequisites
@@ -87,6 +142,11 @@ General Prerequisites
* It is safest to start each variant build with an empty source directory
populated with a fresh copy of the untarred source.
+* It is recommended that you remove any existing installed version of the
+ Python being built::
+
+ sudo rm -rf /Library/Frameworks/Python.framework/Versions/n.n
+
The Recipe
----------
@@ -107,9 +167,9 @@ Building other universal installers
...................................
It is also possible to build a 4-way universal installer that runs on
-OS X Leopard or later::
+OS X 10.5 Leopard or later::
- python 2.6 /build-installer.py \
+ /usr/bin/python /build-installer.py \
--dep-target=10.5
--universal-archs=all
--sdk-path=/Developer/SDKs/MacOSX10.5.sdk
@@ -120,7 +180,8 @@ also that you are building on at least OS X 10.5. 4-way includes
variants can only be run on G5 machines running 10.5. Note that,
while OS X 10.6 is only supported on Intel-based machines, it is possible
to run ``ppc`` (32-bit) executables unmodified thanks to the Rosetta ppc
-emulation in OS X 10.5 and 10.6.
+emulation in OS X 10.5 and 10.6. The 4-way installer variant must be
+built with Xcode 3. It is not regularly built or tested.
Other ``--universal-archs`` options are ``64-bit`` (``x86_64``, ``ppc64``),
and ``3-way`` (``ppc``, ``i386``, ``x86_64``). None of these options
@@ -133,15 +194,21 @@ Testing
Ideally, the resulting binaries should be installed and the test suite run
on all supported OS X releases and architectures. As a practical matter,
that is generally not possible. At a minimum, variant 1 should be run on
-at least one Intel, one PPC G4, and one PPC G3 system and one each of
-OS X 10.6, 10.5, 10.4, and 10.3.9. Not all tests run on 10.3.9.
-Variant 2 should be run on 10.6 in both 32-bit and 64-bit modes.::
+a PPC G4 system with OS X 10.5 and at least one Intel system running OS X
+10.8, 10.7, 10.6, or 10.5. Variant 2 should be run on 10.8, 10.7, and 10.6
+systems in both 32-bit and 64-bit modes.::
- arch -i386 /usr/local/bin/pythonn.n -m test.regrtest -w -u all
- arch -X86_64 /usr/local/bin/pythonn.n -m test.regrtest -w -u all
+ /usr/local/bin/pythonn.n -m test -w -u all,-largefile
+ /usr/local/bin/pythonn.n-32 -m test -w -u all
Certain tests will be skipped and some cause the interpreter to fail
which will likely generate ``Python quit unexpectedly`` alert messages
-to be generated at several points during a test run. These can
-be ignored.
+to be generated at several points during a test run. These are normal
+during testing and can be ignored.
+
+It is also recommend to launch IDLE and verify that it is at least
+functional. Double-click on the IDLE app icon in ``/Applications/Pythonn.n``.
+It should also be tested from the command line::
+
+ /usr/local/bin/idlen.n
diff --git a/Mac/BuildScript/build-installer.py b/Mac/BuildScript/build-installer.py
index ba92012..bd0c476 100755
--- a/Mac/BuildScript/build-installer.py
+++ b/Mac/BuildScript/build-installer.py
@@ -1,7 +1,7 @@
-#!/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
+It requires at least Mac OS X 10.5, Xcode 3, and the 10.4u SDK for
32-bit builds. 64-bit or four-way universal builds require at least
OS X 10.5 and the 10.5 SDK.
@@ -10,18 +10,41 @@ bootstrap issues (/usr/bin/python is Python 2.5 on OSX 10.5). Sphinx,
which is used to build the documentation, currently requires at least
Python 2.4.
+In addition to what is supplied with OS X 10.5+ and Xcode 3+, the script
+requires an installed version of hg and a third-party version of
+Tcl/Tk 8.4 (for OS X 10.4 and 10.5 deployment targets) or Tcl/TK 8.5
+(for 10.6 or later) installed in /Library/Frameworks. When installed,
+the Python built by this script will attempt to dynamically link first to
+Tcl and Tk frameworks in /Library/Frameworks if available otherwise fall
+back to the ones in /System/Library/Framework. For the build, we recommend
+installing the most recent ActiveTcl 8.4 or 8.5 version.
+
+32-bit-only installer builds are still possible on OS X 10.4 with Xcode 2.5
+and the installation of additional components, such as a newer Python
+(2.5 is needed for Python parser updates), hg, and svn (for the documentation
+build).
+
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 +65,35 @@ def grepValue(fn, variable):
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"
@@ -111,13 +149,15 @@ SRCDIR = os.path.dirname(
DEPTARGET = '10.3'
target_cc_map = {
- '10.3': 'gcc-4.0',
- '10.4': 'gcc-4.0',
- '10.5': 'gcc-4.0',
- '10.6': 'gcc-4.2',
+ '10.3': ('gcc-4.0', 'g++-4.0'),
+ '10.4': ('gcc-4.0', 'g++-4.0'),
+ '10.5': ('gcc-4.2', 'g++-4.2'),
+ '10.6': ('gcc-4.2', 'g++-4.2'),
+ '10.7': ('clang', 'clang++'),
+ '10.8': ('clang', 'clang++'),
}
-CC = target_cc_map[DEPTARGET]
+CC, CXX = target_cc_map[DEPTARGET]
PYTHON_3 = getVersionTuple() >= (3, 0)
@@ -135,6 +175,13 @@ USAGE = textwrap.dedent("""\
--universal-archs=x universal architectures (options: %(UNIVERSALOPTS)r, default: %(UNIVERSALARCHS)r)
""")% globals()
+# Dict of object file names with shared library names to check after building.
+# This is to ensure that we ended up dynamically linking with the shared
+# library paths and versions we expected. For example:
+# EXPECTED_SHARED_LIBS['_tkinter.so'] = [
+# '/Library/Frameworks/Tcl.framework/Versions/8.5/Tcl',
+# '/Library/Frameworks/Tk.framework/Versions/8.5/Tk']
+EXPECTED_SHARED_LIBS = {}
# Instructions for building libraries that are necessary for building a
# batteries included python.
@@ -143,6 +190,71 @@ USAGE = textwrap.dedent("""\
def library_recipes():
result = []
+ LT_10_5 = bool(DEPTARGET < '10.5')
+
+ result.extend([
+ dict(
+ name="XZ 5.0.3",
+ url="http://tukaani.org/xz/xz-5.0.3.tar.gz",
+ checksum='fefe52f9ecd521de2a8ce38c21a27574',
+ configure_pre=[
+ '--disable-dependency-tracking',
+ ]
+ ),
+ dict(
+ name="NCurses 5.9",
+ url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.9.tar.gz",
+ checksum='8cb9c412e5f2d96bc6f459aa8c6282a1',
+ configure_pre=[
+ "--enable-widec",
+ "--without-cxx",
+ "--without-cxx-binding",
+ "--without-ada",
+ "--without-curses-h",
+ "--enable-shared",
+ "--with-shared",
+ "--without-debug",
+ "--without-normal",
+ "--without-tests",
+ "--without-manpages",
+ "--datadir=/usr/share",
+ "--sysconfdir=/etc",
+ "--sharedstatedir=/usr/com",
+ "--with-terminfo-dirs=/usr/share/terminfo",
+ "--with-default-terminfo-dir=/usr/share/terminfo",
+ "--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib"%(getVersion(),),
+ ],
+ patchscripts=[
+ ("ftp://invisible-island.net/ncurses//5.9/ncurses-5.9-20120616-patch.sh.bz2",
+ "f54bf02a349f96a7c4f0d00922f3a0d4"),
+ ],
+ useLDFlags=False,
+ install='make && make install DESTDIR=%s && cd %s/usr/local/lib && ln -fs ../../../Library/Frameworks/Python.framework/Versions/%s/lib/lib* .'%(
+ shellQuote(os.path.join(WORKDIR, 'libraries')),
+ shellQuote(os.path.join(WORKDIR, 'libraries')),
+ getVersion(),
+ ),
+ ),
+ dict(
+ name="SQLite 3.7.13",
+ url="http://www.sqlite.org/sqlite-autoconf-3071300.tar.gz",
+ checksum='c97df403e8a3d5b67bb408fcd6aabd8e',
+ extra_cflags=('-Os '
+ '-DSQLITE_ENABLE_FTS4 '
+ '-DSQLITE_ENABLE_FTS3_PARENTHESIS '
+ '-DSQLITE_ENABLE_RTREE '
+ '-DSQLITE_TCL=0 '
+ '%s' % ('','-DSQLITE_WITHOUT_ZONEMALLOC ')[LT_10_5]),
+ configure_pre=[
+ '--enable-threadsafe',
+ '--enable-shared=no',
+ '--enable-static=yes',
+ '--disable-readline',
+ '--disable-dependency-tracking',
+ ]
+ ),
+ ])
+
if DEPTARGET < '10.5':
result.extend([
dict(
@@ -150,8 +262,8 @@ def library_recipes():
url="http://bzip.org/1.0.6/bzip2-1.0.6.tar.gz",
checksum='00b516f4704d4a7cb50a1d97e6e8e15b',
configure=None,
- install='make install CC=%s PREFIX=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%(
- CC,
+ install='make install CC=%s CXX=%s, PREFIX=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%(
+ CC, CXX,
shellQuote(os.path.join(WORKDIR, 'libraries')),
' -arch '.join(ARCHLIST),
SDKPATH,
@@ -162,8 +274,8 @@ def library_recipes():
url="http://www.gzip.org/zlib/zlib-1.2.3.tar.gz",
checksum='debc62758716a169df9f62e6ab2bc634',
configure=None,
- install='make install CC=%s prefix=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%(
- CC,
+ install='make install CC=%s CXX=%s, prefix=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%(
+ CC, CXX,
shellQuote(os.path.join(WORKDIR, 'libraries')),
' -arch '.join(ARCHLIST),
SDKPATH,
@@ -178,58 +290,12 @@ def library_recipes():
patches=[
# The readline maintainers don't do actual micro releases, but
# just ship a set of patches.
- 'http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-001',
- 'http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-002',
- ]
- ),
- dict(
- name="SQLite 3.7.4",
- url="http://www.sqlite.org/sqlite-autoconf-3070400.tar.gz",
- checksum='8f0c690bfb33c3cbbc2471c3d9ba0158',
- configure_env=('CFLAGS="-Os'
- ' -DSQLITE_ENABLE_FTS3'
- ' -DSQLITE_ENABLE_FTS3_PARENTHESIS'
- ' -DSQLITE_ENABLE_RTREE'
- ' -DSQLITE_TCL=0'
- '"'),
- configure_pre=[
- '--enable-threadsafe',
- '--enable-shared=no',
- '--enable-static=yes',
- '--disable-readline',
- '--disable-dependency-tracking',
+ ('http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-001',
+ 'c642f2e84d820884b0bf9fd176bc6c3f'),
+ ('http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-002',
+ '1a76781a1ea734e831588285db7ec9b1'),
]
),
- dict(
- name="NCurses 5.5",
- url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.5.tar.gz",
- checksum='e73c1ac10b4bfc46db43b2ddfd6244ef',
- configure_pre=[
- "--enable-widec",
- "--without-cxx",
- "--without-ada",
- "--without-progs",
- "--without-curses-h",
- "--enable-shared",
- "--with-shared",
- "--datadir=/usr/share",
- "--sysconfdir=/etc",
- "--sharedstatedir=/usr/com",
- "--with-terminfo-dirs=/usr/share/terminfo",
- "--with-default-terminfo-dir=/usr/share/terminfo",
- "--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib"%(getVersion(),),
- "--enable-termcap",
- ],
- patches=[
- "ncurses-5.5.patch",
- ],
- useLDFlags=False,
- install='make && make install DESTDIR=%s && cd %s/usr/local/lib && ln -fs ../../../Library/Frameworks/Python.framework/Versions/%s/lib/lib* .'%(
- shellQuote(os.path.join(WORKDIR, 'libraries')),
- shellQuote(os.path.join(WORKDIR, 'libraries')),
- getVersion(),
- ),
- ),
])
if not PYTHON_3:
@@ -298,9 +364,7 @@ def pkg_recipes():
source="/pydocs",
readme="""\
This package installs the python documentation at a location
- that is useable for pydoc and IDLE. If you have installed Xcode
- it will also install a link to the documentation in
- /Developer/Documentation/Python
+ that is useable for pydoc and IDLE.
""",
postflight="scripts/postflight.documentation",
required=False,
@@ -326,7 +390,7 @@ def pkg_recipes():
),
]
- if DEPTARGET < '10.4':
+ if DEPTARGET < '10.4' and not PYTHON_3:
result.append(
dict(
name="PythonSystemFixes",
@@ -358,7 +422,7 @@ def fileContents(fn):
"""
Return the contents of the named file
"""
- return open(fn, 'rb').read()
+ return open(fn, 'r').read()
def runCommand(commandline):
"""
@@ -370,7 +434,7 @@ def runCommand(commandline):
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()
@@ -381,7 +445,7 @@ def captureCommand(commandline):
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
@@ -423,39 +487,60 @@ def checkEnvironment():
# Because we only support dynamic load of only one major/minor version of
# Tcl/Tk, ensure:
# 1. there are no user-installed frameworks of Tcl/Tk with version
- # higher than the Apple-supplied system version
- # 2. there is a user-installed framework in /Library/Frameworks with the
- # same version as the system version. This allows users to choose
- # to install a newer patch level.
+ # higher than the Apple-supplied system version in
+ # SDKROOT/System/Library/Frameworks
+ # 2. there is a user-installed framework (usually ActiveTcl) in (or linked
+ # in) SDKROOT/Library/Frameworks with the same version as the system
+ # version. This allows users to choose to install a newer patch level.
+ frameworks = {}
for framework in ['Tcl', 'Tk']:
- #fw = dict(lower=framework.lower(),
- # upper=framework.upper(),
- # cap=framework.capitalize())
- #fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw
- fwpth = 'Library/Frameworks/Tcl.framework/Versions/Current'
+ fwpth = 'Library/Frameworks/%s.framework/Versions/Current' % framework
sysfw = os.path.join(SDKPATH, 'System', fwpth)
- libfw = os.path.join('/', fwpth)
+ libfw = os.path.join(SDKPATH, fwpth)
usrfw = os.path.join(os.getenv('HOME'), fwpth)
- #version = "%(upper)s_VERSION" % fw
+ frameworks[framework] = os.readlink(sysfw)
+ if not os.path.exists(libfw):
+ fatal("Please install a link to a current %s %s as %s so "
+ "the user can override the system framework."
+ % (framework, frameworks[framework], libfw))
if os.readlink(libfw) != os.readlink(sysfw):
fatal("Version of %s must match %s" % (libfw, sysfw) )
if os.path.exists(usrfw):
fatal("Please rename %s to avoid possible dynamic load issues."
% usrfw)
+ if frameworks['Tcl'] != frameworks['Tk']:
+ fatal("The Tcl and Tk frameworks are not the same version.")
+
+ # add files to check after build
+ EXPECTED_SHARED_LIBS['_tkinter.so'] = [
+ "/Library/Frameworks/Tcl.framework/Versions/%s/Tcl"
+ % frameworks['Tcl'],
+ "/Library/Frameworks/Tk.framework/Versions/%s/Tk"
+ % frameworks['Tk'],
+ ]
+
# Remove inherited environment variables which might influence build
environ_var_prefixes = ['CPATH', 'C_INCLUDE_', 'DYLD_', 'LANG', 'LC_',
'LD_', 'LIBRARY_', 'PATH', 'PYTHON']
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'])
+ base_path = '/bin:/sbin:/usr/bin:/usr/sbin'
+ if 'SDK_TOOLS_BIN' in os.environ:
+ base_path = os.environ['SDK_TOOLS_BIN'] + ':' + base_path
+ # Xcode 2.5 on OS X 10.4 does not include SetFile in its usr/bin;
+ # add its fixed location here if it exists
+ OLD_DEVELOPER_TOOLS = '/Developer/Tools'
+ if os.path.isdir(OLD_DEVELOPER_TOOLS):
+ base_path = base_path + ':' + OLD_DEVELOPER_TOOLS
+ os.environ['PATH'] = base_path
+ print("Setting default PATH: %s"%(os.environ['PATH']))
def parseOptions(args=None):
@@ -463,7 +548,7 @@ def parseOptions(args=None):
Parse arguments and update global settings.
"""
global WORKDIR, DEPSRC, SDKPATH, SRCDIR, DEPTARGET
- global UNIVERSALOPTS, UNIVERSALARCHS, ARCHLIST, CC
+ global UNIVERSALOPTS, UNIVERSALARCHS, ARCHLIST, CC, CXX
if args is None:
args = sys.argv[1:]
@@ -472,18 +557,18 @@ def parseOptions(args=None):
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'):
@@ -511,27 +596,28 @@ def parseOptions(args=None):
# 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)
SDKPATH=os.path.abspath(SDKPATH)
DEPSRC=os.path.abspath(DEPSRC)
- CC=target_cc_map[DEPTARGET]
+ CC, CXX=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(" * C++ compiler:", CXX)
+ print("")
@@ -576,31 +662,18 @@ def extractArchive(builddir, archiveName):
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)
finally:
os.chdir(curdir)
-KNOWNSIZES = {
- "http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz": 7952742,
- "http://downloads.sleepycat.com/db-4.4.20.tar.gz": 2030276,
-}
-
def downloadURL(url, fname):
"""
Download the contents of the url into the file.
"""
- try:
- size = os.path.getsize(fname)
- except OSError:
- pass
- else:
- if KNOWNSIZES.get(url) == size:
- 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:
@@ -615,6 +688,24 @@ def downloadURL(url, fname):
except:
pass
+def verifyThirdPartyFile(url, checksum, fname):
+ """
+ Download file from url to filename fname if it does not already exist.
+ Abort if file contents does not match supplied md5 checksum.
+ """
+ name = os.path.basename(fname)
+ if os.path.exists(fname):
+ print("Using local copy of %s"%(name,))
+ else:
+ print("Did not find local copy of %s"%(name,))
+ print("Downloading %s"%(name,))
+ downloadURL(url, fname)
+ print("Archive for %s stored as %s"%(name, fname))
+ if os.system(
+ 'MD5=$(openssl md5 %s) ; test "${MD5##*= }" = "%s"'
+ % (shellQuote(fname), checksum) ):
+ fatal('MD5 checksum mismatch for file %s' % fname)
+
def buildRecipe(recipe, basedir, archList):
"""
Build software using a recipe. This function does the
@@ -635,17 +726,8 @@ def buildRecipe(recipe, basedir, archList):
if not os.path.exists(DEPSRC):
os.mkdir(DEPSRC)
-
- if os.path.exists(sourceArchive):
- print "Using local copy of %s"%(name,)
-
- else:
- 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 "Extracting archive for %s"%(name,)
+ verifyThirdPartyFile(url, recipe['checksum'], sourceArchive)
+ print("Extracting archive for %s"%(name,))
buildDir=os.path.join(WORKDIR, '_bld')
if not os.path.exists(buildDir):
os.mkdir(buildDir)
@@ -655,18 +737,31 @@ def buildRecipe(recipe, basedir, archList):
if 'buildDir' in recipe:
os.chdir(recipe['buildDir'])
-
- for fn in recipe.get('patches', ()):
- if fn.startswith('http://'):
- # Download the patch before applying it.
- path = os.path.join(DEPSRC, os.path.basename(fn))
- downloadURL(fn, path)
- fn = path
-
- fn = os.path.join(curdir, fn)
+ for patch in recipe.get('patches', ()):
+ if isinstance(patch, tuple):
+ url, checksum = patch
+ fn = os.path.join(DEPSRC, os.path.basename(url))
+ verifyThirdPartyFile(url, checksum, fn)
+ else:
+ # patch is a file in the source directory
+ fn = os.path.join(curdir, patch)
runCommand('patch -p%s < %s'%(recipe.get('patchlevel', 1),
shellQuote(fn),))
+ for patchscript in recipe.get('patchscripts', ()):
+ if isinstance(patchscript, tuple):
+ url, checksum = patchscript
+ fn = os.path.join(DEPSRC, os.path.basename(url))
+ verifyThirdPartyFile(url, checksum, fn)
+ else:
+ # patch is a file in the source directory
+ fn = os.path.join(curdir, patchscript)
+ if fn.endswith('.bz2'):
+ runCommand('bunzip2 -fk %s' % shellQuote(fn))
+ fn = fn[:-4]
+ runCommand('sh %s' % shellQuote(fn))
+ os.unlink(fn)
+
if configure is not None:
configure_args = [
"--prefix=/usr/local",
@@ -685,40 +780,44 @@ def buildRecipe(recipe, basedir, archList):
if recipe.get('useLDFlags', 1):
configure_args.extend([
- "CFLAGS=-arch %s -isysroot %s -I%s/usr/local/include"%(
+ "CFLAGS=%s-mmacosx-version-min=%s -arch %s -isysroot %s "
+ "-I%s/usr/local/include"%(
+ recipe.get('extra_cflags', ''),
+ DEPTARGET,
' -arch '.join(archList),
shellQuote(SDKPATH)[1:-1],
shellQuote(basedir)[1:-1],),
- "LDFLAGS=-syslibroot,%s -L%s/usr/local/lib -arch %s"%(
+ "LDFLAGS=-mmacosx-version-min=%s -syslibroot,%s -L%s/usr/local/lib -arch %s"%(
+ DEPTARGET,
shellQuote(SDKPATH)[1:-1],
shellQuote(basedir)[1:-1],
' -arch '.join(archList)),
])
else:
configure_args.extend([
- "CFLAGS=-arch %s -isysroot %s -I%s/usr/local/include"%(
+ "CFLAGS=%s-mmacosx-version-min=%s -arch %s -isysroot %s "
+ "-I%s/usr/local/include"%(
+ recipe.get('extra_cflags', ''),
+ DEPTARGET,
' -arch '.join(archList),
shellQuote(SDKPATH)[1:-1],
shellQuote(basedir)[1:-1],),
])
if 'configure_post' in recipe:
- configure_args = configure_args = list(recipe['configure_post'])
+ configure_args = configure_args + list(recipe['configure_post'])
configure_args.insert(0, configure)
configure_args = [ shellQuote(a) for a in configure_args ]
- 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)
@@ -726,9 +825,9 @@ def buildLibraries():
"""
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'))
@@ -742,7 +841,7 @@ def buildLibraries():
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')
@@ -757,7 +856,7 @@ def buildPythonDocs():
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')
@@ -785,7 +884,7 @@ def buildPython():
# 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 "
@@ -797,19 +896,19 @@ def buildPython():
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(
@@ -820,16 +919,16 @@ def buildPython():
'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
+ shared_lib_error = False
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)
-
for fn in filenames:
if os.path.islink(fn):
continue
@@ -840,6 +939,19 @@ def buildPython():
os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP)
os.chown(p, -1, gid)
+ if fn in EXPECTED_SHARED_LIBS:
+ # check to see that this file was linked with the
+ # expected library path and version
+ data = captureCommand("otool -L %s" % shellQuote(p))
+ for sl in EXPECTED_SHARED_LIBS[fn]:
+ if ("\t%s " % sl) not in data:
+ print("Expected shared lib %s was not linked with %s"
+ % (sl, p))
+ shared_lib_error = True
+
+ if shared_lib_error:
+ fatal("Unexpected shared library errors.")
+
if PYTHON_3:
LDVERSION=None
VERSION=None
@@ -863,19 +975,26 @@ def buildPython():
# We added some directories to the search path during the configure
# phase. Remove those because those directories won't be there on
- # the end-users system.
- path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework',
- 'Versions', version, 'lib', 'python%s'%(version,),
- 'config' + config_suffix, 'Makefile')
- fp = open(path, 'r')
- data = fp.read()
- fp.close()
+ # the end-users system. Also remove the directories from _sysconfigdata.py
+ # (added in 3.3) if it exists.
+
+ path_to_lib = os.path.join(rootDir, 'Library', 'Frameworks',
+ 'Python.framework', 'Versions',
+ version, 'lib', 'python%s'%(version,))
+ paths = [os.path.join(path_to_lib, 'config' + config_suffix, 'Makefile'),
+ os.path.join(path_to_lib, '_sysconfigdata.py')]
+ for path in paths:
+ if not os.path.exists(path):
+ continue
+ fp = open(path, 'r')
+ data = fp.read()
+ fp.close()
- data = data.replace('-L%s/libraries/usr/local/lib'%(WORKDIR,), '')
- data = data.replace('-I%s/libraries/usr/local/include'%(WORKDIR,), '')
- fp = open(path, 'w')
- fp.write(data)
- fp.close()
+ data = data.replace(' -L%s/libraries/usr/local/lib'%(WORKDIR,), '')
+ data = data.replace(' -I%s/libraries/usr/local/include'%(WORKDIR,), '')
+ fp = open(path, 'w')
+ fp.write(data)
+ fp.close()
# Add symlinks in /usr/local/bin, using relative links
usr_local_bin = os.path.join(rootDir, 'usr', 'local', 'bin')
@@ -907,17 +1026,17 @@ def patchFile(inPath, outPath):
# 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)
@@ -934,7 +1053,7 @@ def packageFromRecipe(targetDir, recipe):
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(
@@ -979,7 +1098,7 @@ def packageFromRecipe(targetDir, recipe):
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,),
@@ -1016,7 +1135,7 @@ def packageFromRecipe(targetDir, recipe):
def makeMpkgPlist(path):
vers = getFullVersion()
- major, minor = map(int, getVersion().split('.', 2))
+ major, minor = getVersionMajorMinor()
pl = Plist(
CFBundleGetInfoString="Python %s"%(vers,),
@@ -1127,7 +1246,7 @@ def buildDMG():
# Custom icon for the DMG, shown when the DMG is mounted.
shutil.copy("../Icons/Disk Image.icns",
os.path.join(WORKDIR, "mnt", volname, ".VolumeIcon.icns"))
- runCommand("/Developer/Tools/SetFile -a C %s/"%(
+ runCommand("SetFile -a C %s/"%(
shellQuote(os.path.join(WORKDIR, "mnt", volname)),))
runCommand("hdiutil detach %s"%(shellQuote(os.path.join(WORKDIR, "mnt", volname))))
@@ -1168,6 +1287,7 @@ def main():
os.environ['MACOSX_DEPLOYMENT_TARGET'] = DEPTARGET
os.environ['CC'] = CC
+ os.environ['CXX'] = CXX
if os.path.exists(WORKDIR):
shutil.rmtree(WORKDIR)
@@ -1198,7 +1318,7 @@ def main():
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
@@ -1211,9 +1331,9 @@ def main():
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
diff --git a/Mac/BuildScript/ncurses-5.5.patch b/Mac/BuildScript/ncurses-5.5.patch
deleted file mode 100644
index 0eab3d3..0000000
--- a/Mac/BuildScript/ncurses-5.5.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-diff -r -u ncurses-5.5-orig/test/Makefile.in ncurses-5.5/test/Makefile.in
---- ncurses-5.5-orig/test/Makefile.in 2006-03-24 12:47:40.000000000 +0100
-+++ ncurses-5.5/test/Makefile.in 2006-03-24 12:47:50.000000000 +0100
-@@ -75,7 +75,7 @@
- MATH_LIB = @MATH_LIB@
-
- LD = @LD@
--LINK = @LINK_TESTS@ $(LIBTOOL_LINK) $(CC) $(CFLAGS)
-+LINK = @LINK_TESTS@ $(LIBTOOL_LINK) $(CC)
-
- usFLAGS = @LD_MODEL@ @LOCAL_LDFLAGS@ @LDFLAGS@
-
-diff -ru ncurses-5.5-orig/ncurses/tinfo/read_entry.c ncurses-5.5/ncurses/tinfo/read_entry.c
---- ncurses-5.5-orig/ncurses/tinfo/read_entry.c 2004-01-11 02:57:05.000000000 +0100
-+++ ncurses-5.5/ncurses/tinfo/read_entry.c 2006-03-25 22:49:39.000000000 +0100
-@@ -474,7 +474,7 @@
- }
-
- /* truncate the terminal name to prevent buffer overflow */
-- (void) sprintf(ttn, "%c/%.*s", *tn, (int) sizeof(ttn) - 3, tn);
-+ (void) sprintf(ttn, "%x/%.*s", *tn, (int) sizeof(ttn) - 3, tn);
-
- /* This is System V behavior, in conjunction with our requirements for
- * writing terminfo entries.
-diff -ru ncurses-5.5-orig/configure ncurses-5.5/configure
---- ncurses-5.5-orig/configure 2005-09-24 23:50:50.000000000 +0200
-+++ ncurses-5.5/configure 2006-03-26 22:24:59.000000000 +0200
-@@ -5027,7 +5027,7 @@
- darwin*)
- EXTRA_CFLAGS="-no-cpp-precomp"
- CC_SHARED_OPTS="-dynamic"
-- MK_SHARED_LIB='$(CC) -dynamiclib -install_name $(DESTDIR)$(libdir)/`basename $@` -compatibility_version $(ABI_VERSION) -current_version $(ABI_VERSION) -o $@'
-+ MK_SHARED_LIB='$(CC) $(CFLAGS) -dynamiclib -install_name $(DESTDIR)$(libdir)/`basename $@` -compatibility_version $(ABI_VERSION) -current_version $(ABI_VERSION) -o $@'
- test "$cf_cv_shlib_version" = auto && cf_cv_shlib_version=abi
- cf_cv_shlib_version_infix=yes
- ;;
diff --git a/Mac/BuildScript/resources/ReadMe.txt b/Mac/BuildScript/resources/ReadMe.txt
index f1beda0..9ac52d0 100644
--- a/Mac/BuildScript/resources/ReadMe.txt
+++ b/Mac/BuildScript/resources/ReadMe.txt
@@ -5,8 +5,15 @@ $ARCHITECTURES.
Installation requires approximately $INSTALL_SIZE MB of disk space,
ignore the message that it will take zero bytes.
-You must install onto your current boot disk, even though the
-installer does not enforce this, otherwise things will not work.
+If you are attempting to install on an OS X 10.8 system, you may
+see a message that Python can't be installed because it is from an
+unidentified developer. This is because this Python installer
+package is not yet compatible with the Gatekeeper security feature
+introduced in OS X 10.8. To allow Python to be installed, you
+can override the Gatekeeper policy for this install. In the Finder,
+instead of double-clicking, control-click or right click the "Python"
+installer package icon. Then select "Open using ... Installer" from
+the contextual menu that appears.
Python consists of the Python programming language interpreter, plus
a set of programs to allow easy access to it for Mac users including
@@ -16,10 +23,11 @@ Python programs.
**** IMPORTANT ****
-Before using IDLE or other programs using the tkinter graphical user
-interface toolkit, visit http://www.python.org/download/mac/tcltk/
-for current information about supported and recommended versions
-of Tcl/Tk for this version of Python and Mac OS X.
+To use IDLE or other programs that use the tkinter graphical user
+interface toolkit, you may need to install a third-party version of
+the Tcl/Tk frameworks. Visit http://www.python.org/download/mac/tcltk/
+for current information about supported and recommended versions of
+Tcl/Tk for this version of Python and of Mac OS X.
*******************
@@ -32,5 +40,13 @@ optionally place links to the command-line tools in /usr/local/bin as
well. Double-click on the "Update Shell Profile" command to add the
"bin" directory inside the framework to your shell's search path.
+You must install onto your current boot disk, even though the
+installer does not enforce this, otherwise things will not work.
+
+You can verify the integrity of the disk image file containing the
+installer package and this ReadMe file by comparing its md5 checksum
+and size with the values published on the release page linked at
+http://www.python.org/download/
+
More information on Python in general can be found at
http://www.python.org.
diff --git a/Mac/BuildScript/resources/Welcome.rtf b/Mac/BuildScript/resources/Welcome.rtf
index d209b10..86fbf63 100644
--- a/Mac/BuildScript/resources/Welcome.rtf
+++ b/Mac/BuildScript/resources/Welcome.rtf
@@ -1,8 +1,8 @@
-{\rtf1\ansi\ansicpg1252\cocoartf1038\cocoasubrtf350
+{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf470
{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
{\colortbl;\red255\green255\blue255;}
\paperw11904\paperh16836\margl1440\margr1440\vieww9640\viewh10620\viewkind0
-\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\ql\qnatural
+\pard\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640
\f0\fs24 \cf0 This package will install
\b Python $FULL_VERSION
@@ -20,9 +20,9 @@ See the ReadMe file and the Python documentation for more information.\
\
\b NOTE:
-\b0 This package will by default not update your shell profile and will also not install files in /usr/local. Double-click
+\b0 This package will not update your shell profile by default. Double-click
\b Update Shell Profile
-\b0 at any time to make $FULL_VERSION the default Python.\
+\b0 at any time to make $FULL_VERSION the default Python 3 version. This version can co-exist with other installed versions of Python 3 and Python 2.\
\
\b IMPORTANT:
diff --git a/Mac/BuildScript/scripts/postflight.documentation b/Mac/BuildScript/scripts/postflight.documentation
index 31fbf2f..c4ba616 100755
--- a/Mac/BuildScript/scripts/postflight.documentation
+++ b/Mac/BuildScript/scripts/postflight.documentation
@@ -5,19 +5,10 @@ FWK="/Library/Frameworks/Python.framework/Versions/${PYVER}"
FWK_DOCDIR_SUBPATH="Resources/English.lproj/Documentation"
FWK_DOCDIR="${FWK}/${FWK_DOCDIR_SUBPATH}"
APPDIR="/Applications/Python ${PYVER}"
-DEV_DOCDIR="/Developer/Documentation"
SHARE_DIR="${FWK}/share"
SHARE_DOCDIR="${SHARE_DIR}/doc/python${PYVER}"
SHARE_DOCDIR_TO_FWK="../../.."
-# make link in /Developer/Documentation/ for Xcode users
-if [ -d "${DEV_DOCDIR}" ]; then
- if [ ! -d "${DEV_DOCDIR}/Python" ]; then
- mkdir -p "${DEV_DOCDIR}/Python"
- fi
- ln -fhs "${FWK_DOCDIR}" "${DEV_DOCDIR}/Python/Reference Documentation ${PYVER}"
-fi
-
# make link in /Applications/Python m.n/ for Finder users
if [ -d "${APPDIR}" ]; then
ln -fhs "${FWK_DOCDIR}/index.html" "${APPDIR}/Python Documentation.html"
diff --git a/Mac/BuildScript/scripts/postflight.framework b/Mac/BuildScript/scripts/postflight.framework
index 9fc9151..eb08297 100755
--- a/Mac/BuildScript/scripts/postflight.framework
+++ b/Mac/BuildScript/scripts/postflight.framework
@@ -8,14 +8,24 @@ FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@"
"${FWK}/bin/python@PYVER@" -Wi \
"${FWK}/lib/python${PYVER}/compileall.py" \
- -x badsyntax -x site-packages \
+ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
"${FWK}/lib/python${PYVER}"
"${FWK}/bin/python@PYVER@" -Wi -O \
"${FWK}/lib/python${PYVER}/compileall.py" \
- -x badsyntax -x site-packages \
+ -f -x 'bad_coding|badsyntax|site-packages|lib2to3/tests/data' \
"${FWK}/lib/python${PYVER}"
+"${FWK}/bin/python@PYVER@" -Wi \
+ "${FWK}/lib/python${PYVER}/compileall.py" \
+ -f -x badsyntax \
+ "${FWK}/lib/python${PYVER}/site-packages"
+
+"${FWK}/bin/python@PYVER@" -Wi -O \
+ "${FWK}/lib/python${PYVER}/compileall.py" \
+ -f -x badsyntax \
+ "${FWK}/lib/python${PYVER}/site-packages"
+
chgrp -R admin "${FWK}"
chmod -R g+w "${FWK}"
diff --git a/Mac/Makefile.in b/Mac/Makefile.in
index 8a62a90..354c1fd 100644
--- a/Mac/Makefile.in
+++ b/Mac/Makefile.in
@@ -40,14 +40,13 @@ INSTALL_SCRIPT= @INSTALL_SCRIPT@
INSTALL_DATA=@INSTALL_DATA@
LN=@LN@
STRIPFLAG=-s
-CPMAC=/Developer/Tools/CpMac
+CPMAC=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)"
@@ -72,7 +71,7 @@ installunixtools:
for fn in python3 pythonw3 idle3 pydoc3 python3-config \
python$(VERSION) pythonw$(VERSION) idle$(VERSION) \
pydoc$(VERSION) python$(VERSION)-config 2to3 \
- 2to3-$(VERSION) ;\
+ 2to3-$(VERSION) pyvenv pyvenv-$(VERSION) ;\
do \
ln -fs "$(prefix)/bin/$${fn}" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/$${fn}" ;\
done
@@ -93,7 +92,7 @@ altinstallunixtools:
$(INSTALL) -d -m $(DIRMODE) "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" ;\
fi
for fn in python$(VERSION) pythonw$(VERSION) idle$(VERSION) \
- pydoc$(VERSION) python$(VERSION)-config 2to3-$(VERSION);\
+ pydoc$(VERSION) python$(VERSION)-config 2to3-$(VERSION) pyvenv-$(VERSION) ;\
do \
ln -fs "$(prefix)/bin/$${fn}" "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin/$${fn}" ;\
done
@@ -196,14 +195,6 @@ installextras: $(srcdir)/Extras.install.py
"$(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
diff --git a/Mac/README b/Mac/README
index 6853db4..f7bc6c3 100644
--- a/Mac/README
+++ b/Mac/README
@@ -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 @@ the Python distribution.
_`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 @@ the Python distribution.
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 @@ the Python distribution.
* ``--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 @@ Building and using a universal binary of Python on Mac OS X
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,38 +82,55 @@ flag to configure::
$ 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.
-
-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
+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
+.................................
+
+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
+
+ * 10.7 and 10.8 SDKs with Xcode 4 support ``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``).
+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
-.............................
+Running a specific architecture
+...............................
You can run code using a specific architecture using the ``arch`` command::
@@ -113,6 +145,14 @@ Python 2.7 or 3.2, in earlier versions the python (and pythonw) commands are
wrapper tools that execute the real interpreter without ensuring that the
real interpreter runs with the same architecture.
+Using ``arch`` is not a perfect solution as the selected architecture will
+not automatically carry through to subprocesses launched by programs and tests
+under that Python. If you want to ensure that Python interpreters launched in
+subprocesses also run in 32-bit-mode if the main interpreter does, use
+a ``python3.3-32`` binary and use the value of ``sys.executable`` as the
+``subprocess`` ``Popen`` executable value.
+
+
Building and using a framework-based Python on Mac OS X.
========================================================
@@ -122,17 +162,17 @@ Building and using a framework-based Python on Mac OS X.
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?
@@ -148,18 +188,25 @@ Versions/Current and you will see the familiar bin and lib directories.
----------------------------
Yes, probably. If you want Tkinter support you need to get the OSX AquaTk
-distribution, this is installed by default on Mac OS X 10.4 or later. If
-you want wxPython you need to get that. If you want Cocoa you need to get
-PyObjC.
+distribution, this is installed by default on Mac OS X 10.4 or later. Be
+aware, though, that the Cocoa-based AquaTk's supplied starting with OS X
+10.6 have proven to be unstable. If possible, you should consider
+installing a newer version before building on OS X 10.6 or later, such as
+the ActiveTcl 8.5. See http://www.python.org/download/mac/tcltk/. If you
+are building with an SDK, ensure that the newer Tcl and Tk frameworks are
+seen in the SDK's ``Library/Frameworks`` directory; you may need to
+manually create symlinks to their installed location, ``/Library/Frameworks``.
+If you want wxPython you need to get that.
+If you want Cocoa you need to get PyObjC.
4. How do I build a framework Python?
-------------------------------------
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 +218,15 @@ in the sequence
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 +234,7 @@ framework itself, the Mac subtree, the applications and the unix tools.
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 +247,41 @@ debugger, etc.
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. It should be possible to use SDKs and/or older
+versions of Xcode to build installers that are compatible with older systems
+on a newer system but this may not be completely foolproof so the resulting
+executables, shared libraries, and ``.so`` bundles should be carefully
+examined and tested on all supported systems for proper dynamic linking
+dependencies. It is safest to build the distribution on a system running the
+minimum OS X version supported.
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 /.
@@ -244,7 +306,7 @@ The configure script sometimes emits warnings like the one below::
configure: WARNING: ## -------------------------------------- ##
This almost always means you are trying to build a universal binary for
-Python and have libaries in ``/usr/local`` that don't contain the required
+Python and have libraries in ``/usr/local`` that don't contain the required
architectures. Temporarily move ``/usr/local`` aside to finish the build.
@@ -253,7 +315,7 @@ Uninstalling a framework install, including the binary installer
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 +329,12 @@ A framework install also installs some applications in ``/Applications/Python X.
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
-=============
-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.
+Resources
+=========
+
+ * http://www.python.org/download/mac/
+
+ * http://www.python.org/community/sigs/current/pythonmac-sig/
- Jack Jansen, Jack.Jansen@cwi.nl, 15-Jul-2004.
- Ronald Oussoren, RonaldOussoren@mac.com, 30-April-2010
+ * http://docs.python.org/devguide/ \ No newline at end of file
diff --git a/Mac/Tools/fixapplepython23.py b/Mac/Tools/fixapplepython23.py
deleted file mode 100644
index 18b95b3..0000000
--- a/Mac/Tools/fixapplepython23.py
+++ /dev/null
@@ -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()
diff --git a/Mac/Tools/pythonw.c b/Mac/Tools/pythonw.c
index 30c82ac..1d2db38 100644
--- a/Mac/Tools/pythonw.c
+++ b/Mac/Tools/pythonw.c
@@ -28,6 +28,7 @@
#include <dlfcn.h>
#include <stdlib.h>
#include <Python.h>
+#include <mach-o/dyld.h>
extern char** environ;
@@ -150,6 +151,53 @@ setup_spawnattr(posix_spawnattr_t* spawnattr)
int
main(int argc, char **argv) {
char* exec_path = get_python_path();
+ static char path[PATH_MAX * 2];
+ static char real_path[PATH_MAX * 2];
+ int status;
+ uint32_t size = PATH_MAX * 2;
+
+ /* Set the original executable path in the environment. */
+ status = _NSGetExecutablePath(path, &size);
+ if (status == 0) {
+ /*
+ * Note: don't call 'realpath', that will
+ * erase symlink information, and that
+ * breaks "pyvenv --symlink"
+ *
+ * It is nice to have the directory name
+ * as a cleaned up absolute path though,
+ * therefore call realpath on dirname(path)
+ */
+ char* slash = strrchr(path, '/');
+ if (slash) {
+ char replaced;
+ replaced = slash[1];
+ slash[1] = 0;
+ if (realpath(path, real_path) == NULL) {
+ err(1, "realpath: %s", path);
+ }
+ slash[1] = replaced;
+ if (strlcat(real_path, slash, sizeof(real_path)) > sizeof(real_path)) {
+ errno = EINVAL;
+ err(1, "realpath: %s", path);
+ }
+
+ } else {
+ if (realpath(".", real_path) == NULL) {
+ err(1, "realpath: %s", path);
+ }
+ if (strlcat(real_path, "/", sizeof(real_path)) > sizeof(real_path)) {
+ errno = EINVAL;
+ err(1, "realpath: %s", path);
+ }
+ if (strlcat(real_path, path, sizeof(real_path)) > sizeof(real_path)) {
+ errno = EINVAL;
+ err(1, "realpath: %s", path);
+ }
+ }
+
+ setenv("__PYVENV_LAUNCHER__", real_path, 1);
+ }
/*
* Let argv[0] refer to the new interpreter. This is needed to