| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 1 | #!/usr/bin/python | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 2 | """ | 
|  | 3 | This script is used to build the "official unofficial" universal build on | 
|  | 4 | Mac OS X. It requires Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK to do its | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 5 | work.  64-bit or four-way universal builds require at least OS X 10.5 and | 
|  | 6 | the 10.5 SDK. | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 7 |  | 
|  | 8 | Please ensure that this script keeps working with Python 2.3, to avoid | 
|  | 9 | bootstrap issues (/usr/bin/python is Python 2.3 on OSX 10.4) | 
|  | 10 |  | 
|  | 11 | Usage: see USAGE variable in the script. | 
|  | 12 | """ | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 13 | import platform, os, sys, getopt, textwrap, shutil, urllib2, stat, time, pwd | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 14 | import grp | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 15 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 16 | INCLUDE_TIMESTAMP = 1 | 
|  | 17 | VERBOSE = 1 | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 18 |  | 
|  | 19 | from plistlib import Plist | 
|  | 20 |  | 
|  | 21 | import MacOS | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 22 |  | 
|  | 23 | try: | 
|  | 24 | from plistlib import writePlist | 
|  | 25 | except ImportError: | 
|  | 26 | # We're run using python2.3 | 
|  | 27 | def writePlist(plist, path): | 
|  | 28 | plist.write(path) | 
|  | 29 |  | 
|  | 30 | def shellQuote(value): | 
|  | 31 | """ | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 32 | Return the string value in a form that can safely be inserted into | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 33 | a shell command. | 
|  | 34 | """ | 
|  | 35 | return "'%s'"%(value.replace("'", "'\"'\"'")) | 
|  | 36 |  | 
|  | 37 | def grepValue(fn, variable): | 
|  | 38 | variable = variable + '=' | 
|  | 39 | for ln in open(fn, 'r'): | 
|  | 40 | if ln.startswith(variable): | 
|  | 41 | value = ln[len(variable):].strip() | 
|  | 42 | return value[1:-1] | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 43 | raise RuntimeError, "Cannot find variable %s" % variable[:-1] | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 44 |  | 
|  | 45 | def getVersion(): | 
|  | 46 | return grepValue(os.path.join(SRCDIR, 'configure'), 'PACKAGE_VERSION') | 
|  | 47 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 48 | def getVersionTuple(): | 
|  | 49 | return tuple([int(n) for n in getVersion().split('.')]) | 
|  | 50 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 51 | def getFullVersion(): | 
|  | 52 | fn = os.path.join(SRCDIR, 'Include', 'patchlevel.h') | 
|  | 53 | for ln in open(fn): | 
|  | 54 | if 'PY_VERSION' in ln: | 
|  | 55 | return ln.split()[-1][1:-1] | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 56 | raise RuntimeError, "Cannot find full version??" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 57 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 58 | # The directory we'll use to create the build (will be erased and recreated) | 
|  | 59 | WORKDIR = "/tmp/_py" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 60 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 61 | # The directory we'll use to store third-party sources. Set this to something | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 62 | # else if you don't want to re-fetch required libraries every time. | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 63 | DEPSRC = os.path.join(WORKDIR, 'third-party') | 
|  | 64 | DEPSRC = os.path.expanduser('~/Universal/other-sources') | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 65 |  | 
|  | 66 | # Location of the preferred SDK | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 67 |  | 
|  | 68 | ### There are some issues with the SDK selection below here, | 
|  | 69 | ### The resulting binary doesn't work on all platforms that | 
|  | 70 | ### it should. Always default to the 10.4u SDK until that | 
|  | 71 | ### isue is resolved. | 
|  | 72 | ### | 
|  | 73 | ##if int(os.uname()[2].split('.')[0]) == 8: | 
|  | 74 | ##    # Explicitly use the 10.4u (universal) SDK when | 
|  | 75 | ##    # building on 10.4, the system headers are not | 
|  | 76 | ##    # useable for a universal build | 
|  | 77 | ##    SDKPATH = "/Developer/SDKs/MacOSX10.4u.sdk" | 
|  | 78 | ##else: | 
|  | 79 | ##    SDKPATH = "/" | 
|  | 80 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 81 | SDKPATH = "/Developer/SDKs/MacOSX10.4u.sdk" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 82 |  | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 83 | universal_opts_map = { '32-bit': ('i386', 'ppc',), | 
|  | 84 | '64-bit': ('x86_64', 'ppc64',), | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 85 | 'intel':  ('i386', 'x86_64'), | 
|  | 86 | '3-way':  ('ppc', 'i386', 'x86_64'), | 
|  | 87 | 'all':    ('i386', 'ppc', 'x86_64', 'ppc64',) } | 
|  | 88 | default_target_map = { | 
|  | 89 | '64-bit': '10.5', | 
|  | 90 | '3-way': '10.5', | 
|  | 91 | 'intel': '10.5', | 
|  | 92 | 'all': '10.5', | 
|  | 93 | } | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 94 |  | 
|  | 95 | UNIVERSALOPTS = tuple(universal_opts_map.keys()) | 
|  | 96 |  | 
|  | 97 | UNIVERSALARCHS = '32-bit' | 
|  | 98 |  | 
|  | 99 | ARCHLIST = universal_opts_map[UNIVERSALARCHS] | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 100 |  | 
| Thomas Wouters | 73e5a5b | 2006-06-08 15:35:45 +0000 | [diff] [blame] | 101 | # Source directory (asume we're in Mac/BuildScript) | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 102 | SRCDIR = os.path.dirname( | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 103 | os.path.dirname( | 
|  | 104 | os.path.dirname( | 
| Thomas Wouters | 73e5a5b | 2006-06-08 15:35:45 +0000 | [diff] [blame] | 105 | os.path.abspath(__file__ | 
|  | 106 | )))) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 107 |  | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 108 | # $MACOSX_DEPLOYMENT_TARGET -> minimum OS X level | 
|  | 109 | DEPTARGET = '10.3' | 
|  | 110 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 111 | target_cc_map = { | 
|  | 112 | '10.3': 'gcc-4.0', | 
|  | 113 | '10.4': 'gcc-4.0', | 
|  | 114 | '10.5': 'gcc-4.0', | 
|  | 115 | '10.6': 'gcc-4.2', | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 | CC = target_cc_map[DEPTARGET] | 
|  | 119 |  | 
|  | 120 | PYTHON_3 = getVersionTuple() >= (3, 0) | 
|  | 121 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 122 | USAGE = textwrap.dedent("""\ | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 123 | Usage: build_python [options] | 
|  | 124 |  | 
|  | 125 | Options: | 
|  | 126 | -? or -h:            Show this message | 
|  | 127 | -b DIR | 
|  | 128 | --build-dir=DIR:     Create build here (default: %(WORKDIR)r) | 
|  | 129 | --third-party=DIR:   Store third-party sources here (default: %(DEPSRC)r) | 
|  | 130 | --sdk-path=DIR:      Location of the SDK (default: %(SDKPATH)r) | 
|  | 131 | --src-dir=DIR:       Location of the Python sources (default: %(SRCDIR)r) | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 132 | --dep-target=10.n    OS X deployment target (default: %(DEPTARGET)r) | 
|  | 133 | --universal-archs=x  universal architectures (options: %(UNIVERSALOPTS)r, default: %(UNIVERSALARCHS)r) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 134 | """)% globals() | 
|  | 135 |  | 
|  | 136 |  | 
|  | 137 | # Instructions for building libraries that are necessary for building a | 
|  | 138 | # batteries included python. | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 139 | #   [The recipes are defined here for convenience but instantiated later after | 
|  | 140 | #    command line options have been processed.] | 
|  | 141 | def library_recipes(): | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 142 | result = [] | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 143 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 144 | if DEPTARGET < '10.5': | 
|  | 145 | result.extend([ | 
|  | 146 | dict( | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 147 | name="Bzip2 1.0.6", | 
|  | 148 | url="http://bzip.org/1.0.6/bzip2-1.0.6.tar.gz", | 
|  | 149 | checksum='00b516f4704d4a7cb50a1d97e6e8e15b', | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 150 | configure=None, | 
|  | 151 | install='make install CC=%s PREFIX=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%( | 
|  | 152 | CC, | 
|  | 153 | shellQuote(os.path.join(WORKDIR, 'libraries')), | 
|  | 154 | ' -arch '.join(ARCHLIST), | 
|  | 155 | SDKPATH, | 
|  | 156 | ), | 
|  | 157 | ), | 
|  | 158 | dict( | 
|  | 159 | name="ZLib 1.2.3", | 
|  | 160 | url="http://www.gzip.org/zlib/zlib-1.2.3.tar.gz", | 
|  | 161 | checksum='debc62758716a169df9f62e6ab2bc634', | 
|  | 162 | configure=None, | 
|  | 163 | install='make install CC=%s prefix=%s/usr/local/ CFLAGS="-arch %s -isysroot %s"'%( | 
|  | 164 | CC, | 
|  | 165 | shellQuote(os.path.join(WORKDIR, 'libraries')), | 
|  | 166 | ' -arch '.join(ARCHLIST), | 
|  | 167 | SDKPATH, | 
|  | 168 | ), | 
|  | 169 | ), | 
|  | 170 | dict( | 
|  | 171 | # Note that GNU readline is GPL'd software | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 172 | name="GNU Readline 6.1.2", | 
|  | 173 | url="http://ftp.gnu.org/pub/gnu/readline/readline-6.1.tar.gz" , | 
|  | 174 | checksum='fc2f7e714fe792db1ce6ddc4c9fb4ef3', | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 175 | patchlevel='0', | 
|  | 176 | patches=[ | 
|  | 177 | # The readline maintainers don't do actual micro releases, but | 
|  | 178 | # just ship a set of patches. | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 179 | 'http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-001', | 
|  | 180 | 'http://ftp.gnu.org/pub/gnu/readline/readline-6.1-patches/readline61-002', | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 181 | ] | 
|  | 182 | ), | 
|  | 183 | dict( | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 184 | name="SQLite 3.7.4", | 
|  | 185 | url="http://www.sqlite.org/sqlite-autoconf-3070400.tar.gz", | 
|  | 186 | checksum='8f0c690bfb33c3cbbc2471c3d9ba0158', | 
|  | 187 | configure_env=('CFLAGS="-Os' | 
|  | 188 | ' -DSQLITE_ENABLE_FTS3' | 
|  | 189 | ' -DSQLITE_ENABLE_FTS3_PARENTHESIS' | 
|  | 190 | ' -DSQLITE_ENABLE_RTREE' | 
|  | 191 | ' -DSQLITE_TCL=0' | 
|  | 192 | '"'), | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 193 | configure_pre=[ | 
|  | 194 | '--enable-threadsafe', | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 195 | '--enable-shared=no', | 
|  | 196 | '--enable-static=yes', | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 197 | '--disable-readline', | 
|  | 198 | '--disable-dependency-tracking', | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 199 | ] | 
|  | 200 | ), | 
|  | 201 | dict( | 
|  | 202 | name="NCurses 5.5", | 
|  | 203 | url="http://ftp.gnu.org/pub/gnu/ncurses/ncurses-5.5.tar.gz", | 
|  | 204 | checksum='e73c1ac10b4bfc46db43b2ddfd6244ef', | 
|  | 205 | configure_pre=[ | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 206 | "--enable-widec", | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 207 | "--without-cxx", | 
|  | 208 | "--without-ada", | 
|  | 209 | "--without-progs", | 
|  | 210 | "--without-curses-h", | 
|  | 211 | "--enable-shared", | 
|  | 212 | "--with-shared", | 
|  | 213 | "--datadir=/usr/share", | 
|  | 214 | "--sysconfdir=/etc", | 
|  | 215 | "--sharedstatedir=/usr/com", | 
|  | 216 | "--with-terminfo-dirs=/usr/share/terminfo", | 
|  | 217 | "--with-default-terminfo-dir=/usr/share/terminfo", | 
|  | 218 | "--libdir=/Library/Frameworks/Python.framework/Versions/%s/lib"%(getVersion(),), | 
|  | 219 | "--enable-termcap", | 
|  | 220 | ], | 
|  | 221 | patches=[ | 
|  | 222 | "ncurses-5.5.patch", | 
|  | 223 | ], | 
|  | 224 | useLDFlags=False, | 
|  | 225 | install='make && make install DESTDIR=%s && cd %s/usr/local/lib && ln -fs ../../../Library/Frameworks/Python.framework/Versions/%s/lib/lib* .'%( | 
|  | 226 | shellQuote(os.path.join(WORKDIR, 'libraries')), | 
|  | 227 | shellQuote(os.path.join(WORKDIR, 'libraries')), | 
|  | 228 | getVersion(), | 
|  | 229 | ), | 
|  | 230 | ), | 
|  | 231 | ]) | 
|  | 232 |  | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 233 | if not PYTHON_3: | 
|  | 234 | result.extend([ | 
|  | 235 | dict( | 
|  | 236 | name="Sleepycat DB 4.7.25", | 
|  | 237 | url="http://download.oracle.com/berkeley-db/db-4.7.25.tar.gz", | 
|  | 238 | checksum='ec2b87e833779681a0c3a814aa71359e', | 
|  | 239 | buildDir="build_unix", | 
|  | 240 | configure="../dist/configure", | 
|  | 241 | configure_pre=[ | 
|  | 242 | '--includedir=/usr/local/include/db4', | 
|  | 243 | ] | 
|  | 244 | ), | 
|  | 245 | ]) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 246 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 247 | return result | 
|  | 248 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 249 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 250 | # Instructions for building packages inside the .mpkg. | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 251 | def pkg_recipes(): | 
|  | 252 | unselected_for_python3 = ('selected', 'unselected')[PYTHON_3] | 
|  | 253 | result = [ | 
|  | 254 | dict( | 
|  | 255 | name="PythonFramework", | 
|  | 256 | long_name="Python Framework", | 
|  | 257 | source="/Library/Frameworks/Python.framework", | 
|  | 258 | readme="""\ | 
|  | 259 | This package installs Python.framework, that is the python | 
|  | 260 | interpreter and the standard library. This also includes Python | 
|  | 261 | wrappers for lots of Mac OS X API's. | 
|  | 262 | """, | 
|  | 263 | postflight="scripts/postflight.framework", | 
|  | 264 | selected='selected', | 
|  | 265 | ), | 
|  | 266 | dict( | 
|  | 267 | name="PythonApplications", | 
|  | 268 | long_name="GUI Applications", | 
|  | 269 | source="/Applications/Python %(VER)s", | 
|  | 270 | readme="""\ | 
|  | 271 | This package installs IDLE (an interactive Python IDE), | 
|  | 272 | Python Launcher and Build Applet (create application bundles | 
|  | 273 | from python scripts). | 
| Thomas Wouters | 73e5a5b | 2006-06-08 15:35:45 +0000 | [diff] [blame] | 274 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 275 | It also installs a number of examples and demos. | 
|  | 276 | """, | 
|  | 277 | required=False, | 
|  | 278 | selected='selected', | 
|  | 279 | ), | 
|  | 280 | dict( | 
|  | 281 | name="PythonUnixTools", | 
|  | 282 | long_name="UNIX command-line tools", | 
|  | 283 | source="/usr/local/bin", | 
|  | 284 | readme="""\ | 
|  | 285 | This package installs the unix tools in /usr/local/bin for | 
|  | 286 | compatibility with older releases of Python. This package | 
|  | 287 | is not necessary to use Python. | 
|  | 288 | """, | 
|  | 289 | required=False, | 
|  | 290 | selected='selected', | 
|  | 291 | ), | 
|  | 292 | dict( | 
|  | 293 | name="PythonDocumentation", | 
|  | 294 | long_name="Python Documentation", | 
|  | 295 | topdir="/Library/Frameworks/Python.framework/Versions/%(VER)s/Resources/English.lproj/Documentation", | 
|  | 296 | source="/pydocs", | 
|  | 297 | readme="""\ | 
|  | 298 | This package installs the python documentation at a location | 
|  | 299 | that is useable for pydoc and IDLE. If you have installed Xcode | 
|  | 300 | it will also install a link to the documentation in | 
|  | 301 | /Developer/Documentation/Python | 
|  | 302 | """, | 
|  | 303 | postflight="scripts/postflight.documentation", | 
|  | 304 | required=False, | 
|  | 305 | selected='selected', | 
|  | 306 | ), | 
|  | 307 | dict( | 
|  | 308 | name="PythonProfileChanges", | 
|  | 309 | long_name="Shell profile updater", | 
|  | 310 | readme="""\ | 
|  | 311 | This packages updates your shell profile to make sure that | 
|  | 312 | the Python tools are found by your shell in preference of | 
|  | 313 | the system provided Python tools. | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 314 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 315 | If you don't install this package you'll have to add | 
|  | 316 | "/Library/Frameworks/Python.framework/Versions/%(VER)s/bin" | 
|  | 317 | to your PATH by hand. | 
|  | 318 | """, | 
|  | 319 | postflight="scripts/postflight.patch-profile", | 
|  | 320 | topdir="/Library/Frameworks/Python.framework", | 
|  | 321 | source="/empty-dir", | 
|  | 322 | required=False, | 
|  | 323 | selected=unselected_for_python3, | 
|  | 324 | ), | 
|  | 325 | ] | 
|  | 326 |  | 
|  | 327 | if DEPTARGET < '10.4': | 
|  | 328 | result.append( | 
|  | 329 | dict( | 
|  | 330 | name="PythonSystemFixes", | 
|  | 331 | long_name="Fix system Python", | 
|  | 332 | readme="""\ | 
|  | 333 | This package updates the system python installation on | 
|  | 334 | Mac OS X 10.3 to ensure that you can build new python extensions | 
|  | 335 | using that copy of python after installing this version. | 
|  | 336 | """, | 
|  | 337 | postflight="../Tools/fixapplepython23.py", | 
|  | 338 | topdir="/Library/Frameworks/Python.framework", | 
|  | 339 | source="/empty-dir", | 
|  | 340 | required=False, | 
|  | 341 | selected=unselected_for_python3, | 
|  | 342 | ) | 
|  | 343 | ) | 
|  | 344 | return result | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 345 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 346 | def fatal(msg): | 
|  | 347 | """ | 
|  | 348 | A fatal error, bail out. | 
|  | 349 | """ | 
|  | 350 | sys.stderr.write('FATAL: ') | 
|  | 351 | sys.stderr.write(msg) | 
|  | 352 | sys.stderr.write('\n') | 
|  | 353 | sys.exit(1) | 
|  | 354 |  | 
|  | 355 | def fileContents(fn): | 
|  | 356 | """ | 
|  | 357 | Return the contents of the named file | 
|  | 358 | """ | 
|  | 359 | return open(fn, 'rb').read() | 
|  | 360 |  | 
|  | 361 | def runCommand(commandline): | 
|  | 362 | """ | 
|  | 363 | Run a command and raise RuntimeError if it fails. Output is surpressed | 
|  | 364 | unless the command fails. | 
|  | 365 | """ | 
|  | 366 | fd = os.popen(commandline, 'r') | 
|  | 367 | data = fd.read() | 
|  | 368 | xit = fd.close() | 
| Benjamin Peterson | 2a691a8 | 2008-03-31 01:51:45 +0000 | [diff] [blame] | 369 | if xit is not None: | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 370 | sys.stdout.write(data) | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 371 | raise RuntimeError, "command failed: %s"%(commandline,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 372 |  | 
|  | 373 | if VERBOSE: | 
|  | 374 | sys.stdout.write(data); sys.stdout.flush() | 
|  | 375 |  | 
|  | 376 | def captureCommand(commandline): | 
|  | 377 | fd = os.popen(commandline, 'r') | 
|  | 378 | data = fd.read() | 
|  | 379 | xit = fd.close() | 
| Benjamin Peterson | 2a691a8 | 2008-03-31 01:51:45 +0000 | [diff] [blame] | 380 | if xit is not None: | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 381 | sys.stdout.write(data) | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 382 | raise RuntimeError, "command failed: %s"%(commandline,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 383 |  | 
|  | 384 | return data | 
|  | 385 |  | 
| Ronald Oussoren | c45c3d9 | 2010-04-18 15:24:17 +0000 | [diff] [blame] | 386 | def getTclTkVersion(configfile, versionline): | 
|  | 387 | """ | 
|  | 388 | search Tcl or Tk configuration file for version line | 
|  | 389 | """ | 
|  | 390 | try: | 
|  | 391 | f = open(configfile, "r") | 
|  | 392 | except: | 
|  | 393 | fatal("Framework configuration file not found: %s" % configfile) | 
|  | 394 |  | 
|  | 395 | for l in f: | 
|  | 396 | if l.startswith(versionline): | 
|  | 397 | f.close() | 
|  | 398 | return l | 
|  | 399 |  | 
|  | 400 | fatal("Version variable %s not found in framework configuration file: %s" | 
|  | 401 | % (versionline, configfile)) | 
|  | 402 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 403 | def checkEnvironment(): | 
|  | 404 | """ | 
|  | 405 | Check that we're running on a supported system. | 
|  | 406 | """ | 
|  | 407 |  | 
|  | 408 | if platform.system() != 'Darwin': | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 409 | fatal("This script should be run on a Mac OS X 10.4 (or later) system") | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 410 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 411 | if int(platform.release().split('.')[0]) < 8: | 
|  | 412 | fatal("This script should be run on a Mac OS X 10.4 (or later) system") | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 413 |  | 
|  | 414 | if not os.path.exists(SDKPATH): | 
|  | 415 | fatal("Please install the latest version of Xcode and the %s SDK"%( | 
|  | 416 | os.path.basename(SDKPATH[:-4]))) | 
|  | 417 |  | 
| Ronald Oussoren | c45c3d9 | 2010-04-18 15:24:17 +0000 | [diff] [blame] | 418 | # Because we only support dynamic load of only one major/minor version of | 
|  | 419 | # Tcl/Tk, ensure: | 
|  | 420 | # 1. there are no user-installed frameworks of Tcl/Tk with version | 
|  | 421 | #       higher than the Apple-supplied system version | 
|  | 422 | # 2. there is a user-installed framework in /Library/Frameworks with the | 
|  | 423 | #       same version as the system version.  This allows users to choose | 
|  | 424 | #       to install a newer patch level. | 
|  | 425 |  | 
|  | 426 | for framework in ['Tcl', 'Tk']: | 
| Ronald Oussoren | 0499d0b | 2010-12-07 14:41:05 +0000 | [diff] [blame] | 427 | #fw = dict(lower=framework.lower(), | 
|  | 428 | #            upper=framework.upper(), | 
|  | 429 | #            cap=framework.capitalize()) | 
|  | 430 | #fwpth = "Library/Frameworks/%(cap)s.framework/%(lower)sConfig.sh" % fw | 
|  | 431 | fwpth = 'Library/Frameworks/Tcl.framework/Versions/Current' | 
|  | 432 | sysfw = os.path.join(SDKPATH, 'System', fwpth) | 
| Ronald Oussoren | c45c3d9 | 2010-04-18 15:24:17 +0000 | [diff] [blame] | 433 | libfw = os.path.join('/', fwpth) | 
|  | 434 | usrfw = os.path.join(os.getenv('HOME'), fwpth) | 
| Ronald Oussoren | 0499d0b | 2010-12-07 14:41:05 +0000 | [diff] [blame] | 435 | #version = "%(upper)s_VERSION" % fw | 
|  | 436 | if os.readlink(libfw) != os.readlink(sysfw): | 
| Ronald Oussoren | c45c3d9 | 2010-04-18 15:24:17 +0000 | [diff] [blame] | 437 | fatal("Version of %s must match %s" % (libfw, sysfw) ) | 
|  | 438 | if os.path.exists(usrfw): | 
|  | 439 | fatal("Please rename %s to avoid possible dynamic load issues." | 
|  | 440 | % usrfw) | 
|  | 441 |  | 
|  | 442 | # Remove inherited environment variables which might influence build | 
|  | 443 | environ_var_prefixes = ['CPATH', 'C_INCLUDE_', 'DYLD_', 'LANG', 'LC_', | 
|  | 444 | 'LD_', 'LIBRARY_', 'PATH', 'PYTHON'] | 
|  | 445 | for ev in list(os.environ): | 
|  | 446 | for prefix in environ_var_prefixes: | 
|  | 447 | if ev.startswith(prefix) : | 
|  | 448 | print "INFO: deleting environment variable %s=%s" % ( | 
|  | 449 | ev, os.environ[ev]) | 
|  | 450 | del os.environ[ev] | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 451 |  | 
| Ronald Oussoren | 1e99be7 | 2010-04-20 06:36:47 +0000 | [diff] [blame] | 452 | os.environ['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin' | 
|  | 453 | print "Setting default PATH: %s"%(os.environ['PATH']) | 
|  | 454 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 455 |  | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 456 | def parseOptions(args=None): | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 457 | """ | 
|  | 458 | Parse arguments and update global settings. | 
|  | 459 | """ | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 460 | global WORKDIR, DEPSRC, SDKPATH, SRCDIR, DEPTARGET | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 461 | global UNIVERSALOPTS, UNIVERSALARCHS, ARCHLIST, CC | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 462 |  | 
|  | 463 | if args is None: | 
|  | 464 | args = sys.argv[1:] | 
|  | 465 |  | 
|  | 466 | try: | 
|  | 467 | options, args = getopt.getopt(args, '?hb', | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 468 | [ 'build-dir=', 'third-party=', 'sdk-path=' , 'src-dir=', | 
|  | 469 | 'dep-target=', 'universal-archs=', 'help' ]) | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 470 | except getopt.error, msg: | 
|  | 471 | print msg | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 472 | sys.exit(1) | 
|  | 473 |  | 
|  | 474 | if args: | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 475 | print "Additional arguments" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 476 | sys.exit(1) | 
|  | 477 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 478 | deptarget = None | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 479 | for k, v in options: | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 480 | if k in ('-h', '-?', '--help'): | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 481 | print USAGE | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 482 | sys.exit(0) | 
|  | 483 |  | 
|  | 484 | elif k in ('-d', '--build-dir'): | 
|  | 485 | WORKDIR=v | 
|  | 486 |  | 
|  | 487 | elif k in ('--third-party',): | 
|  | 488 | DEPSRC=v | 
|  | 489 |  | 
|  | 490 | elif k in ('--sdk-path',): | 
|  | 491 | SDKPATH=v | 
|  | 492 |  | 
|  | 493 | elif k in ('--src-dir',): | 
|  | 494 | SRCDIR=v | 
|  | 495 |  | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 496 | elif k in ('--dep-target', ): | 
|  | 497 | DEPTARGET=v | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 498 | deptarget=v | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 499 |  | 
|  | 500 | elif k in ('--universal-archs', ): | 
|  | 501 | if v in UNIVERSALOPTS: | 
|  | 502 | UNIVERSALARCHS = v | 
|  | 503 | ARCHLIST = universal_opts_map[UNIVERSALARCHS] | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 504 | if deptarget is None: | 
|  | 505 | # Select alternate default deployment | 
|  | 506 | # target | 
|  | 507 | DEPTARGET = default_target_map.get(v, '10.3') | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 508 | else: | 
|  | 509 | raise NotImplementedError, v | 
|  | 510 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 511 | else: | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 512 | raise NotImplementedError, k | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 513 |  | 
|  | 514 | SRCDIR=os.path.abspath(SRCDIR) | 
|  | 515 | WORKDIR=os.path.abspath(WORKDIR) | 
|  | 516 | SDKPATH=os.path.abspath(SDKPATH) | 
|  | 517 | DEPSRC=os.path.abspath(DEPSRC) | 
|  | 518 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 519 | CC=target_cc_map[DEPTARGET] | 
|  | 520 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 521 | print "Settings:" | 
|  | 522 | print " * Source directory:", SRCDIR | 
|  | 523 | print " * Build directory: ", WORKDIR | 
|  | 524 | print " * SDK location:    ", SDKPATH | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 525 | print " * Third-party source:", DEPSRC | 
|  | 526 | print " * Deployment target:", DEPTARGET | 
|  | 527 | print " * Universal architectures:", ARCHLIST | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 528 | print " * C compiler:", CC | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 529 | print "" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 530 |  | 
|  | 531 |  | 
|  | 532 |  | 
|  | 533 |  | 
|  | 534 | def extractArchive(builddir, archiveName): | 
|  | 535 | """ | 
|  | 536 | Extract a source archive into 'builddir'. Returns the path of the | 
|  | 537 | extracted archive. | 
|  | 538 |  | 
|  | 539 | XXX: This function assumes that archives contain a toplevel directory | 
|  | 540 | that is has the same name as the basename of the archive. This is | 
|  | 541 | save enough for anything we use. | 
|  | 542 | """ | 
|  | 543 | curdir = os.getcwd() | 
|  | 544 | try: | 
|  | 545 | os.chdir(builddir) | 
|  | 546 | if archiveName.endswith('.tar.gz'): | 
|  | 547 | retval = os.path.basename(archiveName[:-7]) | 
|  | 548 | if os.path.exists(retval): | 
|  | 549 | shutil.rmtree(retval) | 
|  | 550 | fp = os.popen("tar zxf %s 2>&1"%(shellQuote(archiveName),), 'r') | 
|  | 551 |  | 
|  | 552 | elif archiveName.endswith('.tar.bz2'): | 
|  | 553 | retval = os.path.basename(archiveName[:-8]) | 
|  | 554 | if os.path.exists(retval): | 
|  | 555 | shutil.rmtree(retval) | 
|  | 556 | fp = os.popen("tar jxf %s 2>&1"%(shellQuote(archiveName),), 'r') | 
|  | 557 |  | 
|  | 558 | elif archiveName.endswith('.tar'): | 
|  | 559 | retval = os.path.basename(archiveName[:-4]) | 
|  | 560 | if os.path.exists(retval): | 
|  | 561 | shutil.rmtree(retval) | 
|  | 562 | fp = os.popen("tar xf %s 2>&1"%(shellQuote(archiveName),), 'r') | 
|  | 563 |  | 
|  | 564 | elif archiveName.endswith('.zip'): | 
|  | 565 | retval = os.path.basename(archiveName[:-4]) | 
|  | 566 | if os.path.exists(retval): | 
|  | 567 | shutil.rmtree(retval) | 
|  | 568 | fp = os.popen("unzip %s 2>&1"%(shellQuote(archiveName),), 'r') | 
|  | 569 |  | 
|  | 570 | data = fp.read() | 
|  | 571 | xit = fp.close() | 
|  | 572 | if xit is not None: | 
|  | 573 | sys.stdout.write(data) | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 574 | raise RuntimeError, "Cannot extract %s"%(archiveName,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 575 |  | 
|  | 576 | return os.path.join(builddir, retval) | 
|  | 577 |  | 
|  | 578 | finally: | 
|  | 579 | os.chdir(curdir) | 
|  | 580 |  | 
|  | 581 | KNOWNSIZES = { | 
|  | 582 | "http://ftp.gnu.org/pub/gnu/readline/readline-5.1.tar.gz": 7952742, | 
|  | 583 | "http://downloads.sleepycat.com/db-4.4.20.tar.gz": 2030276, | 
|  | 584 | } | 
|  | 585 |  | 
|  | 586 | def downloadURL(url, fname): | 
|  | 587 | """ | 
|  | 588 | Download the contents of the url into the file. | 
|  | 589 | """ | 
|  | 590 | try: | 
|  | 591 | size = os.path.getsize(fname) | 
|  | 592 | except OSError: | 
|  | 593 | pass | 
|  | 594 | else: | 
|  | 595 | if KNOWNSIZES.get(url) == size: | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 596 | print "Using existing file for", url | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 597 | return | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 598 | fpIn = urllib2.urlopen(url) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 599 | fpOut = open(fname, 'wb') | 
|  | 600 | block = fpIn.read(10240) | 
|  | 601 | try: | 
|  | 602 | while block: | 
|  | 603 | fpOut.write(block) | 
|  | 604 | block = fpIn.read(10240) | 
|  | 605 | fpIn.close() | 
|  | 606 | fpOut.close() | 
|  | 607 | except: | 
|  | 608 | try: | 
|  | 609 | os.unlink(fname) | 
|  | 610 | except: | 
|  | 611 | pass | 
|  | 612 |  | 
|  | 613 | def buildRecipe(recipe, basedir, archList): | 
|  | 614 | """ | 
|  | 615 | Build software using a recipe. This function does the | 
|  | 616 | 'configure;make;make install' dance for C software, with a possibility | 
|  | 617 | to customize this process, basically a poor-mans DarwinPorts. | 
|  | 618 | """ | 
|  | 619 | curdir = os.getcwd() | 
|  | 620 |  | 
|  | 621 | name = recipe['name'] | 
|  | 622 | url = recipe['url'] | 
|  | 623 | configure = recipe.get('configure', './configure') | 
|  | 624 | install = recipe.get('install', 'make && make install DESTDIR=%s'%( | 
|  | 625 | shellQuote(basedir))) | 
|  | 626 |  | 
|  | 627 | archiveName = os.path.split(url)[-1] | 
|  | 628 | sourceArchive = os.path.join(DEPSRC, archiveName) | 
|  | 629 |  | 
|  | 630 | if not os.path.exists(DEPSRC): | 
|  | 631 | os.mkdir(DEPSRC) | 
|  | 632 |  | 
|  | 633 |  | 
|  | 634 | if os.path.exists(sourceArchive): | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 635 | print "Using local copy of %s"%(name,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 636 |  | 
|  | 637 | else: | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 638 | print "Did not find local copy of %s"%(name,) | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 639 | print "Downloading %s"%(name,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 640 | downloadURL(url, sourceArchive) | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 641 | print "Archive for %s stored as %s"%(name, sourceArchive) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 642 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 643 | print "Extracting archive for %s"%(name,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 644 | buildDir=os.path.join(WORKDIR, '_bld') | 
|  | 645 | if not os.path.exists(buildDir): | 
|  | 646 | os.mkdir(buildDir) | 
|  | 647 |  | 
|  | 648 | workDir = extractArchive(buildDir, sourceArchive) | 
|  | 649 | os.chdir(workDir) | 
|  | 650 | if 'buildDir' in recipe: | 
|  | 651 | os.chdir(recipe['buildDir']) | 
|  | 652 |  | 
|  | 653 |  | 
|  | 654 | for fn in recipe.get('patches', ()): | 
|  | 655 | if fn.startswith('http://'): | 
|  | 656 | # Download the patch before applying it. | 
|  | 657 | path = os.path.join(DEPSRC, os.path.basename(fn)) | 
|  | 658 | downloadURL(fn, path) | 
|  | 659 | fn = path | 
|  | 660 |  | 
|  | 661 | fn = os.path.join(curdir, fn) | 
|  | 662 | runCommand('patch -p%s < %s'%(recipe.get('patchlevel', 1), | 
|  | 663 | shellQuote(fn),)) | 
|  | 664 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 665 | if configure is not None: | 
|  | 666 | configure_args = [ | 
|  | 667 | "--prefix=/usr/local", | 
|  | 668 | "--enable-static", | 
|  | 669 | "--disable-shared", | 
|  | 670 | #"CPP=gcc -arch %s -E"%(' -arch '.join(archList,),), | 
|  | 671 | ] | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 672 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 673 | if 'configure_pre' in recipe: | 
|  | 674 | args = list(recipe['configure_pre']) | 
|  | 675 | if '--disable-static' in args: | 
|  | 676 | configure_args.remove('--enable-static') | 
|  | 677 | if '--enable-shared' in args: | 
|  | 678 | configure_args.remove('--disable-shared') | 
|  | 679 | configure_args.extend(args) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 680 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 681 | if recipe.get('useLDFlags', 1): | 
|  | 682 | configure_args.extend([ | 
|  | 683 | "CFLAGS=-arch %s -isysroot %s -I%s/usr/local/include"%( | 
|  | 684 | ' -arch '.join(archList), | 
|  | 685 | shellQuote(SDKPATH)[1:-1], | 
|  | 686 | shellQuote(basedir)[1:-1],), | 
|  | 687 | "LDFLAGS=-syslibroot,%s -L%s/usr/local/lib -arch %s"%( | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 688 | shellQuote(SDKPATH)[1:-1], | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 689 | shellQuote(basedir)[1:-1], | 
|  | 690 | ' -arch '.join(archList)), | 
|  | 691 | ]) | 
|  | 692 | else: | 
|  | 693 | configure_args.extend([ | 
|  | 694 | "CFLAGS=-arch %s -isysroot %s -I%s/usr/local/include"%( | 
|  | 695 | ' -arch '.join(archList), | 
|  | 696 | shellQuote(SDKPATH)[1:-1], | 
|  | 697 | shellQuote(basedir)[1:-1],), | 
|  | 698 | ]) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 699 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 700 | if 'configure_post' in recipe: | 
|  | 701 | configure_args = configure_args = list(recipe['configure_post']) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 702 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 703 | configure_args.insert(0, configure) | 
|  | 704 | configure_args = [ shellQuote(a) for a in configure_args ] | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 705 |  | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 706 | if 'configure_env' in recipe: | 
|  | 707 | configure_args.insert(0, recipe['configure_env']) | 
|  | 708 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 709 | print "Running configure for %s"%(name,) | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 710 | runCommand(' '.join(configure_args) + ' 2>&1') | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 711 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 712 | print "Running install for %s"%(name,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 713 | runCommand('{ ' + install + ' ;} 2>&1') | 
|  | 714 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 715 | print "Done %s"%(name,) | 
|  | 716 | print "" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 717 |  | 
|  | 718 | os.chdir(curdir) | 
|  | 719 |  | 
|  | 720 | def buildLibraries(): | 
|  | 721 | """ | 
|  | 722 | Build our dependencies into $WORKDIR/libraries/usr/local | 
|  | 723 | """ | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 724 | print "" | 
|  | 725 | print "Building required libraries" | 
|  | 726 | print "" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 727 | universal = os.path.join(WORKDIR, 'libraries') | 
|  | 728 | os.mkdir(universal) | 
|  | 729 | os.makedirs(os.path.join(universal, 'usr', 'local', 'lib')) | 
|  | 730 | os.makedirs(os.path.join(universal, 'usr', 'local', 'include')) | 
|  | 731 |  | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 732 | for recipe in library_recipes(): | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 733 | buildRecipe(recipe, universal, ARCHLIST) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 734 |  | 
|  | 735 |  | 
|  | 736 |  | 
|  | 737 | def buildPythonDocs(): | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 738 | # This stores the documentation as Resources/English.lproj/Documentation | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 739 | # inside the framwork. pydoc and IDLE will pick it up there. | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 740 | print "Install python documentation" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 741 | rootDir = os.path.join(WORKDIR, '_root') | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 742 | buildDir = os.path.join('../../Doc') | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 743 | docdir = os.path.join(rootDir, 'pydocs') | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 744 | curDir = os.getcwd() | 
|  | 745 | os.chdir(buildDir) | 
|  | 746 | runCommand('make update') | 
| Martin v. Löwis | 6120ddb | 2010-04-22 13:16:44 +0000 | [diff] [blame] | 747 | runCommand("make html PYTHON='%s'" % os.path.abspath(sys.executable)) | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 748 | os.chdir(curDir) | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 749 | if not os.path.exists(docdir): | 
|  | 750 | os.mkdir(docdir) | 
| Ronald Oussoren | f84d7e9 | 2009-05-19 11:27:25 +0000 | [diff] [blame] | 751 | os.rename(os.path.join(buildDir, 'build', 'html'), docdir) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 752 |  | 
|  | 753 |  | 
|  | 754 | def buildPython(): | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 755 | print "Building a universal python for %s architectures" % UNIVERSALARCHS | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 756 |  | 
|  | 757 | buildDir = os.path.join(WORKDIR, '_bld', 'python') | 
|  | 758 | rootDir = os.path.join(WORKDIR, '_root') | 
|  | 759 |  | 
|  | 760 | if os.path.exists(buildDir): | 
|  | 761 | shutil.rmtree(buildDir) | 
|  | 762 | if os.path.exists(rootDir): | 
|  | 763 | shutil.rmtree(rootDir) | 
| Ned Deily | 4f7ff78 | 2011-01-15 05:29:12 +0000 | [diff] [blame^] | 764 | os.makedirs(buildDir) | 
|  | 765 | os.makedirs(rootDir) | 
|  | 766 | os.makedirs(os.path.join(rootDir, 'empty-dir')) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 767 | curdir = os.getcwd() | 
|  | 768 | os.chdir(buildDir) | 
|  | 769 |  | 
|  | 770 | # Not sure if this is still needed, the original build script | 
|  | 771 | # claims that parts of the install assume python.exe exists. | 
|  | 772 | os.symlink('python', os.path.join(buildDir, 'python.exe')) | 
|  | 773 |  | 
|  | 774 | # Extract the version from the configure file, needed to calculate | 
|  | 775 | # several paths. | 
|  | 776 | version = getVersion() | 
|  | 777 |  | 
| Ronald Oussoren | ac4b39f | 2009-03-30 20:05:35 +0000 | [diff] [blame] | 778 | # Since the extra libs are not in their installed framework location | 
|  | 779 | # during the build, augment the library path so that the interpreter | 
|  | 780 | # will find them during its extension import sanity checks. | 
|  | 781 | os.environ['DYLD_LIBRARY_PATH'] = os.path.join(WORKDIR, | 
|  | 782 | 'libraries', 'usr', 'local', 'lib') | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 783 | print "Running configure..." | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 784 | runCommand("%s -C --enable-framework --enable-universalsdk=%s " | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 785 | "--with-universal-archs=%s " | 
|  | 786 | "%s " | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 787 | "LDFLAGS='-g -L%s/libraries/usr/local/lib' " | 
|  | 788 | "OPT='-g -O3 -I%s/libraries/usr/local/include' 2>&1"%( | 
|  | 789 | shellQuote(os.path.join(SRCDIR, 'configure')), shellQuote(SDKPATH), | 
|  | 790 | UNIVERSALARCHS, | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 791 | (' ', '--with-computed-gotos ')[PYTHON_3], | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 792 | shellQuote(WORKDIR)[1:-1], | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 793 | shellQuote(WORKDIR)[1:-1])) | 
|  | 794 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 795 | print "Running make" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 796 | runCommand("make") | 
|  | 797 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 798 | print "Running make install" | 
| Ronald Oussoren | f84d7e9 | 2009-05-19 11:27:25 +0000 | [diff] [blame] | 799 | runCommand("make install DESTDIR=%s"%( | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 800 | shellQuote(rootDir))) | 
|  | 801 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 802 | print "Running make frameworkinstallextras" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 803 | runCommand("make frameworkinstallextras DESTDIR=%s"%( | 
|  | 804 | shellQuote(rootDir))) | 
|  | 805 |  | 
| Ronald Oussoren | ac4b39f | 2009-03-30 20:05:35 +0000 | [diff] [blame] | 806 | del os.environ['DYLD_LIBRARY_PATH'] | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 807 | print "Copying required shared libraries" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 808 | if os.path.exists(os.path.join(WORKDIR, 'libraries', 'Library')): | 
|  | 809 | runCommand("mv %s/* %s"%( | 
|  | 810 | shellQuote(os.path.join( | 
|  | 811 | WORKDIR, 'libraries', 'Library', 'Frameworks', | 
|  | 812 | 'Python.framework', 'Versions', getVersion(), | 
|  | 813 | 'lib')), | 
|  | 814 | shellQuote(os.path.join(WORKDIR, '_root', 'Library', 'Frameworks', | 
|  | 815 | 'Python.framework', 'Versions', getVersion(), | 
|  | 816 | 'lib')))) | 
|  | 817 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 818 | print "Fix file modes" | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 819 | frmDir = os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework') | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 820 | gid = grp.getgrnam('admin').gr_gid | 
|  | 821 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 822 | for dirpath, dirnames, filenames in os.walk(frmDir): | 
|  | 823 | for dn in dirnames: | 
|  | 824 | os.chmod(os.path.join(dirpath, dn), 0775) | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 825 | os.chown(os.path.join(dirpath, dn), -1, gid) | 
|  | 826 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 827 |  | 
|  | 828 | for fn in filenames: | 
|  | 829 | if os.path.islink(fn): | 
|  | 830 | continue | 
|  | 831 |  | 
|  | 832 | # "chmod g+w $fn" | 
|  | 833 | p = os.path.join(dirpath, fn) | 
|  | 834 | st = os.stat(p) | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 835 | os.chmod(p, stat.S_IMODE(st.st_mode) | stat.S_IWGRP) | 
|  | 836 | os.chown(p, -1, gid) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 837 |  | 
| Ronald Oussoren | 0499d0b | 2010-12-07 14:41:05 +0000 | [diff] [blame] | 838 | LDVERSION=None | 
|  | 839 | VERSION=None | 
|  | 840 | ABIFLAGS=None | 
|  | 841 |  | 
|  | 842 | with open(os.path.join(buildDir, 'Makefile')) as fp: | 
|  | 843 | for ln in fp: | 
|  | 844 | if ln.startswith('VERSION='): | 
|  | 845 | VERSION=ln.split()[1] | 
|  | 846 | if ln.startswith('ABIFLAGS='): | 
|  | 847 | ABIFLAGS=ln.split()[1] | 
|  | 848 |  | 
|  | 849 | if ln.startswith('LDVERSION='): | 
|  | 850 | LDVERSION=ln.split()[1] | 
|  | 851 |  | 
|  | 852 | LDVERSION = LDVERSION.replace('$(VERSION)', VERSION) | 
|  | 853 | LDVERSION = LDVERSION.replace('$(ABIFLAGS)', ABIFLAGS) | 
|  | 854 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 855 | # We added some directories to the search path during the configure | 
|  | 856 | # phase. Remove those because those directories won't be there on | 
|  | 857 | # the end-users system. | 
|  | 858 | path =os.path.join(rootDir, 'Library', 'Frameworks', 'Python.framework', | 
|  | 859 | 'Versions', version, 'lib', 'python%s'%(version,), | 
| Ronald Oussoren | 0499d0b | 2010-12-07 14:41:05 +0000 | [diff] [blame] | 860 | 'config-' + LDVERSION, 'Makefile') | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 861 | fp = open(path, 'r') | 
|  | 862 | data = fp.read() | 
|  | 863 | fp.close() | 
|  | 864 |  | 
|  | 865 | data = data.replace('-L%s/libraries/usr/local/lib'%(WORKDIR,), '') | 
|  | 866 | data = data.replace('-I%s/libraries/usr/local/include'%(WORKDIR,), '') | 
|  | 867 | fp = open(path, 'w') | 
|  | 868 | fp.write(data) | 
|  | 869 | fp.close() | 
|  | 870 |  | 
|  | 871 | # Add symlinks in /usr/local/bin, using relative links | 
|  | 872 | usr_local_bin = os.path.join(rootDir, 'usr', 'local', 'bin') | 
|  | 873 | to_framework = os.path.join('..', '..', '..', 'Library', 'Frameworks', | 
|  | 874 | 'Python.framework', 'Versions', version, 'bin') | 
|  | 875 | if os.path.exists(usr_local_bin): | 
|  | 876 | shutil.rmtree(usr_local_bin) | 
|  | 877 | os.makedirs(usr_local_bin) | 
|  | 878 | for fn in os.listdir( | 
|  | 879 | os.path.join(frmDir, 'Versions', version, 'bin')): | 
|  | 880 | os.symlink(os.path.join(to_framework, fn), | 
|  | 881 | os.path.join(usr_local_bin, fn)) | 
|  | 882 |  | 
|  | 883 | os.chdir(curdir) | 
|  | 884 |  | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 885 | if PYTHON_3: | 
|  | 886 | # Remove the 'Current' link, that way we don't accidently mess | 
|  | 887 | # with an already installed version of python 2 | 
|  | 888 | os.unlink(os.path.join(rootDir, 'Library', 'Frameworks', | 
|  | 889 | 'Python.framework', 'Versions', 'Current')) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 890 |  | 
|  | 891 | def patchFile(inPath, outPath): | 
|  | 892 | data = fileContents(inPath) | 
|  | 893 | data = data.replace('$FULL_VERSION', getFullVersion()) | 
|  | 894 | data = data.replace('$VERSION', getVersion()) | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 895 | data = data.replace('$MACOSX_DEPLOYMENT_TARGET', ''.join((DEPTARGET, ' or later'))) | 
| Ronald Oussoren | d010329 | 2010-10-20 12:56:56 +0000 | [diff] [blame] | 896 | data = data.replace('$ARCHITECTURES', ", ".join(universal_opts_map[UNIVERSALARCHS])) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 897 | data = data.replace('$INSTALL_SIZE', installSize()) | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 898 |  | 
|  | 899 | # This one is not handy as a template variable | 
|  | 900 | data = data.replace('$PYTHONFRAMEWORKINSTALLDIR', '/Library/Frameworks/Python.framework') | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 901 | fp = open(outPath, 'wb') | 
|  | 902 | fp.write(data) | 
|  | 903 | fp.close() | 
|  | 904 |  | 
|  | 905 | def patchScript(inPath, outPath): | 
|  | 906 | data = fileContents(inPath) | 
|  | 907 | data = data.replace('@PYVER@', getVersion()) | 
|  | 908 | fp = open(outPath, 'wb') | 
|  | 909 | fp.write(data) | 
|  | 910 | fp.close() | 
|  | 911 | os.chmod(outPath, 0755) | 
|  | 912 |  | 
|  | 913 |  | 
|  | 914 |  | 
|  | 915 | def packageFromRecipe(targetDir, recipe): | 
|  | 916 | curdir = os.getcwd() | 
|  | 917 | try: | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 918 | # The major version (such as 2.5) is included in the package name | 
|  | 919 | # because having two version of python installed at the same time is | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 920 | # common. | 
|  | 921 | pkgname = '%s-%s'%(recipe['name'], getVersion()) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 922 | srcdir  = recipe.get('source') | 
|  | 923 | pkgroot = recipe.get('topdir', srcdir) | 
|  | 924 | postflight = recipe.get('postflight') | 
|  | 925 | readme = textwrap.dedent(recipe['readme']) | 
|  | 926 | isRequired = recipe.get('required', True) | 
|  | 927 |  | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 928 | print "- building package %s"%(pkgname,) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 929 |  | 
|  | 930 | # Substitute some variables | 
|  | 931 | textvars = dict( | 
|  | 932 | VER=getVersion(), | 
|  | 933 | FULLVER=getFullVersion(), | 
|  | 934 | ) | 
|  | 935 | readme = readme % textvars | 
|  | 936 |  | 
|  | 937 | if pkgroot is not None: | 
|  | 938 | pkgroot = pkgroot % textvars | 
|  | 939 | else: | 
|  | 940 | pkgroot = '/' | 
|  | 941 |  | 
|  | 942 | if srcdir is not None: | 
|  | 943 | srcdir = os.path.join(WORKDIR, '_root', srcdir[1:]) | 
|  | 944 | srcdir = srcdir % textvars | 
|  | 945 |  | 
|  | 946 | if postflight is not None: | 
|  | 947 | postflight = os.path.abspath(postflight) | 
|  | 948 |  | 
|  | 949 | packageContents = os.path.join(targetDir, pkgname + '.pkg', 'Contents') | 
|  | 950 | os.makedirs(packageContents) | 
|  | 951 |  | 
|  | 952 | if srcdir is not None: | 
|  | 953 | os.chdir(srcdir) | 
|  | 954 | runCommand("pax -wf %s . 2>&1"%(shellQuote(os.path.join(packageContents, 'Archive.pax')),)) | 
|  | 955 | runCommand("gzip -9 %s 2>&1"%(shellQuote(os.path.join(packageContents, 'Archive.pax')),)) | 
|  | 956 | runCommand("mkbom . %s 2>&1"%(shellQuote(os.path.join(packageContents, 'Archive.bom')),)) | 
|  | 957 |  | 
|  | 958 | fn = os.path.join(packageContents, 'PkgInfo') | 
|  | 959 | fp = open(fn, 'w') | 
|  | 960 | fp.write('pmkrpkg1') | 
|  | 961 | fp.close() | 
|  | 962 |  | 
|  | 963 | rsrcDir = os.path.join(packageContents, "Resources") | 
|  | 964 | os.mkdir(rsrcDir) | 
|  | 965 | fp = open(os.path.join(rsrcDir, 'ReadMe.txt'), 'w') | 
|  | 966 | fp.write(readme) | 
|  | 967 | fp.close() | 
|  | 968 |  | 
|  | 969 | if postflight is not None: | 
|  | 970 | patchScript(postflight, os.path.join(rsrcDir, 'postflight')) | 
|  | 971 |  | 
|  | 972 | vers = getFullVersion() | 
|  | 973 | major, minor = map(int, getVersion().split('.', 2)) | 
|  | 974 | pl = Plist( | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 975 | CFBundleGetInfoString="Python.%s %s"%(pkgname, vers,), | 
|  | 976 | CFBundleIdentifier='org.python.Python.%s'%(pkgname,), | 
|  | 977 | CFBundleName='Python.%s'%(pkgname,), | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 978 | CFBundleShortVersionString=vers, | 
|  | 979 | IFMajorVersion=major, | 
|  | 980 | IFMinorVersion=minor, | 
|  | 981 | IFPkgFormatVersion=0.10000000149011612, | 
|  | 982 | IFPkgFlagAllowBackRev=False, | 
|  | 983 | IFPkgFlagAuthorizationAction="RootAuthorization", | 
|  | 984 | IFPkgFlagDefaultLocation=pkgroot, | 
|  | 985 | IFPkgFlagFollowLinks=True, | 
|  | 986 | IFPkgFlagInstallFat=True, | 
|  | 987 | IFPkgFlagIsRequired=isRequired, | 
|  | 988 | IFPkgFlagOverwritePermissions=False, | 
|  | 989 | IFPkgFlagRelocatable=False, | 
|  | 990 | IFPkgFlagRestartAction="NoRestart", | 
|  | 991 | IFPkgFlagRootVolumeOnly=True, | 
|  | 992 | IFPkgFlagUpdateInstalledLangauges=False, | 
|  | 993 | ) | 
|  | 994 | writePlist(pl, os.path.join(packageContents, 'Info.plist')) | 
|  | 995 |  | 
|  | 996 | pl = Plist( | 
|  | 997 | IFPkgDescriptionDescription=readme, | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 998 | IFPkgDescriptionTitle=recipe.get('long_name', "Python.%s"%(pkgname,)), | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 999 | IFPkgDescriptionVersion=vers, | 
|  | 1000 | ) | 
|  | 1001 | writePlist(pl, os.path.join(packageContents, 'Resources', 'Description.plist')) | 
|  | 1002 |  | 
|  | 1003 | finally: | 
|  | 1004 | os.chdir(curdir) | 
|  | 1005 |  | 
|  | 1006 |  | 
|  | 1007 | def makeMpkgPlist(path): | 
|  | 1008 |  | 
|  | 1009 | vers = getFullVersion() | 
|  | 1010 | major, minor = map(int, getVersion().split('.', 2)) | 
|  | 1011 |  | 
|  | 1012 | pl = Plist( | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 1013 | CFBundleGetInfoString="Python %s"%(vers,), | 
|  | 1014 | CFBundleIdentifier='org.python.Python', | 
|  | 1015 | CFBundleName='Python', | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1016 | CFBundleShortVersionString=vers, | 
|  | 1017 | IFMajorVersion=major, | 
|  | 1018 | IFMinorVersion=minor, | 
|  | 1019 | IFPkgFlagComponentDirectory="Contents/Packages", | 
|  | 1020 | IFPkgFlagPackageList=[ | 
|  | 1021 | dict( | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1022 | IFPkgFlagPackageLocation='%s-%s.pkg'%(item['name'], getVersion()), | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 1023 | IFPkgFlagPackageSelection=item.get('selected', 'selected'), | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1024 | ) | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 1025 | for item in pkg_recipes() | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1026 | ], | 
|  | 1027 | IFPkgFormatVersion=0.10000000149011612, | 
|  | 1028 | IFPkgFlagBackgroundScaling="proportional", | 
|  | 1029 | IFPkgFlagBackgroundAlignment="left", | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1030 | IFPkgFlagAuthorizationAction="RootAuthorization", | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1031 | ) | 
|  | 1032 |  | 
|  | 1033 | writePlist(pl, path) | 
|  | 1034 |  | 
|  | 1035 |  | 
|  | 1036 | def buildInstaller(): | 
|  | 1037 |  | 
|  | 1038 | # Zap all compiled files | 
|  | 1039 | for dirpath, _, filenames in os.walk(os.path.join(WORKDIR, '_root')): | 
|  | 1040 | for fn in filenames: | 
|  | 1041 | if fn.endswith('.pyc') or fn.endswith('.pyo'): | 
|  | 1042 | os.unlink(os.path.join(dirpath, fn)) | 
|  | 1043 |  | 
|  | 1044 | outdir = os.path.join(WORKDIR, 'installer') | 
|  | 1045 | if os.path.exists(outdir): | 
|  | 1046 | shutil.rmtree(outdir) | 
|  | 1047 | os.mkdir(outdir) | 
|  | 1048 |  | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 1049 | pkgroot = os.path.join(outdir, 'Python.mpkg', 'Contents') | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1050 | pkgcontents = os.path.join(pkgroot, 'Packages') | 
|  | 1051 | os.makedirs(pkgcontents) | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 1052 | for recipe in pkg_recipes(): | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1053 | packageFromRecipe(pkgcontents, recipe) | 
|  | 1054 |  | 
|  | 1055 | rsrcDir = os.path.join(pkgroot, 'Resources') | 
|  | 1056 |  | 
|  | 1057 | fn = os.path.join(pkgroot, 'PkgInfo') | 
|  | 1058 | fp = open(fn, 'w') | 
|  | 1059 | fp.write('pmkrpkg1') | 
|  | 1060 | fp.close() | 
|  | 1061 |  | 
|  | 1062 | os.mkdir(rsrcDir) | 
|  | 1063 |  | 
|  | 1064 | makeMpkgPlist(os.path.join(pkgroot, 'Info.plist')) | 
|  | 1065 | pl = Plist( | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 1066 | IFPkgDescriptionTitle="Python", | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1067 | IFPkgDescriptionVersion=getVersion(), | 
|  | 1068 | ) | 
|  | 1069 |  | 
|  | 1070 | writePlist(pl, os.path.join(pkgroot, 'Resources', 'Description.plist')) | 
|  | 1071 | for fn in os.listdir('resources'): | 
|  | 1072 | if fn == '.svn': continue | 
|  | 1073 | if fn.endswith('.jpg'): | 
|  | 1074 | shutil.copy(os.path.join('resources', fn), os.path.join(rsrcDir, fn)) | 
|  | 1075 | else: | 
|  | 1076 | patchFile(os.path.join('resources', fn), os.path.join(rsrcDir, fn)) | 
|  | 1077 |  | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1078 | shutil.copy("../../LICENSE", os.path.join(rsrcDir, 'License.txt')) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1079 |  | 
|  | 1080 |  | 
|  | 1081 | def installSize(clear=False, _saved=[]): | 
|  | 1082 | if clear: | 
|  | 1083 | del _saved[:] | 
|  | 1084 | if not _saved: | 
|  | 1085 | data = captureCommand("du -ks %s"%( | 
|  | 1086 | shellQuote(os.path.join(WORKDIR, '_root')))) | 
|  | 1087 | _saved.append("%d"%((0.5 + (int(data.split()[0]) / 1024.0)),)) | 
|  | 1088 | return _saved[0] | 
|  | 1089 |  | 
|  | 1090 |  | 
|  | 1091 | def buildDMG(): | 
|  | 1092 | """ | 
| Thomas Wouters | 89f507f | 2006-12-13 04:49:30 +0000 | [diff] [blame] | 1093 | Create DMG containing the rootDir. | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1094 | """ | 
|  | 1095 | outdir = os.path.join(WORKDIR, 'diskimage') | 
|  | 1096 | if os.path.exists(outdir): | 
|  | 1097 | shutil.rmtree(outdir) | 
|  | 1098 |  | 
|  | 1099 | imagepath = os.path.join(outdir, | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 1100 | 'python-%s-macosx%s'%(getFullVersion(),DEPTARGET)) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1101 | if INCLUDE_TIMESTAMP: | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 1102 | imagepath = imagepath + '-%04d-%02d-%02d'%(time.localtime()[:3]) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1103 | imagepath = imagepath + '.dmg' | 
|  | 1104 |  | 
|  | 1105 | os.mkdir(outdir) | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 1106 | volname='Python %s'%(getFullVersion()) | 
|  | 1107 | runCommand("hdiutil create -format UDRW -volname %s -srcfolder %s %s"%( | 
|  | 1108 | shellQuote(volname), | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1109 | shellQuote(os.path.join(WORKDIR, 'installer')), | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 1110 | shellQuote(imagepath + ".tmp.dmg" ))) | 
|  | 1111 |  | 
|  | 1112 |  | 
|  | 1113 | if not os.path.exists(os.path.join(WORKDIR, "mnt")): | 
|  | 1114 | os.mkdir(os.path.join(WORKDIR, "mnt")) | 
|  | 1115 | runCommand("hdiutil attach %s -mountroot %s"%( | 
|  | 1116 | shellQuote(imagepath + ".tmp.dmg"), shellQuote(os.path.join(WORKDIR, "mnt")))) | 
|  | 1117 |  | 
|  | 1118 | # Custom icon for the DMG, shown when the DMG is mounted. | 
|  | 1119 | shutil.copy("../Icons/Disk Image.icns", | 
|  | 1120 | os.path.join(WORKDIR, "mnt", volname, ".VolumeIcon.icns")) | 
|  | 1121 | runCommand("/Developer/Tools/SetFile -a C %s/"%( | 
|  | 1122 | shellQuote(os.path.join(WORKDIR, "mnt", volname)),)) | 
|  | 1123 |  | 
|  | 1124 | runCommand("hdiutil detach %s"%(shellQuote(os.path.join(WORKDIR, "mnt", volname)))) | 
|  | 1125 |  | 
|  | 1126 | setIcon(imagepath + ".tmp.dmg", "../Icons/Disk Image.icns") | 
|  | 1127 | runCommand("hdiutil convert %s -format UDZO -o %s"%( | 
|  | 1128 | shellQuote(imagepath + ".tmp.dmg"), shellQuote(imagepath))) | 
|  | 1129 | setIcon(imagepath, "../Icons/Disk Image.icns") | 
|  | 1130 |  | 
|  | 1131 | os.unlink(imagepath + ".tmp.dmg") | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1132 |  | 
|  | 1133 | return imagepath | 
|  | 1134 |  | 
|  | 1135 |  | 
|  | 1136 | def setIcon(filePath, icnsPath): | 
|  | 1137 | """ | 
|  | 1138 | Set the custom icon for the specified file or directory. | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1139 | """ | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1140 |  | 
| Ronald Oussoren | 7005067 | 2010-04-30 15:00:26 +0000 | [diff] [blame] | 1141 | dirPath = os.path.normpath(os.path.dirname(__file__)) | 
|  | 1142 | toolPath = os.path.join(dirPath, "seticon.app/Contents/MacOS/seticon") | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 1143 | if not os.path.exists(toolPath) or os.stat(toolPath).st_mtime < os.stat(dirPath + '/seticon.m').st_mtime: | 
|  | 1144 | # NOTE: The tool is created inside an .app bundle, otherwise it won't work due | 
|  | 1145 | # to connections to the window server. | 
| Ronald Oussoren | 7005067 | 2010-04-30 15:00:26 +0000 | [diff] [blame] | 1146 | appPath = os.path.join(dirPath, "seticon.app/Contents/MacOS") | 
|  | 1147 | if not os.path.exists(appPath): | 
|  | 1148 | os.makedirs(appPath) | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 1149 | runCommand("cc -o %s %s/seticon.m -framework Cocoa"%( | 
|  | 1150 | shellQuote(toolPath), shellQuote(dirPath))) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1151 |  | 
| Ronald Oussoren | 207b4c2 | 2009-03-30 17:20:30 +0000 | [diff] [blame] | 1152 | runCommand("%s %s %s"%(shellQuote(os.path.abspath(toolPath)), shellQuote(icnsPath), | 
|  | 1153 | shellQuote(filePath))) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1154 |  | 
|  | 1155 | def main(): | 
|  | 1156 | # First parse options and check if we can perform our work | 
|  | 1157 | parseOptions() | 
|  | 1158 | checkEnvironment() | 
|  | 1159 |  | 
| Ronald Oussoren | 1943f86 | 2009-03-30 19:39:14 +0000 | [diff] [blame] | 1160 | os.environ['MACOSX_DEPLOYMENT_TARGET'] = DEPTARGET | 
| Benjamin Peterson | d9b7d48 | 2010-03-19 21:42:45 +0000 | [diff] [blame] | 1161 | os.environ['CC'] = CC | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1162 |  | 
|  | 1163 | if os.path.exists(WORKDIR): | 
|  | 1164 | shutil.rmtree(WORKDIR) | 
|  | 1165 | os.mkdir(WORKDIR) | 
|  | 1166 |  | 
| Ronald Oussoren | c45c3d9 | 2010-04-18 15:24:17 +0000 | [diff] [blame] | 1167 | os.environ['LC_ALL'] = 'C' | 
|  | 1168 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1169 | # Then build third-party libraries such as sleepycat DB4. | 
|  | 1170 | buildLibraries() | 
|  | 1171 |  | 
|  | 1172 | # Now build python itself | 
|  | 1173 | buildPython() | 
| Ronald Oussoren | 6bf6367 | 2009-03-31 13:25:17 +0000 | [diff] [blame] | 1174 |  | 
|  | 1175 | # And then build the documentation | 
|  | 1176 | # Remove the Deployment Target from the shell | 
|  | 1177 | # environment, it's no longer needed and | 
|  | 1178 | # an unexpected build target can cause problems | 
|  | 1179 | # when Sphinx and its dependencies need to | 
|  | 1180 | # be (re-)installed. | 
|  | 1181 | del os.environ['MACOSX_DEPLOYMENT_TARGET'] | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1182 | buildPythonDocs() | 
| Ronald Oussoren | 6bf6367 | 2009-03-31 13:25:17 +0000 | [diff] [blame] | 1183 |  | 
|  | 1184 |  | 
|  | 1185 | # Prepare the applications folder | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1186 | fn = os.path.join(WORKDIR, "_root", "Applications", | 
| Benjamin Peterson | f10a79a | 2008-10-11 00:49:57 +0000 | [diff] [blame] | 1187 | "Python %s"%(getVersion(),), "Update Shell Profile.command") | 
| Ronald Oussoren | bc44866 | 2009-02-12 16:08:14 +0000 | [diff] [blame] | 1188 | patchScript("scripts/postflight.patch-profile",  fn) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1189 |  | 
| Benjamin Peterson | f10a79a | 2008-10-11 00:49:57 +0000 | [diff] [blame] | 1190 | folder = os.path.join(WORKDIR, "_root", "Applications", "Python %s"%( | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1191 | getVersion(),)) | 
|  | 1192 | os.chmod(folder, 0755) | 
|  | 1193 | setIcon(folder, "../Icons/Python Folder.icns") | 
|  | 1194 |  | 
|  | 1195 | # Create the installer | 
|  | 1196 | buildInstaller() | 
|  | 1197 |  | 
|  | 1198 | # And copy the readme into the directory containing the installer | 
|  | 1199 | patchFile('resources/ReadMe.txt', os.path.join(WORKDIR, 'installer', 'ReadMe.txt')) | 
|  | 1200 |  | 
|  | 1201 | # Ditto for the license file. | 
| Thomas Wouters | 0e3f591 | 2006-08-11 14:57:12 +0000 | [diff] [blame] | 1202 | shutil.copy('../../LICENSE', os.path.join(WORKDIR, 'installer', 'License.txt')) | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1203 |  | 
|  | 1204 | fp = open(os.path.join(WORKDIR, 'installer', 'Build.txt'), 'w') | 
| Benjamin Peterson | 623918e | 2008-12-20 22:50:25 +0000 | [diff] [blame] | 1205 | print >> fp, "# BUILD INFO" | 
|  | 1206 | print >> fp, "# Date:", time.ctime() | 
|  | 1207 | print >> fp, "# By:", pwd.getpwuid(os.getuid()).pw_gecos | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1208 | fp.close() | 
|  | 1209 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1210 | # And copy it to a DMG | 
|  | 1211 | buildDMG() | 
|  | 1212 |  | 
| Thomas Wouters | 477c8d5 | 2006-05-27 19:21:47 +0000 | [diff] [blame] | 1213 | if __name__ == "__main__": | 
|  | 1214 | main() |