diff --git a/Lib/distutils/sysconfig.py b/Lib/distutils/sysconfig.py --- a/Lib/distutils/sysconfig.py +++ b/Lib/distutils/sysconfig.py @@ -162,7 +162,7 @@ "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. @@ -178,27 +178,7 @@ 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 @@ -207,6 +187,7 @@ and ldshared.startswith(cc)): ldshared = newcc + ldshared[len(cc):] cc = newcc + if 'CXX' in os.environ: cxx = os.environ['CXX'] if 'LDSHARED' in os.environ: @@ -521,6 +502,16 @@ global _config_vars _config_vars = g +def _binary_on_path(binary): + if os.path.isabs(binary): + return os.path.exists(binary) + + else: + for dn in os.environ.get('PATH', '').split(':'): + fn = os.path.join(dn, binary) + if os.path.exists(fn): + return True + return False def get_config_vars(*args): """With no arguments, return a dictionary of all configuration @@ -564,6 +555,57 @@ 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. + # + # Futhermore, the compiler that can be used varies between + # Xcode releases. Upto Xcode 4 it was possible to '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. + cc = _config_vars['CC'] + if not _binary_on_path(cc): + # Compiler is not found on the shell search PATH + from subprocess import Popen, PIPE + + p= Popen(['/usr/bin/xcrun', '-find', 'clang'], + stdout=PIPE, stderr=PIPE) + data, _ = p.communicate() + p.wait() + + if p.returncode != 0: + raise DistutilsPlatformError( + "Cannot locate working compiler") + cc = data.strip() + cxx = cc + '++' + + _config_vars['CC'] = cc + _config_vars['CXX'] = cxx + + elif os.path.basename(cc).startswith('gcc'): + + # Compiler is GCC, check if it is LLVM-GCC + from distutils import log + from subprocess import Popen, PIPE + + p = Popen([cc, '--version'], stdout=PIPE, stderr=PIPE) + data, _ = p.communicate() + p.wait() + + if 'llvm-gcc' in data: + # Found LLVM-GCC, fall back to clang + p = Popen(['/usr/bin/xcrun', '-find', 'clang']) + data, _ = p.communicate() + p.wait() + + data = data.strip() + if _binary_on_path(data): + _config_vars['CC'] = data + _config_vars['CXX'] = data + '++' + 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,13 +621,41 @@ _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 automaticly removed '-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 prebuild + # 32-bit installer on the python.org website. + flags = _config_vars['CFLAGS'] + if re.search('-arch\s+ppc', flags) is not None: + from subprocess import Popen, PIPE + p = Popen([_config_vars['CC'], + '-arch', 'ppc', '-x', 'c', '/dev/null'], + stdout=PIPE, stderr=PIPE) + data, _ = p.communicate() + p.wait() + + if p.returncode != 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'): + + 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', diff --git a/configure.ac b/configure.ac --- a/configure.ac +++ b/configure.ac @@ -104,14 +104,20 @@ AC_MSG_CHECKING([for --enable-universalsdk]) AC_ARG_ENABLE(universalsdk, - AS_HELP_STRING([--enable-universalsdk@<:@=SDKDIR@:>@], [Build against Mac OS X 10.4u SDK (ppc/i386)]), + AS_HELP_STRING([--enable-universalsdk@<:@=SDKDIR@:>@], [Build fat binary against Mac OS X SDK]), [ case $enableval in yes) - enableval=/Developer/SDKs/MacOSX10.4u.sdk - if test ! -d "${enableval}" + # Locate the best usable SDK, see Mac/README.txt for more + # information + enableval="`/usr/bin/xcodebuild -version -sdk macosx Path 2>/dev/null`" + if test -z "${enableval}" then - enableval=/ + enableval=/Developer/SDKs/MacOSX10.4u.sdk + if test ! -d "${enableval}" + then + enableval=/ + fi fi ;; esac @@ -143,7 +149,20 @@ AC_SUBST(ARCH_RUN_32BIT) +# For backward compatibility reasons we prefer to select '32-bit' if available, +# otherwise use 'intel' UNIVERSAL_ARCHS="32-bit" +if test "`uname -s`" = "Darwin" +then + if test -n "${UNIVERSALSDK}" + then + if test -z "`/usr/bin/file "${UNIVERSALSDK}/usr/lib/libSystem.dylib" | grep ppc`" + then + UNIVERSAL_ARCHS="intel" + fi + fi +fi + AC_SUBST(LIPO_32BIT_FLAGS) AC_MSG_CHECKING(for --with-universal-archs) AC_ARG_WITH(universal-archs, @@ -153,7 +172,7 @@ UNIVERSAL_ARCHS="$withval" ], [ - AC_MSG_RESULT(32-bit) + AC_MSG_RESULT(${UNIVERSAL_ARCHS}) ]) @@ -501,6 +520,63 @@ if test -z "$CFLAGS"; then CFLAGS= fi + +if test "$ac_sys_system" = "Darwin" +then + # Compiler selection on MacOSX is more complicated than + # AC_PROG_CC can handle, see Mac/README.txt for more + # information + if test -z "${CC}" + then + found_gcc= + found_clang= + as_save_IFS=$IFS; IFS=: + for as_dir in $PATH + do + IFS=$as_save_IFS + if test -x $as_dir/gcc; then + if test -z "${found_gcc}"; then + found_gcc=$as_dir/gcc + fi + fi + if test -x $as_dir/clang; then + if test -z "${found_clang}"; then + found_clang=$as_dir/clang + fi + fi + done + IFS=$as_save_IFS + + if test -n "$found_gcc" -a -n "$found_clang" + then + if test -n "`"$found_gcc" --version | grep llvm-gcc`" + then + AC_MSG_NOTICE([Detected llvm-gcc, falling back to clang]) + CC="$found_clang" + CXX="$found_clang++" + fi + + + elif test -z "$found_gcc" -a -n "$found_clang" + then + AC_MSG_NOTICE([No GCC found, use CLANG]) + CC="$found_clang" + CXX="$found_clang++" + + elif test -z "$found_gcc" -a -z "$found_clang" + then + found_clang=`/usr/bin/xcrun -find clang 2>/dev/null` + if test -n "${found_clang}" + then + AC_MSG_NOTICE([Using clang from Xcode.app]) + CC="${found_clang}" + CXX="`/usr/bin/xcrun -find clang++`" + + # else: use default behaviour + fi + fi + fi +fi AC_PROG_CC AC_SUBST(CXX) @@ -534,6 +610,7 @@ case "$CC" in gcc) AC_PATH_PROG(CXX, [g++], [g++], [notfound]) ;; cc) AC_PATH_PROG(CXX, [c++], [c++], [notfound]) ;; + clang|*/clang) AC_PATH_PROG(CXX, [clang++], [clang++], [notfound]) ;; esac if test "$CXX" = "notfound" then