diff options
author | Ned Deily <nad@acm.org> | 2012-06-23 16:02:19 -0700 |
---|---|---|
committer | Ned Deily <nad@acm.org> | 2012-06-23 16:02:19 -0700 |
commit | 07020e7ceee1fc8cd6bd07901839f4c39e77b226 (patch) | |
tree | 640027984b8a78649e45ef902a50a9385b0ec52e /Lib/distutils/sysconfig.py | |
parent | 350ce0ff79836330ca167da28e618027769da9c9 (diff) | |
download | cpython-07020e7ceee1fc8cd6bd07901839f4c39e77b226.tar.gz |
Issue #13590: Improve support for OS X Xcode 4:
- Try to avoid building Python or extension modules with problematic
llvm-gcc compiler.
- Since Xcode 4 removes ppc support, extension module builds now
check for ppc compiler support and automatically remove ppc and
ppc64 archs when not available.
- Since Xcode 4 no longer install SDKs in default locations,
extension module builds now revert to using installed headers
and libs if the SDK used to build the interpreter is not
available.
- Update ./configure to use better defaults for universal builds;
in particular, --enable-universalsdk=yes uses the Xcode default
SDK and --with-universal-archs now defaults to "intel" if ppc
not available.
Diffstat (limited to 'Lib/distutils/sysconfig.py')
-rw-r--r-- | Lib/distutils/sysconfig.py | 147 |
1 files changed, 114 insertions, 33 deletions
diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py index e86cb23236..dac3035f1b 100644 --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -162,7 +162,7 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None): "I don't know where Python installs its library " "on platform '%s'" % os.name) -_USE_CLANG = None + def customize_compiler(compiler): """Do any platform-specific customization of a CCompiler instance. @@ -177,36 +177,7 @@ def customize_compiler(compiler): newcc = None if 'CC' in os.environ: - newcc = os.environ['CC'] - elif sys.platform == 'darwin' and cc == 'gcc-4.2': - # Issue #13590: - # Since Apple removed gcc-4.2 in Xcode 4.2, we can no - # longer assume it is available for extension module builds. - # If Python was built with gcc-4.2, check first to see if - # it is available on this system; if not, try to use clang - # instead unless the caller explicitly set CC. - global _USE_CLANG - if _USE_CLANG is None: - from distutils import log - from subprocess import Popen, PIPE - p = Popen("! type gcc-4.2 && type clang && exit 2", - shell=True, stdout=PIPE, stderr=PIPE) - p.wait() - if p.returncode == 2: - _USE_CLANG = True - log.warn("gcc-4.2 not found, using clang instead") - else: - _USE_CLANG = False - if _USE_CLANG: - newcc = 'clang' - if newcc: - # On OS X, if CC is overridden, use that as the default - # command for LDSHARED as well - if (sys.platform == 'darwin' - and 'LDSHARED' not in os.environ - and ldshared.startswith(cc)): - ldshared = newcc + ldshared[len(cc):] - cc = newcc + cc = os.environ['CC'] if 'CXX' in os.environ: cxx = os.environ['CXX'] if 'LDSHARED' in os.environ: @@ -522,6 +493,29 @@ def _init_os2(): _config_vars = g +def _read_output(commandstring): + """ + Returns os.popen(commandstring, "r").read(), but + without actually using os.popen because that + function is not usable during python bootstrap + """ + # NOTE: tempfile is also not useable during + # bootstrap + import contextlib + try: + import tempfile + fp = tempfile.NamedTemporaryFile() + except ImportError: + fp = open("/tmp/distutils.%s"%( + os.getpid(),), "w+b") + + with contextlib.closing(fp) as fp: + cmd = "%s >'%s'"%(commandstring, fp.name) + os.system(cmd) + data = fp.read() + + return data.decode('utf-8') + def get_config_vars(*args): """With no arguments, return a dictionary of all configuration variables relevant for the current platform. Generally this includes @@ -561,9 +555,70 @@ def get_config_vars(*args): _config_vars['srcdir'] = os.path.normpath(srcdir) if sys.platform == 'darwin': + from distutils.spawn import find_executable + kernel_version = os.uname()[2] # Kernel version (8.4.3) major_version = int(kernel_version.split('.')[0]) + # Issue #13590: + # The OSX location for the compiler varies between OSX + # (or rather Xcode) releases. With older releases (up-to 10.5) + # the compiler is in /usr/bin, with newer releases the compiler + # can only be found inside Xcode.app if the "Command Line Tools" + # are not installed. + # + # Futhermore, the compiler that can be used varies between + # Xcode releases. Upto Xcode 4 it was possible to use 'gcc-4.2' + # as the compiler, after that 'clang' should be used because + # gcc-4.2 is either not present, or a copy of 'llvm-gcc' that + # miscompiles Python. + + # skip checks if the compiler was overriden with a CC env variable + if 'CC' not in os.environ: + cc = oldcc = _config_vars['CC'] + if not find_executable(cc): + # Compiler is not found on the shell search PATH. + # Now search for clang, first on PATH (if the Command LIne + # Tools have been installed in / or if the user has provided + # another location via CC). If not found, try using xcrun + # to find an uninstalled clang (within a selected Xcode). + + # NOTE: Cannot use subprocess here because of bootstrap + # issues when building Python itself (and os.popen is + # implemented on top of subprocess and is therefore not + # usable as well) + + data = (find_executable('clang') or + _read_output( + "/usr/bin/xcrun -find clang 2>/dev/null").strip()) + if not data: + raise DistutilsPlatformError( + "Cannot locate working compiler") + + _config_vars['CC'] = cc = data + _config_vars['CXX'] = cc + '++' + + elif os.path.basename(cc).startswith('gcc'): + # Compiler is GCC, check if it is LLVM-GCC + data = _read_output("'%s' --version 2>/dev/null" + % (cc.replace("'", "'\"'\"'"),)) + if 'llvm-gcc' in data: + # Found LLVM-GCC, fall back to clang + data = (find_executable('clang') or + _read_output( + "/usr/bin/xcrun -find clang 2>/dev/null").strip()) + if find_executable(data): + _config_vars['CC'] = cc = data + _config_vars['CXX'] = cc + '++' + + if (cc != oldcc + and 'LDSHARED' in _config_vars + and 'LDSHARED' not in os.environ): + # modify LDSHARED if we modified CC + ldshared = _config_vars['LDSHARED'] + if ldshared.startswith(oldcc): + _config_vars['LDSHARED'] = cc + ldshared[len(oldcc):] + if major_version < 8: # On Mac OS X before 10.4, check if -arch and -isysroot # are in CFLAGS or LDFLAGS and remove them if they are. @@ -579,19 +634,45 @@ def get_config_vars(*args): _config_vars[key] = flags else: + # Different Xcode releases support different sets for '-arch' + # flags. In particular, Xcode 4.x no longer supports the + # PPC architectures. + # + # This code automatically removes '-arch ppc' and '-arch ppc64' + # when these are not supported. That makes it possible to + # build extensions on OSX 10.7 and later with the prebuilt + # 32-bit installer on the python.org website. + flags = _config_vars['CFLAGS'] + if re.search('-arch\s+ppc', flags) is not None: + # NOTE: Cannot use subprocess here because of bootstrap + # issues when building Python itself + status = os.system("'%s' -arch ppc -x c /dev/null 2>/dev/null"%( + _config_vars['CC'].replace("'", "'\"'\"'"),)) + + if status != 0: + # Compiler doesn't support PPC, remove the related + # '-arch' flags. + for key in ('LDFLAGS', 'BASECFLAGS', + # a number of derived variables. These need to be + # patched up as well. + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED', 'LDSHARED'): + + flags = _config_vars[key] + flags = re.sub('-arch\s+ppc\w*\s', ' ', flags) + _config_vars[key] = flags + # Allow the user to override the architecture flags using # an environment variable. # NOTE: This name was introduced by Apple in OSX 10.5 and # is used by several scripting languages distributed with # that OS release. - if 'ARCHFLAGS' in os.environ: arch = os.environ['ARCHFLAGS'] for key in ('LDFLAGS', 'BASECFLAGS', # a number of derived variables. These need to be # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): + 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED', 'LDSHARED'): flags = _config_vars[key] flags = re.sub('-arch\s+\w+\s', ' ', flags) |