mirror of
https://github.com/python/cpython.git
synced 2025-12-23 09:19:18 +00:00
merge heads
This commit is contained in:
commit
853ef47522
8 changed files with 224 additions and 291 deletions
|
|
@ -190,14 +190,15 @@ Directory and files operations
|
|||
handled by calling a handler specified by *onerror* or, if that is omitted,
|
||||
they raise an exception.
|
||||
|
||||
.. warning::
|
||||
.. note::
|
||||
|
||||
The default :func:`rmtree` function is susceptible to a symlink attack:
|
||||
given proper timing and circumstances, attackers can use it to delete
|
||||
files they wouldn't be able to access otherwise. Thus -- on platforms
|
||||
that support the necessary fd-based functions -- a safe version of
|
||||
:func:`rmtree` is used, which isn't vulnerable. In this case
|
||||
:data:`rmtree_is_safe` is set to True.
|
||||
On platforms that support the necessary fd-based functions a symlink
|
||||
attack resistant version of :func:`rmtree` is used by default. On other
|
||||
platforms, the :func:`rmtree` implementation is susceptible to a
|
||||
symlink attack: given proper timing and circumstances, attackers can
|
||||
manipulate symlinks on the filesystem to delete files they wouldn't
|
||||
be able to access otherwise. Applications can use the :data:`rmtree.avoids_symlink_attacks` function attribute to
|
||||
determine which case applies.
|
||||
|
||||
If *onerror* is provided, it must be a callable that accepts three
|
||||
parameters: *function*, *path*, and *excinfo*.
|
||||
|
|
@ -209,16 +210,16 @@ Directory and files operations
|
|||
:func:`sys.exc_info`. Exceptions raised by *onerror* will not be caught.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added a safe version that is used automatically if platform supports
|
||||
fd-based functions.
|
||||
Added a symlink attack resistant version that is used automatically
|
||||
if platform supports fd-based functions.
|
||||
|
||||
.. data:: rmtree_is_safe
|
||||
.. data:: rmtree.avoids_symlink_attacks
|
||||
|
||||
Indicates whether the current platform and implementation has a symlink
|
||||
attack-proof version of :func:`rmtree`. Currently this is only true for
|
||||
platforms supporting fd-based directory access functions.
|
||||
Indicates whether the current platform and implementation provides a
|
||||
symlink attack resistant version of :func:`rmtree`. Currently this is
|
||||
only true for platforms supporting fd-based directory access functions.
|
||||
|
||||
.. versionadded:: 3.3
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. function:: move(src, dst)
|
||||
|
||||
|
|
|
|||
|
|
@ -1296,6 +1296,11 @@ shutil
|
|||
acts on the symlink itself (or creates one, if relevant).
|
||||
(Contributed by Hynek Schlawack in :issue:`12715`.)
|
||||
|
||||
* :func:`~shutil.rmtree` is now resistant to symlink attacks on platforms
|
||||
which support the new ``dir_fd`` parameter in :func:`os.open` and
|
||||
:func:`os.unlinkat`. (Contributed by Martin von Löwis and Hynek Schlawack
|
||||
in :issue:`4489`.)
|
||||
|
||||
|
||||
|
||||
signal
|
||||
|
|
|
|||
|
|
@ -405,8 +405,9 @@ def _rmtree_safe_fd(topfd, path, onerror):
|
|||
except os.error:
|
||||
onerror(os.rmdir, path, sys.exc_info())
|
||||
|
||||
rmtree_is_safe = _use_fd_functions = (os.unlink in os.supports_dir_fd and
|
||||
os.open in os.supports_dir_fd)
|
||||
_use_fd_functions = (os.unlink in os.supports_dir_fd and
|
||||
os.open in os.supports_dir_fd)
|
||||
|
||||
def rmtree(path, ignore_errors=False, onerror=None):
|
||||
"""Recursively delete a directory tree.
|
||||
|
||||
|
|
@ -449,6 +450,9 @@ def rmtree(path, ignore_errors=False, onerror=None):
|
|||
else:
|
||||
return _rmtree_unsafe(path, onerror)
|
||||
|
||||
# Allow introspection of whether or not the hardening against symlink
|
||||
# attacks is supported on the current platform
|
||||
rmtree.avoids_symlink_attacks = _use_fd_functions
|
||||
|
||||
def _basename(path):
|
||||
# A basename() variant which first strips the trailing slash, if present.
|
||||
|
|
|
|||
|
|
@ -487,7 +487,7 @@ class TestShutil(unittest.TestCase):
|
|||
def test_rmtree_uses_safe_fd_version_if_available(self):
|
||||
if os.unlink in os.supports_dir_fd and os.open in os.supports_dir_fd:
|
||||
self.assertTrue(shutil._use_fd_functions)
|
||||
self.assertTrue(shutil.rmtree_is_safe)
|
||||
self.assertTrue(shutil.rmtree.avoids_symlink_attacks)
|
||||
tmp_dir = self.mkdtemp()
|
||||
d = os.path.join(tmp_dir, 'a')
|
||||
os.mkdir(d)
|
||||
|
|
@ -502,7 +502,7 @@ class TestShutil(unittest.TestCase):
|
|||
shutil._rmtree_safe_fd = real_rmtree
|
||||
else:
|
||||
self.assertFalse(shutil._use_fd_functions)
|
||||
self.assertFalse(shutil.rmtree_is_safe)
|
||||
self.assertFalse(shutil.rmtree.avoids_symlink_attacks)
|
||||
|
||||
def test_rmtree_dont_delete_file(self):
|
||||
# When called on a file instead of a directory, don't delete it.
|
||||
|
|
|
|||
|
|
@ -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 @@ Python 2.4.
|
|||
|
||||
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"
|
||||
|
|
@ -337,7 +361,7 @@ def pkg_recipes():
|
|||
),
|
||||
]
|
||||
|
||||
if DEPTARGET < '10.4':
|
||||
if DEPTARGET < '10.4' and not PYTHON_3:
|
||||
result.append(
|
||||
dict(
|
||||
name="PythonSystemFixes",
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -43,11 +43,10 @@ STRIPFLAG=-s
|
|||
CPMAC=/Developer/Tools/CpMac
|
||||
|
||||
APPTEMPLATE=$(srcdir)/Resources/app
|
||||
APPSUBDIRS=MacOS Resources
|
||||
APPSUBDIRS=MacOS Resources
|
||||
compileall=$(srcdir)/../Lib/compileall.py
|
||||
|
||||
installapps: install_Python install_pythonw install_PythonLauncher install_IDLE \
|
||||
checkapplepython
|
||||
installapps: install_Python install_pythonw install_PythonLauncher install_IDLE
|
||||
|
||||
install_pythonw: pythonw
|
||||
$(INSTALL_PROGRAM) $(STRIPFLAG) pythonw "$(DESTDIR)$(prefix)/bin/pythonw$(VERSION)"
|
||||
|
|
@ -196,14 +195,6 @@ installextras: $(srcdir)/Extras.install.py
|
|||
"$(DESTDIR)$(prefix)/share/doc/python$(VERSION)/examples/Tools" ; \
|
||||
chmod -R ugo+rX,go-w "$(DESTDIR)$(prefix)/share/doc/python$(VERSION)/examples/Tools"
|
||||
|
||||
|
||||
checkapplepython: $(srcdir)/Tools/fixapplepython23.py
|
||||
@if ! $(RUNSHARED) $(BUILDPYTHON) $(srcdir)/Tools/fixapplepython23.py -n; then \
|
||||
echo "* WARNING: Apple-installed Python 2.3 will have trouble building extensions from now on."; \
|
||||
echo "* WARNING: Run $(srcdir)/Tools/fixapplepython23.py with \"sudo\" to fix this."; \
|
||||
fi
|
||||
|
||||
|
||||
clean:
|
||||
rm pythonw
|
||||
cd PythonLauncher && make clean
|
||||
|
|
|
|||
171
Mac/README
171
Mac/README
|
|
@ -1,6 +1,13 @@
|
|||
============
|
||||
MacOSX Notes
|
||||
============
|
||||
=========================
|
||||
Python on Mac OS X README
|
||||
=========================
|
||||
|
||||
:Authors:
|
||||
Jack Jansen (2004-07),
|
||||
Ronald Oussoren (2010-04),
|
||||
Ned Deily (2012-06)
|
||||
|
||||
:Version: 3.3.0
|
||||
|
||||
This document provides a quick overview of some Mac OS X specific features in
|
||||
the Python distribution.
|
||||
|
|
@ -12,11 +19,11 @@ the Python distribution.
|
|||
_`Building and using a framework-based Python on Mac OS X` for more
|
||||
information on frameworks.
|
||||
|
||||
If the optional directory argument is specified the framework it installed
|
||||
If the optional directory argument is specified the framework is installed
|
||||
into that directory. This can be used to install a python framework into
|
||||
your home directory::
|
||||
|
||||
$ configure --enable-framework=/Users/ronald/Library/Frameworks
|
||||
$ ./configure --enable-framework=/Users/ronald/Library/Frameworks
|
||||
$ make && make install
|
||||
|
||||
This will install the framework itself in ``/Users/ronald/Library/Frameworks``,
|
||||
|
|
@ -33,9 +40,10 @@ the Python distribution.
|
|||
Create a universal binary build of of Python. This can be used with both
|
||||
regular and framework builds.
|
||||
|
||||
The optional argument specifies which OSX SDK should be used to perform the
|
||||
build. This defaults to ``/Developer/SDKs/MacOSX.10.4u.sdk``, specify
|
||||
``/`` when building on a 10.5 system, especially when building 64-bit code.
|
||||
The optional argument specifies which OS X SDK should be used to perform the
|
||||
build. If xcodebuild is available and configured, this defaults to
|
||||
the Xcode default MacOS X SDK, otherwise ``/Developer/SDKs/MacOSX.10.4u.sdk``
|
||||
if available or ``/`` if not.
|
||||
|
||||
See the section _`Building and using a universal binary of Python on Mac OS X`
|
||||
for more information.
|
||||
|
|
@ -43,7 +51,9 @@ the Python distribution.
|
|||
* ``--with-univeral-archs=VALUE``
|
||||
|
||||
Specify the kind of universal binary that should be created. This option is
|
||||
only valid when ``--enable-universalsdk`` is specified.
|
||||
only valid when ``--enable-universalsdk`` is specified. The default is
|
||||
``32-bit`` if a building with a SDK that supports PPC, otherwise defaults
|
||||
to ``intel``.
|
||||
|
||||
|
||||
Building and using a universal binary of Python on Mac OS X
|
||||
|
|
@ -52,9 +62,14 @@ Building and using a universal binary of Python on Mac OS X
|
|||
1. What is a universal binary
|
||||
-----------------------------
|
||||
|
||||
A universal binary build of Python contains object code for both PPC and i386
|
||||
and can therefore run at native speed on both classic powerpc based macs and
|
||||
the newer intel based macs.
|
||||
A universal binary build of Python contains object code for more than one
|
||||
CPU architecture. A universal OS X executable file or library combines the
|
||||
architecture-specific code into one file and can therefore run at native
|
||||
speed on all supported architectures. Universal files were introduced in
|
||||
OS X 10.4 to add support for Intel-based Macs to the existing PowerPC (PPC)
|
||||
machines. In OS X 10.5 support was extended to 64-bit Intel and 64-bit PPC
|
||||
architectures. It is possible to build Python with various combinations
|
||||
of architectures depending on the build tools and OS X version in use.
|
||||
|
||||
2. How do I build a universal binary
|
||||
------------------------------------
|
||||
|
|
@ -67,35 +82,52 @@ flag to configure::
|
|||
$ make install
|
||||
|
||||
This flag can be used with a framework build of python, but also with a classic
|
||||
unix build. Either way you will have to build python on Mac OS X 10.4 (or later)
|
||||
with Xcode 2.1 (or later). You also have to install the 10.4u SDK when
|
||||
installing Xcode.
|
||||
unix build. Universal builds were first supported with OS X 10.4 with Xcode 2.1
|
||||
and the 10.4u SDK. Starting with Xcode 3 and OS X 10.5, more configurations are
|
||||
available.
|
||||
|
||||
2.1 Flavours of universal binaries
|
||||
..................................
|
||||
2.1 Flavors of universal binaries
|
||||
.................................
|
||||
|
||||
It is possible to build a number of flavours of the universal binary build,
|
||||
the default is a 32-bit only binary (i386 and ppc). The flavour can be
|
||||
specified using the option ``--with-universal-archs=VALUE``. The following
|
||||
It is possible to build a number of flavors of the universal binary build,
|
||||
the default is a 32-bit only binary (i386 and ppc) in build environments that
|
||||
support ppc (10.4 with Xcode 2, 10.5 and 10.6 with Xcode 3) or an
|
||||
Intel-32/-64-bit binary (i386 and X86_64) in build environments that do not
|
||||
support ppc (Xcode 4 on 10.6 and later systems). The flavor can be specified
|
||||
using the configure option ``--with-universal-archs=VALUE``. The following
|
||||
values are available:
|
||||
|
||||
* ``intel``: ``i386``, ``x86_64``
|
||||
|
||||
* ``32-bit``: ``ppc``, ``i386``
|
||||
|
||||
* ``3-way``: ``i386``, ``x86_64``, ``ppc``
|
||||
|
||||
* ``64-bit``: ``ppc64``, ``x86_64``
|
||||
|
||||
* ``all``: ``ppc``, ``ppc64``, ``i386``, ``x86_64``
|
||||
|
||||
* ``3-way``: ``ppc``, ``i386`` and ``x86_64``
|
||||
|
||||
* ``intel``: ``i386``, ``x86_64``
|
||||
|
||||
To build a universal binary that includes a 64-bit architecture, you must build
|
||||
on a system running OSX 10.5 or later. The ``all`` flavour can only be built on
|
||||
OSX 10.5.
|
||||
on a system running OS X 10.5 or later. The ``all`` and ``64-bit`` flavors can
|
||||
only be built with an 10.5 SDK because ``ppc64`` support was only included with
|
||||
OS X 10.5. Although legacy ``ppc`` support was included with Xcode 3 on OS X
|
||||
10.6, it was removed in Xcode 4, versions of which were released on OS X 10.6
|
||||
and which is the current standard for OS X 10.7 and 10.8. To summarize, the
|
||||
following combinations of SDKs and universal-archs flavors are available:
|
||||
|
||||
The makefile for a framework build will install ``python32`` and ``pythonw32``
|
||||
binaries when the universal architecures includes at least one 32-bit architecture
|
||||
(that is, for all flavours but ``64-bit``).
|
||||
* 10.4u SDK with Xcode 2 supports ``32-bit`` only
|
||||
|
||||
* 10.5 SDK with Xcode 3.1.x supports all flavors
|
||||
|
||||
* 10.6 SDK with Xcode 3.2.x supports ``intel``, ``3-way``, and ``32-bit``
|
||||
|
||||
* 10.6 SDK with Xcode 4 supports ``intel`` only
|
||||
|
||||
* 10.7 and 10.8 SDKs with Xcode 4 support ``intel`` only
|
||||
|
||||
The makefile for a framework build will also install ``python3.3-32``
|
||||
binaries when the universal architecture includes at least one 32-bit
|
||||
architecture (that is, for all flavors but ``64-bit``).
|
||||
|
||||
Running a specific archicture
|
||||
.............................
|
||||
|
|
@ -122,17 +154,17 @@ Building and using a framework-based Python on Mac OS X.
|
|||
|
||||
The main reason is because you want to create GUI programs in Python. With the
|
||||
exception of X11/XDarwin-based GUI toolkits all GUI programs need to be run
|
||||
from a fullblown MacOSX application (a ".app" bundle).
|
||||
from a Mac OSX application bundle (".app").
|
||||
|
||||
While it is technically possible to create a .app without using frameworks you
|
||||
will have to do the work yourself if you really want this.
|
||||
|
||||
A second reason for using frameworks is that they put Python-related items in
|
||||
only two places: "/Library/Framework/Python.framework" and
|
||||
"/Applications/MacPython <VERSION>" where ``<VERSION>`` can be e.g. "2.6",
|
||||
"3.1", etc.. This simplifies matters for users installing
|
||||
"/Applications/Python <VERSION>" where ``<VERSION>`` can be e.g. "3.3",
|
||||
"2.7", etc. This simplifies matters for users installing
|
||||
Python from a binary distribution if they want to get rid of it again. Moreover,
|
||||
due to the way frameworks work a user without admin privileges can install a
|
||||
due to the way frameworks work, a user without admin privileges can install a
|
||||
binary distribution in his or her home directory without recompilation.
|
||||
|
||||
2. How does a framework Python differ from a normal static Python?
|
||||
|
|
@ -156,10 +188,10 @@ PyObjC.
|
|||
-------------------------------------
|
||||
|
||||
This directory contains a Makefile that will create a couple of python-related
|
||||
applications (fullblown OSX .app applications, that is) in
|
||||
"/Applications/MacPython <VERSION>", and a hidden helper application Python.app
|
||||
inside the Python.framework, and unix tools "python" and "pythonw" into
|
||||
/usr/local/bin. In addition it has a target "installmacsubtree" that installs
|
||||
applications (full-blown OSX .app applications, that is) in
|
||||
"/Applications/Python <VERSION>", and a hidden helper application Python.app
|
||||
inside the Python.framework, and unix tools "python" and "pythonw" into
|
||||
/usr/local/bin. In addition it has a target "installmacsubtree" that installs
|
||||
the relevant portions of the Mac subtree into the Python.framework.
|
||||
|
||||
It is normally invoked indirectly through the main Makefile, as the last step
|
||||
|
|
@ -171,17 +203,15 @@ in the sequence
|
|||
|
||||
3. make install
|
||||
|
||||
This sequence will put the framework in /Library/Framework/Python.framework,
|
||||
the applications in "/Applications/MacPython <VERSION>" and the unix tools in
|
||||
/usr/local/bin.
|
||||
This sequence will put the framework in ``/Library/Framework/Python.framework``,
|
||||
the applications in ``/Applications/Python <VERSION>`` and the unix tools in
|
||||
``/usr/local/bin``.
|
||||
|
||||
Installing in another place, for instance $HOME/Library/Frameworks if you have
|
||||
no admin privileges on your machine, has only been tested very lightly. This
|
||||
can be done by configuring with --enable-framework=$HOME/Library/Frameworks.
|
||||
The other two directories, "/Applications/MacPython-<VERSION>" and
|
||||
/usr/local/bin, will then also be deposited in $HOME. This is sub-optimal for
|
||||
the unix tools, which you would want in $HOME/bin, but there is no easy way to
|
||||
fix this right now.
|
||||
Installing in another place, for instance ``$HOME/Library/Frameworks`` if you
|
||||
have no admin privileges on your machine, is possible. This can be accomplished
|
||||
by configuring with ``--enable-framework=$HOME/Library/Frameworks``.
|
||||
The other two directories will then also be installed in your home directory,
|
||||
at ``$HOME/Applications/Python-<VERSION>`` and ``$HOME/bin``.
|
||||
|
||||
If you want to install some part, but not all, read the main Makefile. The
|
||||
frameworkinstall is composed of a couple of sub-targets that install the
|
||||
|
|
@ -189,7 +219,7 @@ framework itself, the Mac subtree, the applications and the unix tools.
|
|||
|
||||
There is an extra target frameworkinstallextras that is not part of the
|
||||
normal frameworkinstall which installs the Tools directory into
|
||||
"/Applications/MacPython <VERSION>", this is useful for binary
|
||||
"/Applications/Python <VERSION>", this is useful for binary
|
||||
distributions.
|
||||
|
||||
What do all these programs do?
|
||||
|
|
@ -202,24 +232,35 @@ debugger, etc.
|
|||
double-click a .py, .pyc or .pyw file. For the first two it creates a Terminal
|
||||
window and runs the scripts with the normal command-line Python. For the
|
||||
latter it runs the script in the Python.app interpreter so the script can do
|
||||
GUI-things. Keep the "alt" key depressed while dragging or double-clicking a
|
||||
script to set runtime options. These options can be set once and for all
|
||||
GUI-things. Keep the ``Option`` key depressed while dragging or double-clicking
|
||||
a script to set runtime options. These options can be set persistently
|
||||
through PythonLauncher's preferences dialog.
|
||||
|
||||
The commandline scripts /usr/local/bin/python and pythonw can be used to run
|
||||
non-GUI and GUI python scripts from the command line, respectively.
|
||||
The program ``pythonx.x`` runs python scripts from the command line. Various
|
||||
compatibility aliases are also installed, including ``pythonwx.x`` which
|
||||
in early releases of Python on OS X was required to run GUI programs. In
|
||||
current releases, the ``pythonx.x`` and ``pythonwx.x`` commands are identical.
|
||||
|
||||
How do I create a binary distribution?
|
||||
======================================
|
||||
|
||||
Go to the directory "Mac/OSX/BuildScript". There you'll find a script
|
||||
"build-installer.py" that does all the work. This will download and build
|
||||
Download and unpack the source release from http://www.python.org/download/.
|
||||
Go to the directory ``Mac/BuildScript``. There you will find a script
|
||||
``build-installer.py`` that does all the work. This will download and build
|
||||
a number of 3rd-party libaries, configures and builds a framework Python,
|
||||
installs it, creates the installer package files and then packs this in a
|
||||
DMG image.
|
||||
DMG image. The script also builds an HTML copy of the current Python
|
||||
documentation set for this release for inclusion in the framework. The
|
||||
installer package will create links to the documentation for use by IDLE,
|
||||
pydoc, shell users, and Finder user.
|
||||
|
||||
The script will build a universal binary, you'll therefore have to run this
|
||||
The script will build a universal binary so you'll therefore have to run this
|
||||
script on Mac OS X 10.4 or later and with Xcode 2.1 or later installed.
|
||||
However, the Python build process itself has several build dependencies not
|
||||
available out of the box with OS X 10.4 so you may have to install
|
||||
additional software beyond what is provided with Xcode 2. OS X 10.5
|
||||
provides a recent enough system Python (in ``/usr/bin``) to build
|
||||
the Python documentation set.
|
||||
|
||||
All of this is normally done completely isolated in /tmp/_py, so it does not
|
||||
use your normal build directory nor does it install into /.
|
||||
|
|
@ -253,7 +294,7 @@ Uninstalling a framework install, including the binary installer
|
|||
|
||||
Uninstalling a framework can be done by manually removing all bits that got installed.
|
||||
That's true for both installations from source and installations using the binary installer.
|
||||
Sadly enough OSX does not have a central uninstaller.
|
||||
OS X does not provide a central uninstaller.
|
||||
|
||||
The main bit of a framework install is the framework itself, installed in
|
||||
``/Library/Frameworks/Python.framework``. This can contain multiple versions
|
||||
|
|
@ -267,14 +308,12 @@ A framework install also installs some applications in ``/Applications/Python X.
|
|||
And lastly a framework installation installs files in ``/usr/local/bin``, all of
|
||||
them symbolic links to files in ``/Library/Frameworks/Python.framework/Versions/X.Y/bin``.
|
||||
|
||||
Odds and ends
|
||||
=============
|
||||
|
||||
Something to take note of is that the ".rsrc" files in the distribution are
|
||||
not actually resource files, they're AppleSingle encoded resource files. The
|
||||
macresource module and the Mac/OSX/Makefile cater for this, and create
|
||||
".rsrc.df.rsrc" files on the fly that are normal datafork-based resource
|
||||
files.
|
||||
Resources
|
||||
=========
|
||||
|
||||
Jack Jansen, Jack.Jansen@cwi.nl, 15-Jul-2004.
|
||||
Ronald Oussoren, RonaldOussoren@mac.com, 30-April-2010
|
||||
* http://www.python.org/download/mac/
|
||||
|
||||
* http://www.python.org/community/sigs/current/pythonmac-sig/
|
||||
|
||||
* http://docs.python.org/devguide/
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
#!/usr/bin/python
|
||||
"""fixapplepython23 - Fix Apple-installed Python 2.3 (on Mac OS X 10.3)
|
||||
|
||||
Python 2.3 (and 2.3.X for X<5) have the problem that building an extension
|
||||
for a framework installation may accidentally pick up the framework
|
||||
of a newer Python, in stead of the one that was used to build the extension.
|
||||
|
||||
This script modifies the Makefile (in .../lib/python2.3/config) to use
|
||||
the newer method of linking extensions with "-undefined dynamic_lookup"
|
||||
which fixes this problem.
|
||||
|
||||
The script will first check all prerequisites, and return a zero exit
|
||||
status also when nothing needs to be fixed.
|
||||
"""
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
|
||||
MAKEFILE='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/Makefile'
|
||||
CHANGES=((
|
||||
'LDSHARED=\t$(CC) $(LDFLAGS) -bundle -framework $(PYTHONFRAMEWORK)\n',
|
||||
'LDSHARED=\t$(CC) $(LDFLAGS) -bundle -undefined dynamic_lookup\n'
|
||||
),(
|
||||
'BLDSHARED=\t$(CC) $(LDFLAGS) -bundle -framework $(PYTHONFRAMEWORK)\n',
|
||||
'BLDSHARED=\t$(CC) $(LDFLAGS) -bundle -undefined dynamic_lookup\n'
|
||||
),(
|
||||
'CC=\t\tgcc\n',
|
||||
'CC=\t\t/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-gcc\n'
|
||||
),(
|
||||
'CXX=\t\tc++\n',
|
||||
'CXX=\t\t/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-g++\n'
|
||||
))
|
||||
|
||||
GCC_SCRIPT='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-gcc'
|
||||
GXX_SCRIPT='/System/Library/Frameworks/Python.framework/Versions/2.3/lib/python2.3/config/PantherPythonFix/run-g++'
|
||||
SCRIPT="""#!/bin/sh
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.3
|
||||
exec %s "${@}"
|
||||
"""
|
||||
|
||||
def findline(lines, start):
|
||||
"""return line starting with given string or -1"""
|
||||
for i in range(len(lines)):
|
||||
if lines[i][:len(start)] == start:
|
||||
return i
|
||||
return -1
|
||||
|
||||
def fix(makefile, do_apply):
|
||||
"""Fix the Makefile, if required."""
|
||||
fixed = False
|
||||
lines = open(makefile).readlines()
|
||||
|
||||
for old, new in CHANGES:
|
||||
i = findline(lines, new)
|
||||
if i >= 0:
|
||||
# Already fixed
|
||||
continue
|
||||
i = findline(lines, old)
|
||||
if i < 0:
|
||||
print('fixapplepython23: Python installation not fixed (appears broken)')
|
||||
print('fixapplepython23: missing line:', old)
|
||||
return 2
|
||||
lines[i] = new
|
||||
fixed = True
|
||||
|
||||
if fixed:
|
||||
if do_apply:
|
||||
print('fixapplepython23: Fix to Apple-installed Python 2.3 applied')
|
||||
os.rename(makefile, makefile + '~')
|
||||
open(makefile, 'w').writelines(lines)
|
||||
return 0
|
||||
else:
|
||||
print('fixapplepython23: Fix to Apple-installed Python 2.3 should be applied')
|
||||
return 1
|
||||
else:
|
||||
print('fixapplepython23: No fix needed, appears to have been applied before')
|
||||
return 0
|
||||
|
||||
def makescript(filename, compiler):
|
||||
"""Create a wrapper script for a compiler"""
|
||||
dirname = os.path.split(filename)[0]
|
||||
if not os.access(dirname, os.X_OK):
|
||||
os.mkdir(dirname, 0o755)
|
||||
fp = open(filename, 'w')
|
||||
fp.write(SCRIPT % compiler)
|
||||
fp.close()
|
||||
os.chmod(filename, 0o755)
|
||||
print('fixapplepython23: Created', filename)
|
||||
|
||||
def main():
|
||||
# Check for -n option
|
||||
if len(sys.argv) > 1 and sys.argv[1] == '-n':
|
||||
do_apply = False
|
||||
else:
|
||||
do_apply = True
|
||||
# First check OS version
|
||||
if sys.byteorder == 'little':
|
||||
# All intel macs are fine
|
||||
print("fixapplypython23: no fix is needed on MacOSX on Intel")
|
||||
sys.exit(0)
|
||||
|
||||
osver = platform.mac_ver()
|
||||
if osver != '10.3' and os.ver < '10.3.':
|
||||
print('fixapplepython23: no fix needed on MacOSX < 10.3')
|
||||
sys.exit(0)
|
||||
|
||||
if osver >= '10.4':
|
||||
print('fixapplepython23: no fix needed on MacOSX >= 10.4')
|
||||
sys.exit(0)
|
||||
|
||||
# Test that a framework Python is indeed installed
|
||||
if not os.path.exists(MAKEFILE):
|
||||
print('fixapplepython23: Python framework does not appear to be installed (?), nothing fixed')
|
||||
sys.exit(0)
|
||||
# Check that we can actually write the file
|
||||
if do_apply and not os.access(MAKEFILE, os.W_OK):
|
||||
print('fixapplepython23: No write permission, please run with "sudo"')
|
||||
sys.exit(2)
|
||||
# Create the shell scripts
|
||||
if do_apply:
|
||||
if not os.access(GCC_SCRIPT, os.X_OK):
|
||||
makescript(GCC_SCRIPT, "gcc")
|
||||
if not os.access(GXX_SCRIPT, os.X_OK):
|
||||
makescript(GXX_SCRIPT, "g++")
|
||||
# Finally fix the makefile
|
||||
rv = fix(MAKEFILE, do_apply)
|
||||
#sys.exit(rv)
|
||||
sys.exit(0)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Add table
Add a link
Reference in a new issue