Commit 1943f868 authored by Ronald Oussoren's avatar Ronald Oussoren

Merged revisions 70737 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r70737 | ronald.oussoren | 2009-03-30 14:34:51 -0500 (Mon, 30 Mar 2009) | 6 lines

  * Set a custom icon on the Python installer DMG
  * Remove last traces of "MacPython"
  * Add options to build different flavors of the installer
    (still defaulting to a 2-way universal build that
    runs on OSX 10.3)
........
parent 4a85269f
...@@ -37,6 +37,17 @@ Here are the steps you need to follow to build a MacPython installer: ...@@ -37,6 +37,17 @@ Here are the steps you need to follow to build a MacPython installer:
* When done the script will tell you where the DMG image is (by default * When done the script will tell you where the DMG image is (by default
somewhere in ``/tmp/_py``). somewhere in ``/tmp/_py``).
Building a 4-way universal installer
....................................
It is also possible to build a 4-way universal installer that runs on
OSX Leopard or later::
$ ./build-installer.py --dep-target=10.5 --universal-archs=all --sdk=/
This requires that the deployment target is 10.5 (or later), and hence
also that your building on at least OSX 10.5.
Testing Testing
------- -------
......
...@@ -2,7 +2,8 @@ ...@@ -2,7 +2,8 @@
""" """
This script is used to build the "official unofficial" universal build on This script is used to build the "official unofficial" universal build on
Mac OS X. It requires Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK to do its Mac OS X. It requires Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK to do its
work. work. 64-bit or four-way universal builds require at least OS X 10.5 and
the 10.5 SDK.
Please ensure that this script keeps working with Python 2.3, to avoid Please ensure that this script keeps working with Python 2.3, to avoid
bootstrap issues (/usr/bin/python is Python 2.3 on OSX 10.4) bootstrap issues (/usr/bin/python is Python 2.3 on OSX 10.4)
...@@ -63,7 +64,15 @@ DEPSRC = os.path.expanduser('~/Universal/other-sources') ...@@ -63,7 +64,15 @@ DEPSRC = os.path.expanduser('~/Universal/other-sources')
SDKPATH = "/Developer/SDKs/MacOSX10.4u.sdk" SDKPATH = "/Developer/SDKs/MacOSX10.4u.sdk"
#SDKPATH = "/" #SDKPATH = "/"
ARCHLIST = ('i386', 'ppc',) universal_opts_map = { '32-bit': ('i386', 'ppc',),
'64-bit': ('x86_64', 'ppc64',),
'all': ('i386', 'ppc', 'x86_64', 'ppc64',) }
UNIVERSALOPTS = tuple(universal_opts_map.keys())
UNIVERSALARCHS = '32-bit'
ARCHLIST = universal_opts_map[UNIVERSALARCHS]
# Source directory (asume we're in Mac/BuildScript) # Source directory (asume we're in Mac/BuildScript)
SRCDIR = os.path.dirname( SRCDIR = os.path.dirname(
...@@ -72,6 +81,9 @@ SRCDIR = os.path.dirname( ...@@ -72,6 +81,9 @@ SRCDIR = os.path.dirname(
os.path.abspath(__file__ os.path.abspath(__file__
)))) ))))
# $MACOSX_DEPLOYMENT_TARGET -> minimum OS X level
DEPTARGET = '10.3'
USAGE = textwrap.dedent("""\ USAGE = textwrap.dedent("""\
Usage: build_python [options] Usage: build_python [options]
...@@ -82,62 +94,67 @@ USAGE = textwrap.dedent("""\ ...@@ -82,62 +94,67 @@ USAGE = textwrap.dedent("""\
--third-party=DIR: Store third-party sources here (default: %(DEPSRC)r) --third-party=DIR: Store third-party sources here (default: %(DEPSRC)r)
--sdk-path=DIR: Location of the SDK (default: %(SDKPATH)r) --sdk-path=DIR: Location of the SDK (default: %(SDKPATH)r)
--src-dir=DIR: Location of the Python sources (default: %(SRCDIR)r) --src-dir=DIR: Location of the Python sources (default: %(SRCDIR)r)
--dep-target=10.n OS X deployment target (default: %(DEPTARGET)r)
--universal-archs=x universal architectures (options: %(UNIVERSALOPTS)r, default: %(UNIVERSALARCHS)r)
""")% globals() """)% globals()
# Instructions for building libraries that are necessary for building a # Instructions for building libraries that are necessary for building a
# batteries included python. # batteries included python.
LIBRARY_RECIPES = [ # [The recipes are defined here for convenience but instantiated later after
dict( # command line options have been processed.]
name="Bzip2 1.0.4", def library_recipes():
url="http://www.bzip.org/1.0.4/bzip2-1.0.4.tar.gz", return [
checksum='fc310b254f6ba5fbb5da018f04533688', dict(
configure=None, name="Bzip2 1.0.4",
install='make install PREFIX=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%( url="http://www.bzip.org/1.0.4/bzip2-1.0.4.tar.gz",
shellQuote(os.path.join(WORKDIR, 'libraries')), checksum='fc310b254f6ba5fbb5da018f04533688',
' -arch '.join(ARCHLIST), configure=None,
SDKPATH, install='make install PREFIX=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%(
), shellQuote(os.path.join(WORKDIR, 'libraries')),
), ' -arch '.join(ARCHLIST),
dict( SDKPATH,
name="ZLib 1.2.3", ),
url="http://www.gzip.org/zlib/zlib-1.2.3.tar.gz", ),
checksum='debc62758716a169df9f62e6ab2bc634', dict(
configure=None, name="ZLib 1.2.3",
install='make install prefix=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%( url="http://www.gzip.org/zlib/zlib-1.2.3.tar.gz",
shellQuote(os.path.join(WORKDIR, 'libraries')), checksum='debc62758716a169df9f62e6ab2bc634',
' -arch '.join(ARCHLIST), configure=None,
SDKPATH, install='make install prefix=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%(
), shellQuote(os.path.join(WORKDIR, 'libraries')),
), ' -arch '.join(ARCHLIST),
dict( SDKPATH,
# Note that GNU readline is GPL'd software ),
name="GNU Readline 5.1.4", ),
url="http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz" , dict(
checksum='7ee5a692db88b30ca48927a13fd60e46', # Note that GNU readline is GPL'd software
patchlevel='0', name="GNU Readline 5.1.4",
patches=[ url="http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz" ,
# The readline maintainers don't do actual micro releases, but checksum='7ee5a692db88b30ca48927a13fd60e46',
# just ship a set of patches. patchlevel='0',
'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-001', patches=[
'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-002', # The readline maintainers don't do actual micro releases, but
'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-003', # just ship a set of patches.
'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-004', 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-001',
] 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-002',
), 'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-003',
'http://ftp.gnu.org/pub/gnu/readline/readline-5.1-patches/readline51-004',
dict( ]
name="SQLite 3.6.11", ),
url="http://www.sqlite.org/sqlite-3.6.11.tar.gz",
checksum='7ebb099696ab76cc6ff65dd496d17858', dict(
configure_pre=[ name="SQLite 3.6.11",
'--enable-threadsafe', url="http://www.sqlite.org/sqlite-3.6.11.tar.gz",
'--enable-tempstore', checksum='7ebb099696ab76cc6ff65dd496d17858',
'--enable-shared=no', configure_pre=[
'--enable-static=yes', '--enable-threadsafe',
'--disable-tcl', '--enable-tempstore',
] '--enable-shared=no',
), '--enable-static=yes',
'--disable-tcl',
]
),
dict( dict(
name="NCurses 5.5", name="NCurses 5.5",
...@@ -170,7 +187,6 @@ LIBRARY_RECIPES = [ ...@@ -170,7 +187,6 @@ LIBRARY_RECIPES = [
), ),
] ]
# Instructions for building packages inside the .mpkg. # Instructions for building packages inside the .mpkg.
PKG_RECIPES = [ PKG_RECIPES = [
dict( dict(
...@@ -205,8 +221,8 @@ PKG_RECIPES = [ ...@@ -205,8 +221,8 @@ PKG_RECIPES = [
source="/usr/local/bin", source="/usr/local/bin",
readme="""\ readme="""\
This package installs the unix tools in /usr/local/bin for This package installs the unix tools in /usr/local/bin for
compatibility with older releases of MacPython. This package compatibility with older releases of Python. This package
is not necessary to use MacPython. is not necessary to use Python.
""", """,
required=False, required=False,
selected='unselected', selected='unselected',
...@@ -231,7 +247,7 @@ PKG_RECIPES = [ ...@@ -231,7 +247,7 @@ PKG_RECIPES = [
long_name="Shell profile updater", long_name="Shell profile updater",
readme="""\ readme="""\
This packages updates your shell profile to make sure that This packages updates your shell profile to make sure that
the MacPython tools are found by your shell in preference of the Python tools are found by your shell in preference of
the system provided Python tools. the system provided Python tools.
If you don't install this package you'll have to add If you don't install this package you'll have to add
...@@ -321,14 +337,16 @@ def parseOptions(args=None): ...@@ -321,14 +337,16 @@ def parseOptions(args=None):
""" """
Parse arguments and update global settings. Parse arguments and update global settings.
""" """
global WORKDIR, DEPSRC, SDKPATH, SRCDIR global WORKDIR, DEPSRC, SDKPATH, SRCDIR, DEPTARGET
global UNIVERSALOPTS, UNIVERSALARCHS, ARCHLIST
if args is None: if args is None:
args = sys.argv[1:] args = sys.argv[1:]
try: try:
options, args = getopt.getopt(args, '?hb', options, args = getopt.getopt(args, '?hb',
[ 'build-dir=', 'third-party=', 'sdk-path=' , 'src-dir=']) [ 'build-dir=', 'third-party=', 'sdk-path=' , 'src-dir=',
'dep-target=', 'universal-archs=', 'help' ])
except getopt.error, msg: except getopt.error, msg:
print msg print msg
sys.exit(1) sys.exit(1)
...@@ -338,7 +356,7 @@ def parseOptions(args=None): ...@@ -338,7 +356,7 @@ def parseOptions(args=None):
sys.exit(1) sys.exit(1)
for k, v in options: for k, v in options:
if k in ('-h', '-?'): if k in ('-h', '-?', '--help'):
print USAGE print USAGE
sys.exit(0) sys.exit(0)
...@@ -354,6 +372,16 @@ def parseOptions(args=None): ...@@ -354,6 +372,16 @@ def parseOptions(args=None):
elif k in ('--src-dir',): elif k in ('--src-dir',):
SRCDIR=v SRCDIR=v
elif k in ('--dep-target', ):
DEPTARGET=v
elif k in ('--universal-archs', ):
if v in UNIVERSALOPTS:
UNIVERSALARCHS = v
ARCHLIST = universal_opts_map[UNIVERSALARCHS]
else:
raise NotImplementedError, v
else: else:
raise NotImplementedError, k raise NotImplementedError, k
...@@ -366,7 +394,9 @@ def parseOptions(args=None): ...@@ -366,7 +394,9 @@ def parseOptions(args=None):
print " * Source directory:", SRCDIR print " * Source directory:", SRCDIR
print " * Build directory: ", WORKDIR print " * Build directory: ", WORKDIR
print " * SDK location: ", SDKPATH print " * SDK location: ", SDKPATH
print " * third-party source:", DEPSRC print " * Third-party source:", DEPSRC
print " * Deployment target:", DEPTARGET
print " * Universal architectures:", ARCHLIST
print "" print ""
...@@ -476,6 +506,7 @@ def buildRecipe(recipe, basedir, archList): ...@@ -476,6 +506,7 @@ def buildRecipe(recipe, basedir, archList):
print "Using local copy of %s"%(name,) print "Using local copy of %s"%(name,)
else: else:
print "Did not find local copy of %s"%(name,)
print "Downloading %s"%(name,) print "Downloading %s"%(name,)
downloadURL(url, sourceArchive) downloadURL(url, sourceArchive)
print "Archive for %s stored as %s"%(name, sourceArchive) print "Archive for %s stored as %s"%(name, sourceArchive)
...@@ -566,7 +597,7 @@ def buildLibraries(): ...@@ -566,7 +597,7 @@ def buildLibraries():
os.makedirs(os.path.join(universal, 'usr', 'local', 'lib')) os.makedirs(os.path.join(universal, 'usr', 'local', 'lib'))
os.makedirs(os.path.join(universal, 'usr', 'local', 'include')) os.makedirs(os.path.join(universal, 'usr', 'local', 'include'))
for recipe in LIBRARY_RECIPES: for recipe in library_recipes():
buildRecipe(recipe, universal, ARCHLIST) buildRecipe(recipe, universal, ARCHLIST)
...@@ -590,7 +621,7 @@ def buildPythonDocs(): ...@@ -590,7 +621,7 @@ def buildPythonDocs():
def buildPython(): def buildPython():
print "Building a universal python" print "Building a universal python for %s architectures" % UNIVERSALARCHS
buildDir = os.path.join(WORKDIR, '_bld', 'python') buildDir = os.path.join(WORKDIR, '_bld', 'python')
rootDir = os.path.join(WORKDIR, '_root') rootDir = os.path.join(WORKDIR, '_root')
...@@ -614,9 +645,13 @@ def buildPython(): ...@@ -614,9 +645,13 @@ def buildPython():
version = getVersion() version = getVersion()
print "Running configure..." print "Running configure..."
runCommand("%s -C --enable-framework --enable-universalsdk=%s LDFLAGS='-g -L%s/libraries/usr/local/lib' OPT='-g -O3 -I%s/libraries/usr/local/include' 2>&1"%( runCommand("%s -C --enable-framework --enable-universalsdk=%s "
shellQuote(os.path.join(SRCDIR, 'configure')), "--with-universal-archs=%s "
shellQuote(SDKPATH), shellQuote(WORKDIR)[1:-1], "LDFLAGS='-g -L%s/libraries/usr/local/lib' "
"OPT='-g -O3 -I%s/libraries/usr/local/include' 2>&1"%(
shellQuote(os.path.join(SRCDIR, 'configure')), shellQuote(SDKPATH),
UNIVERSALARCHS,
shellQuote(WORKDIR)[1:-1],
shellQuote(WORKDIR)[1:-1])) shellQuote(WORKDIR)[1:-1]))
print "Running make" print "Running make"
...@@ -704,7 +739,7 @@ def patchFile(inPath, outPath): ...@@ -704,7 +739,7 @@ def patchFile(inPath, outPath):
data = fileContents(inPath) data = fileContents(inPath)
data = data.replace('$FULL_VERSION', getFullVersion()) data = data.replace('$FULL_VERSION', getFullVersion())
data = data.replace('$VERSION', getVersion()) data = data.replace('$VERSION', getVersion())
data = data.replace('$MACOSX_DEPLOYMENT_TARGET', '10.3 or later') data = data.replace('$MACOSX_DEPLOYMENT_TARGET', ''.join((DEPTARGET, ' or later')))
data = data.replace('$ARCHITECTURES', "i386, ppc") data = data.replace('$ARCHITECTURES', "i386, ppc")
data = data.replace('$INSTALL_SIZE', installSize()) data = data.replace('$INSTALL_SIZE', installSize())
...@@ -784,9 +819,9 @@ def packageFromRecipe(targetDir, recipe): ...@@ -784,9 +819,9 @@ def packageFromRecipe(targetDir, recipe):
vers = getFullVersion() vers = getFullVersion()
major, minor = map(int, getVersion().split('.', 2)) major, minor = map(int, getVersion().split('.', 2))
pl = Plist( pl = Plist(
CFBundleGetInfoString="MacPython.%s %s"%(pkgname, vers,), CFBundleGetInfoString="Python.%s %s"%(pkgname, vers,),
CFBundleIdentifier='org.python.MacPython.%s'%(pkgname,), CFBundleIdentifier='org.python.Python.%s'%(pkgname,),
CFBundleName='MacPython.%s'%(pkgname,), CFBundleName='Python.%s'%(pkgname,),
CFBundleShortVersionString=vers, CFBundleShortVersionString=vers,
IFMajorVersion=major, IFMajorVersion=major,
IFMinorVersion=minor, IFMinorVersion=minor,
...@@ -807,7 +842,7 @@ def packageFromRecipe(targetDir, recipe): ...@@ -807,7 +842,7 @@ def packageFromRecipe(targetDir, recipe):
pl = Plist( pl = Plist(
IFPkgDescriptionDescription=readme, IFPkgDescriptionDescription=readme,
IFPkgDescriptionTitle=recipe.get('long_name', "MacPython.%s"%(pkgname,)), IFPkgDescriptionTitle=recipe.get('long_name', "Python.%s"%(pkgname,)),
IFPkgDescriptionVersion=vers, IFPkgDescriptionVersion=vers,
) )
writePlist(pl, os.path.join(packageContents, 'Resources', 'Description.plist')) writePlist(pl, os.path.join(packageContents, 'Resources', 'Description.plist'))
...@@ -822,9 +857,9 @@ def makeMpkgPlist(path): ...@@ -822,9 +857,9 @@ def makeMpkgPlist(path):
major, minor = map(int, getVersion().split('.', 2)) major, minor = map(int, getVersion().split('.', 2))
pl = Plist( pl = Plist(
CFBundleGetInfoString="MacPython %s"%(vers,), CFBundleGetInfoString="Python %s"%(vers,),
CFBundleIdentifier='org.python.MacPython', CFBundleIdentifier='org.python.Python',
CFBundleName='MacPython', CFBundleName='Python',
CFBundleShortVersionString=vers, CFBundleShortVersionString=vers,
IFMajorVersion=major, IFMajorVersion=major,
IFMinorVersion=minor, IFMinorVersion=minor,
...@@ -858,7 +893,7 @@ def buildInstaller(): ...@@ -858,7 +893,7 @@ def buildInstaller():
shutil.rmtree(outdir) shutil.rmtree(outdir)
os.mkdir(outdir) os.mkdir(outdir)
pkgroot = os.path.join(outdir, 'MacPython.mpkg', 'Contents') pkgroot = os.path.join(outdir, 'Python.mpkg', 'Contents')
pkgcontents = os.path.join(pkgroot, 'Packages') pkgcontents = os.path.join(pkgroot, 'Packages')
os.makedirs(pkgcontents) os.makedirs(pkgcontents)
for recipe in PKG_RECIPES: for recipe in PKG_RECIPES:
...@@ -875,7 +910,7 @@ def buildInstaller(): ...@@ -875,7 +910,7 @@ def buildInstaller():
makeMpkgPlist(os.path.join(pkgroot, 'Info.plist')) makeMpkgPlist(os.path.join(pkgroot, 'Info.plist'))
pl = Plist( pl = Plist(
IFPkgDescriptionTitle="Universal MacPython", IFPkgDescriptionTitle="Python",
IFPkgDescriptionVersion=getVersion(), IFPkgDescriptionVersion=getVersion(),
) )
...@@ -915,10 +950,32 @@ def buildDMG(): ...@@ -915,10 +950,32 @@ def buildDMG():
imagepath = imagepath + '.dmg' imagepath = imagepath + '.dmg'
os.mkdir(outdir) os.mkdir(outdir)
runCommand("hdiutil create -volname 'Universal MacPython %s' -srcfolder %s %s"%( volname='Python %s'%(getFullVersion())
getFullVersion(), runCommand("hdiutil create -format UDRW -volname %s -srcfolder %s %s"%(
shellQuote(volname),
shellQuote(os.path.join(WORKDIR, 'installer')), shellQuote(os.path.join(WORKDIR, 'installer')),
shellQuote(imagepath))) shellQuote(imagepath + ".tmp.dmg" )))
if not os.path.exists(os.path.join(WORKDIR, "mnt")):
os.mkdir(os.path.join(WORKDIR, "mnt"))
runCommand("hdiutil attach %s -mountroot %s"%(
shellQuote(imagepath + ".tmp.dmg"), shellQuote(os.path.join(WORKDIR, "mnt"))))
# 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/"%(
shellQuote(os.path.join(WORKDIR, "mnt", volname)),))
runCommand("hdiutil detach %s"%(shellQuote(os.path.join(WORKDIR, "mnt", volname))))
setIcon(imagepath + ".tmp.dmg", "../Icons/Disk Image.icns")
runCommand("hdiutil convert %s -format UDZO -o %s"%(
shellQuote(imagepath + ".tmp.dmg"), shellQuote(imagepath)))
setIcon(imagepath, "../Icons/Disk Image.icns")
os.unlink(imagepath + ".tmp.dmg")
return imagepath return imagepath
...@@ -946,7 +1003,7 @@ def main(): ...@@ -946,7 +1003,7 @@ def main():
parseOptions() parseOptions()
checkEnvironment() checkEnvironment()
os.environ['MACOSX_DEPLOYMENT_TARGET'] = '10.3' os.environ['MACOSX_DEPLOYMENT_TARGET'] = DEPTARGET
if os.path.exists(WORKDIR): if os.path.exists(WORKDIR):
shutil.rmtree(WORKDIR) shutil.rmtree(WORKDIR)
...@@ -982,13 +1039,6 @@ def main(): ...@@ -982,13 +1039,6 @@ def main():
print >> fp, "# By:", pwd.getpwuid(os.getuid()).pw_gecos print >> fp, "# By:", pwd.getpwuid(os.getuid()).pw_gecos
fp.close() fp.close()
# Custom icon for the DMG, shown when the DMG is mounted.
# XXX: Code is diabled because it doesn't actually work :-(
# shutil.copy("../Icons/Disk Image.icns",
# os.path.join(WORKDIR, "installer", ".VolumeIcon.icns"))
# os.system("/Developer/Tools/SetFile -a C %s"%(
# os.path.join(WORKDIR, "installer", ".VolumeIcon.icns")))
setIcon(os.path.join(WORKDIR, "installer"), "../Icons/Disk Image.icns")
# And copy it to a DMG # And copy it to a DMG
......
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