mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	Update OS X installer build script to be Python 3 compatible.
Builds are not yet fully supported on Python 3 as some parts of the build process (like the documentation build chain) are still dependent on Python 2.
This commit is contained in:
		
							parent
							
								
									5b0eca116a
								
							
						
					
					
						commit
						7d9cf83f2f
					
				
					 1 changed files with 88 additions and 64 deletions
				
			
		|  | @ -1,4 +1,4 @@ | |||
| #!/usr/bin/python | ||||
| #!/usr/bin/env python | ||||
| """ | ||||
| This script is used to build "official" universal installers on Mac OS X. | ||||
| It requires at least Mac OS X 10.4, Xcode 2.2 and the 10.4u SDK for | ||||
|  | @ -12,16 +12,25 @@ | |||
| 
 | ||||
| Usage: see USAGE variable in the script. | ||||
| """ | ||||
| import platform, os, sys, getopt, textwrap, shutil, urllib2, stat, time, pwd | ||||
| import grp | ||||
| import platform, os, sys, getopt, textwrap, shutil, stat, time, pwd, grp | ||||
| try: | ||||
|     import urllib2 as urllib_request | ||||
| except ImportError: | ||||
|     import urllib.request as urllib_request | ||||
| 
 | ||||
| STAT_0o755 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | ||||
|              | stat.S_IRGRP |                stat.S_IXGRP | ||||
|              | stat.S_IROTH |                stat.S_IXOTH ) | ||||
| 
 | ||||
| STAT_0o775 = ( stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR | ||||
|              | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXGRP | ||||
|              | stat.S_IROTH |                stat.S_IXOTH ) | ||||
| 
 | ||||
| INCLUDE_TIMESTAMP = 1 | ||||
| VERBOSE = 1 | ||||
| 
 | ||||
| from plistlib import Plist | ||||
| 
 | ||||
| import MacOS | ||||
| 
 | ||||
| try: | ||||
|     from plistlib import writePlist | ||||
| except ImportError: | ||||
|  | @ -42,20 +51,35 @@ 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" | ||||
|  | @ -369,7 +393,7 @@ def fileContents(fn): | |||
|     """ | ||||
|     Return the contents of the named file | ||||
|     """ | ||||
|     return open(fn, 'rb').read() | ||||
|     return open(fn, 'r').read() | ||||
| 
 | ||||
| def runCommand(commandline): | ||||
|     """ | ||||
|  | @ -381,7 +405,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() | ||||
|  | @ -392,7 +416,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 | ||||
| 
 | ||||
|  | @ -461,12 +485,12 @@ def checkEnvironment(): | |||
|     for ev in list(os.environ): | ||||
|         for prefix in environ_var_prefixes: | ||||
|             if ev.startswith(prefix) : | ||||
|                 print "INFO: deleting environment variable %s=%s" % ( | ||||
|                                                     ev, os.environ[ev]) | ||||
|                 print("INFO: deleting environment variable %s=%s" % ( | ||||
|                                                     ev, os.environ[ev])) | ||||
|                 del os.environ[ev] | ||||
| 
 | ||||
|     os.environ['PATH'] = '/bin:/sbin:/usr/bin:/usr/sbin' | ||||
|     print "Setting default PATH: %s"%(os.environ['PATH']) | ||||
|     print("Setting default PATH: %s"%(os.environ['PATH'])) | ||||
| 
 | ||||
| 
 | ||||
| def parseOptions(args=None): | ||||
|  | @ -483,18 +507,18 @@ 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'): | ||||
|  | @ -522,10 +546,10 @@ 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) | ||||
|  | @ -534,15 +558,15 @@ def parseOptions(args=None): | |||
| 
 | ||||
|     CC=target_cc_map[DEPTARGET] | ||||
| 
 | ||||
|     print "Settings:" | ||||
|     print " * Source directory:", SRCDIR | ||||
|     print " * Build directory: ", WORKDIR | ||||
|     print " * SDK location:    ", SDKPATH | ||||
|     print " * Third-party source:", DEPSRC | ||||
|     print " * Deployment target:", DEPTARGET | ||||
|     print " * Universal architectures:", ARCHLIST | ||||
|     print " * C compiler:", CC | ||||
|     print "" | ||||
|     print("Settings:") | ||||
|     print(" * Source directory:", SRCDIR) | ||||
|     print(" * Build directory: ", WORKDIR) | ||||
|     print(" * SDK location:    ", SDKPATH) | ||||
|     print(" * Third-party source:", DEPSRC) | ||||
|     print(" * Deployment target:", DEPTARGET) | ||||
|     print(" * Universal architectures:", ARCHLIST) | ||||
|     print(" * C compiler:", CC) | ||||
|     print("") | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -587,7 +611,7 @@ 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) | ||||
| 
 | ||||
|  | @ -609,9 +633,9 @@ def downloadURL(url, fname): | |||
|         pass | ||||
|     else: | ||||
|         if KNOWNSIZES.get(url) == size: | ||||
|             print "Using existing file for", url | ||||
|             print("Using existing file for", url) | ||||
|             return | ||||
|     fpIn = urllib2.urlopen(url) | ||||
|     fpIn = urllib_request.urlopen(url) | ||||
|     fpOut = open(fname, 'wb') | ||||
|     block = fpIn.read(10240) | ||||
|     try: | ||||
|  | @ -648,15 +672,15 @@ def buildRecipe(recipe, basedir, archList): | |||
| 
 | ||||
| 
 | ||||
|     if os.path.exists(sourceArchive): | ||||
|         print "Using local copy of %s"%(name,) | ||||
|         print("Using local copy of %s"%(name,)) | ||||
| 
 | ||||
|     else: | ||||
|         print "Did not find local copy of %s"%(name,) | ||||
|         print "Downloading %s"%(name,) | ||||
|         print("Did not find local copy of %s"%(name,)) | ||||
|         print("Downloading %s"%(name,)) | ||||
|         downloadURL(url, sourceArchive) | ||||
|         print "Archive for %s stored as %s"%(name, sourceArchive) | ||||
|         print("Archive for %s stored as %s"%(name, sourceArchive)) | ||||
| 
 | ||||
|     print "Extracting archive for %s"%(name,) | ||||
|     print("Extracting archive for %s"%(name,)) | ||||
|     buildDir=os.path.join(WORKDIR, '_bld') | ||||
|     if not os.path.exists(buildDir): | ||||
|         os.mkdir(buildDir) | ||||
|  | @ -722,14 +746,14 @@ def buildRecipe(recipe, basedir, archList): | |||
|         if 'configure_env' in recipe: | ||||
|             configure_args.insert(0, recipe['configure_env']) | ||||
| 
 | ||||
|         print "Running configure for %s"%(name,) | ||||
|         print("Running configure for %s"%(name,)) | ||||
|         runCommand(' '.join(configure_args) + ' 2>&1') | ||||
| 
 | ||||
|     print "Running install for %s"%(name,) | ||||
|     print("Running install for %s"%(name,)) | ||||
|     runCommand('{ ' + install + ' ;} 2>&1') | ||||
| 
 | ||||
|     print "Done %s"%(name,) | ||||
|     print "" | ||||
|     print("Done %s"%(name,)) | ||||
|     print("") | ||||
| 
 | ||||
|     os.chdir(curdir) | ||||
| 
 | ||||
|  | @ -737,9 +761,9 @@ 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')) | ||||
|  | @ -753,7 +777,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') | ||||
|  | @ -768,7 +792,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') | ||||
|  | @ -796,7 +820,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 " | ||||
|  | @ -808,19 +832,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( | ||||
|  | @ -831,13 +855,13 @@ 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 | ||||
| 
 | ||||
|     for dirpath, dirnames, filenames in os.walk(frmDir): | ||||
|         for dn in dirnames: | ||||
|             os.chmod(os.path.join(dirpath, dn), 0775) | ||||
|             os.chmod(os.path.join(dirpath, dn), STAT_0o775) | ||||
|             os.chown(os.path.join(dirpath, dn), -1, gid) | ||||
| 
 | ||||
| 
 | ||||
|  | @ -918,17 +942,17 @@ 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) | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -945,7 +969,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( | ||||
|  | @ -990,7 +1014,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,), | ||||
|  | @ -1027,7 +1051,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,), | ||||
|  | @ -1209,7 +1233,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 | ||||
|  | @ -1222,9 +1246,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 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Ned Deily
						Ned Deily