Skip to content

Commit cbfb9a5

Browse files
committed
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.
1 parent 88bc0d2 commit cbfb9a5

File tree

5 files changed

+493
-172
lines changed

5 files changed

+493
-172
lines changed

Lib/distutils/sysconfig.py

Lines changed: 114 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ def get_python_lib(plat_specific=0, standard_lib=0, prefix=None):
162162
"I don't know where Python installs its library "
163163
"on platform '%s'" % os.name)
164164

165-
_USE_CLANG = None
165+
166166

167167
def customize_compiler(compiler):
168168
"""Do any platform-specific customization of a CCompiler instance.
@@ -177,36 +177,7 @@ def customize_compiler(compiler):
177177

178178
newcc = None
179179
if 'CC' in os.environ:
180-
newcc = os.environ['CC']
181-
elif sys.platform == 'darwin' and cc == 'gcc-4.2':
182-
# Issue #13590:
183-
# Since Apple removed gcc-4.2 in Xcode 4.2, we can no
184-
# longer assume it is available for extension module builds.
185-
# If Python was built with gcc-4.2, check first to see if
186-
# it is available on this system; if not, try to use clang
187-
# instead unless the caller explicitly set CC.
188-
global _USE_CLANG
189-
if _USE_CLANG is None:
190-
from distutils import log
191-
from subprocess import Popen, PIPE
192-
p = Popen("! type gcc-4.2 && type clang && exit 2",
193-
shell=True, stdout=PIPE, stderr=PIPE)
194-
p.wait()
195-
if p.returncode == 2:
196-
_USE_CLANG = True
197-
log.warn("gcc-4.2 not found, using clang instead")
198-
else:
199-
_USE_CLANG = False
200-
if _USE_CLANG:
201-
newcc = 'clang'
202-
if newcc:
203-
# On OS X, if CC is overridden, use that as the default
204-
# command for LDSHARED as well
205-
if (sys.platform == 'darwin'
206-
and 'LDSHARED' not in os.environ
207-
and ldshared.startswith(cc)):
208-
ldshared = newcc + ldshared[len(cc):]
209-
cc = newcc
180+
cc = os.environ['CC']
210181
if 'CXX' in os.environ:
211182
cxx = os.environ['CXX']
212183
if 'LDSHARED' in os.environ:
@@ -522,6 +493,29 @@ def _init_os2():
522493
_config_vars = g
523494

524495

496+
def _read_output(commandstring):
497+
"""
498+
Returns os.popen(commandstring, "r").read(), but
499+
without actually using os.popen because that
500+
function is not usable during python bootstrap
501+
"""
502+
# NOTE: tempfile is also not useable during
503+
# bootstrap
504+
import contextlib
505+
try:
506+
import tempfile
507+
fp = tempfile.NamedTemporaryFile()
508+
except ImportError:
509+
fp = open("/tmp/distutils.%s"%(
510+
os.getpid(),), "w+b")
511+
512+
with contextlib.closing(fp) as fp:
513+
cmd = "%s >'%s'"%(commandstring, fp.name)
514+
os.system(cmd)
515+
data = fp.read()
516+
517+
return data.decode('utf-8')
518+
525519
def get_config_vars(*args):
526520
"""With no arguments, return a dictionary of all configuration
527521
variables relevant for the current platform. Generally this includes
@@ -561,9 +555,70 @@ def get_config_vars(*args):
561555
_config_vars['srcdir'] = os.path.normpath(srcdir)
562556

563557
if sys.platform == 'darwin':
558+
from distutils.spawn import find_executable
559+
564560
kernel_version = os.uname()[2] # Kernel version (8.4.3)
565561
major_version = int(kernel_version.split('.')[0])
566562

563+
# Issue #13590:
564+
# The OSX location for the compiler varies between OSX
565+
# (or rather Xcode) releases. With older releases (up-to 10.5)
566+
# the compiler is in /usr/bin, with newer releases the compiler
567+
# can only be found inside Xcode.app if the "Command Line Tools"
568+
# are not installed.
569+
#
570+
# Futhermore, the compiler that can be used varies between
571+
# Xcode releases. Upto Xcode 4 it was possible to use 'gcc-4.2'
572+
# as the compiler, after that 'clang' should be used because
573+
# gcc-4.2 is either not present, or a copy of 'llvm-gcc' that
574+
# miscompiles Python.
575+
576+
# skip checks if the compiler was overriden with a CC env variable
577+
if 'CC' not in os.environ:
578+
cc = oldcc = _config_vars['CC']
579+
if not find_executable(cc):
580+
# Compiler is not found on the shell search PATH.
581+
# Now search for clang, first on PATH (if the Command LIne
582+
# Tools have been installed in / or if the user has provided
583+
# another location via CC). If not found, try using xcrun
584+
# to find an uninstalled clang (within a selected Xcode).
585+
586+
# NOTE: Cannot use subprocess here because of bootstrap
587+
# issues when building Python itself (and os.popen is
588+
# implemented on top of subprocess and is therefore not
589+
# usable as well)
590+
591+
data = (find_executable('clang') or
592+
_read_output(
593+
"/usr/bin/xcrun -find clang 2>/dev/null").strip())
594+
if not data:
595+
raise DistutilsPlatformError(
596+
"Cannot locate working compiler")
597+
598+
_config_vars['CC'] = cc = data
599+
_config_vars['CXX'] = cc + '++'
600+
601+
elif os.path.basename(cc).startswith('gcc'):
602+
# Compiler is GCC, check if it is LLVM-GCC
603+
data = _read_output("'%s' --version 2>/dev/null"
604+
% (cc.replace("'", "'\"'\"'"),))
605+
if 'llvm-gcc' in data:
606+
# Found LLVM-GCC, fall back to clang
607+
data = (find_executable('clang') or
608+
_read_output(
609+
"/usr/bin/xcrun -find clang 2>/dev/null").strip())
610+
if find_executable(data):
611+
_config_vars['CC'] = cc = data
612+
_config_vars['CXX'] = cc + '++'
613+
614+
if (cc != oldcc
615+
and 'LDSHARED' in _config_vars
616+
and 'LDSHARED' not in os.environ):
617+
# modify LDSHARED if we modified CC
618+
ldshared = _config_vars['LDSHARED']
619+
if ldshared.startswith(oldcc):
620+
_config_vars['LDSHARED'] = cc + ldshared[len(oldcc):]
621+
567622
if major_version < 8:
568623
# On Mac OS X before 10.4, check if -arch and -isysroot
569624
# are in CFLAGS or LDFLAGS and remove them if they are.
@@ -579,19 +634,45 @@ def get_config_vars(*args):
579634
_config_vars[key] = flags
580635

581636
else:
637+
# Different Xcode releases support different sets for '-arch'
638+
# flags. In particular, Xcode 4.x no longer supports the
639+
# PPC architectures.
640+
#
641+
# This code automatically removes '-arch ppc' and '-arch ppc64'
642+
# when these are not supported. That makes it possible to
643+
# build extensions on OSX 10.7 and later with the prebuilt
644+
# 32-bit installer on the python.org website.
645+
flags = _config_vars['CFLAGS']
646+
if re.search('-arch\s+ppc', flags) is not None:
647+
# NOTE: Cannot use subprocess here because of bootstrap
648+
# issues when building Python itself
649+
status = os.system("'%s' -arch ppc -x c /dev/null 2>/dev/null"%(
650+
_config_vars['CC'].replace("'", "'\"'\"'"),))
651+
652+
if status != 0:
653+
# Compiler doesn't support PPC, remove the related
654+
# '-arch' flags.
655+
for key in ('LDFLAGS', 'BASECFLAGS',
656+
# a number of derived variables. These need to be
657+
# patched up as well.
658+
'CFLAGS', 'PY_CFLAGS', 'BLDSHARED', 'LDSHARED'):
659+
660+
flags = _config_vars[key]
661+
flags = re.sub('-arch\s+ppc\w*\s', ' ', flags)
662+
_config_vars[key] = flags
663+
582664

583665
# Allow the user to override the architecture flags using
584666
# an environment variable.
585667
# NOTE: This name was introduced by Apple in OSX 10.5 and
586668
# is used by several scripting languages distributed with
587669
# that OS release.
588-
589670
if 'ARCHFLAGS' in os.environ:
590671
arch = os.environ['ARCHFLAGS']
591672
for key in ('LDFLAGS', 'BASECFLAGS',
592673
# a number of derived variables. These need to be
593674
# patched up as well.
594-
'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'):
675+
'CFLAGS', 'PY_CFLAGS', 'BLDSHARED', 'LDSHARED'):
595676

596677
flags = _config_vars[key]
597678
flags = re.sub('-arch\s+\w+\s', ' ', flags)

Lib/distutils/unixccompiler.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,8 @@ def _darwin_compiler_fixup(compiler_so, cc_args):
8383
except ValueError:
8484
pass
8585

86-
# Check if the SDK that is used during compilation actually exists,
87-
# the universal build requires the usage of a universal SDK and not all
88-
# users have that installed by default.
86+
# Check if the SDK that is used during compilation actually exists.
87+
# If not, revert to using the installed headers and hope for the best.
8988
sysroot = None
9089
if '-isysroot' in cc_args:
9190
idx = cc_args.index('-isysroot')
@@ -97,7 +96,21 @@ def _darwin_compiler_fixup(compiler_so, cc_args):
9796
if sysroot and not os.path.isdir(sysroot):
9897
log.warn("Compiling with an SDK that doesn't seem to exist: %s",
9998
sysroot)
100-
log.warn("Please check your Xcode installation")
99+
log.warn("Attempting to compile without the SDK")
100+
while True:
101+
try:
102+
index = cc_args.index('-isysroot')
103+
# Strip this argument and the next one:
104+
del cc_args[index:index+2]
105+
except ValueError:
106+
break
107+
while True:
108+
try:
109+
index = compiler_so.index('-isysroot')
110+
# Strip this argument and the next one:
111+
del compiler_so[index:index+2]
112+
except ValueError:
113+
break
101114

102115
return compiler_so
103116

Misc/NEWS

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,21 @@ Tests
234234
Build
235235
-----
236236

237+
- Issue #13590: Improve support for OS X Xcode 4:
238+
* Try to avoid building Python or extension modules with problematic
239+
llvm-gcc compiler.
240+
* Since Xcode 4 removes ppc support, extension module builds now
241+
check for ppc compiler support and automatically remove ppc and
242+
ppc64 archs when not available.
243+
* Since Xcode 4 no longer install SDKs in default locations,
244+
extension module builds now revert to using installed headers
245+
and libs if the SDK used to build the interpreter is not
246+
available.
247+
* Update ./configure to use better defaults for universal builds;
248+
in particular, --enable-universalsdk=yes uses the Xcode default
249+
SDK and --with-universal-archs now defaults to "intel" if ppc
250+
not available.
251+
237252
- Issue #14225: Fix Unicode support for curses (#12567) on OS X
238253

239254
- Issue #14928: Fix importlib bootstrap issues by using a custom executable

0 commit comments

Comments
 (0)