Commit e1c97949 authored by Ned Deily's avatar Ned Deily

Issue #14018: Backport OS X installer updates from 3.3.

parent 8d15ca3c
......@@ -8,51 +8,56 @@ $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:
For Python 2.7.x and 3.2.x, 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.3.9 through (at least) 10.8::
python build-installer.py \
/usr/bin/python build-installer.py \
--sdk-path=/Developer/SDKs/MacOSX10.4u.sdk \
--universal-archs=32-bit \
--dep-target=10.3
# These are the current default options
- builds the following third-party libraries
* Bzip2
* Zlib 1.2.3
* GNU Readline (GPL)
* SQLite 3
* NCurses
* GNU Readline (GPL)
* SQLite 3.7.13
* 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
- current target build environment:
- recommended build environment:
* Mac OS X 10.5.8 PPC or Intel
* Xcode 3.1.4 (or later)
* Xcode 3.1.4
* ``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
* 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
- uses system-supplied versions of third-party libraries
* readline module links with Apple BSD editline (libedit)
......@@ -60,18 +65,27 @@ for each release:
- requires ActiveState Tcl/Tk 8.5.9 (or later) to be installed for building
- current target build environment:
- recommended build environment:
* Mac OS X 10.6.6 (or later)
* Xcode 3.2.5 (or later)
* 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.5.x
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.
General Prerequisites
......@@ -87,6 +101,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 +126,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 +139,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 +153,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
#!/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,75 @@ USAGE = textwrap.dedent("""\
def library_recipes():
result = []
LT_10_5 = bool(DEPTARGET < '10.5')
if getVersionTuple() >= (3, 3):
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',
]
),
])
result.extend([
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 +266,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 +278,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 +294,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',
('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="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',
]
),
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 +368,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 +394,7 @@ def pkg_recipes():
),
]
if DEPTARGET < '10.4':
if DEPTARGET < '10.4' and not PYTHON_3:
result.append(
dict(
name="PythonSystemFixes",
......@@ -358,7 +426,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 +438,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 +449,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 +491,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 +552,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 +561,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 +600,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 +666,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 +692,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 +730,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 +741,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 +784,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 +829,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 +845,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 +860,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 +888,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 +900,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 +923,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 +943,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,16 +979,23 @@ 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')
# 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,), '')
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()
......@@ -907,17 +1030,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 +1057,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 +1102,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 +1139,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 +1250,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 +1291,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 +1322,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 +1335,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 -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
;;
......@@ -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,15 +23,16 @@ 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.
*******************
The installer puts applications, an "Update Shell Profile" command,
and an Extras folder containing demo programs and tools into the
and a link to the optionally installed Python Documentation into the
"Python $VERSION" subfolder of the system Applications folder,
and puts the underlying machinery into the folder
$PYTHONFRAMEWORKINSTALLDIR. It can
......@@ -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.
......@@ -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"
......
......@@ -8,14 +8,24 @@ FWK="/Library/Frameworks/Python.framework/Versions/@PYVER@"
"${FWK}/bin/python@PYVER@" -Wi -tt \
"${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 -tt -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}"
......
......@@ -38,7 +38,7 @@ 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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment