@@ -52,7 +52,7 @@ def _find_executable(executable, path=None):
5252 return executable
5353
5454
55- def _read_output (commandstring ):
55+ def _read_output (commandstring , capture_stderr = False ):
5656 """Output from successful command execution or None"""
5757 # Similar to os.popen(commandstring, "r").read(),
5858 # but without actually using os.popen because that
@@ -67,7 +67,10 @@ def _read_output(commandstring):
6767 os .getpid (),), "w+b" )
6868
6969 with contextlib .closing (fp ) as fp :
70- cmd = "%s 2>/dev/null >'%s'" % (commandstring , fp .name )
70+ if capture_stderr :
71+ cmd = "%s >'%s' 2>&1" % (commandstring , fp .name )
72+ else :
73+ cmd = "%s 2>/dev/null >'%s'" % (commandstring , fp .name )
7174 return fp .read ().decode ('utf-8' ).strip () if not os .system (cmd ) else None
7275
7376
@@ -93,7 +96,7 @@ def _get_system_version():
9396 if _SYSTEM_VERSION is None :
9497 _SYSTEM_VERSION = ''
9598 try :
96- f = open ('/System/Library/CoreServices/SystemVersion.plist' )
99+ f = open ('/System/Library/CoreServices/SystemVersion.plist' , encoding = "utf-8" )
97100 except OSError :
98101 # We're on a plain darwin box, fall back to the default
99102 # behaviour.
@@ -110,6 +113,26 @@ def _get_system_version():
110113
111114 return _SYSTEM_VERSION
112115
116+ _SYSTEM_VERSION_TUPLE = None
117+ def _get_system_version_tuple ():
118+ """
119+ Return the macOS system version as a tuple
120+
121+ The return value is safe to use to compare
122+ two version numbers.
123+ """
124+ global _SYSTEM_VERSION_TUPLE
125+ if _SYSTEM_VERSION_TUPLE is None :
126+ osx_version = _get_system_version ()
127+ if osx_version :
128+ try :
129+ _SYSTEM_VERSION_TUPLE = tuple (int (i ) for i in osx_version .split ('.' ))
130+ except ValueError :
131+ _SYSTEM_VERSION_TUPLE = ()
132+
133+ return _SYSTEM_VERSION_TUPLE
134+
135+
113136def _remove_original_values (_config_vars ):
114137 """Remove original unmodified values for testing"""
115138 # This is needed for higher-level cross-platform tests of get_platform.
@@ -125,21 +148,52 @@ def _save_modified_value(_config_vars, cv, newvalue):
125148 _config_vars [_INITPRE + cv ] = oldvalue
126149 _config_vars [cv ] = newvalue
127150
151+
152+ _cache_default_sysroot = None
153+ def _default_sysroot (cc ):
154+ """ Returns the root of the default SDK for this system, or '/' """
155+ global _cache_default_sysroot
156+
157+ if _cache_default_sysroot is not None :
158+ return _cache_default_sysroot
159+
160+ contents = _read_output ('%s -c -E -v - </dev/null' % (cc ,), True )
161+ in_incdirs = False
162+ for line in contents .splitlines ():
163+ if line .startswith ("#include <...>" ):
164+ in_incdirs = True
165+ elif line .startswith ("End of search list" ):
166+ in_incdirs = False
167+ elif in_incdirs :
168+ line = line .strip ()
169+ if line == '/usr/include' :
170+ _cache_default_sysroot = '/'
171+ elif line .endswith (".sdk/usr/include" ):
172+ _cache_default_sysroot = line [:- 12 ]
173+ if _cache_default_sysroot is None :
174+ _cache_default_sysroot = '/'
175+
176+ return _cache_default_sysroot
177+
128178def _supports_universal_builds ():
129179 """Returns True if universal builds are supported on this system"""
130180 # As an approximation, we assume that if we are running on 10.4 or above,
131181 # then we are running with an Xcode environment that supports universal
132182 # builds, in particular -isysroot and -arch arguments to the compiler. This
133183 # is in support of allowing 10.4 universal builds to run on 10.3.x systems.
134184
135- osx_version = _get_system_version ()
136- if osx_version :
137- try :
138- osx_version = tuple (int (i ) for i in osx_version .split ('.' ))
139- except ValueError :
140- osx_version = ''
185+ osx_version = _get_system_version_tuple ()
141186 return bool (osx_version >= (10 , 4 )) if osx_version else False
142187
188+ def _supports_arm64_builds ():
189+ """Returns True if arm64 builds are supported on this system"""
190+ # There are two sets of systems supporting macOS/arm64 builds:
191+ # 1. macOS 11 and later, unconditionally
192+ # 2. macOS 10.15 with Xcode 12.2 or later
193+ # For now the second category is ignored.
194+ osx_version = _get_system_version_tuple ()
195+ return osx_version >= (11 , 0 ) if osx_version else False
196+
143197
144198def _find_appropriate_compiler (_config_vars ):
145199 """Find appropriate C compiler for extension module builds"""
@@ -211,7 +265,7 @@ def _remove_universal_flags(_config_vars):
211265 if cv in _config_vars and cv not in os .environ :
212266 flags = _config_vars [cv ]
213267 flags = re .sub (r'-arch\s+\w+\s' , ' ' , flags , flags = re .ASCII )
214- flags = re .sub ('-isysroot [^ \t ]* ' , ' ' , flags )
268+ flags = re .sub (r '-isysroot\s*\S+ ' , ' ' , flags )
215269 _save_modified_value (_config_vars , cv , flags )
216270
217271 return _config_vars
@@ -287,15 +341,15 @@ def _check_for_unavailable_sdk(_config_vars):
287341 # to /usr and /System/Library by either a standalone CLT
288342 # package or the CLT component within Xcode.
289343 cflags = _config_vars .get ('CFLAGS' , '' )
290- m = re .search (r'-isysroot\s+ (\S+)' , cflags )
344+ m = re .search (r'-isysroot\s* (\S+)' , cflags )
291345 if m is not None :
292346 sdk = m .group (1 )
293347 if not os .path .exists (sdk ):
294348 for cv in _UNIVERSAL_CONFIG_VARS :
295349 # Do not alter a config var explicitly overridden by env var
296350 if cv in _config_vars and cv not in os .environ :
297351 flags = _config_vars [cv ]
298- flags = re .sub (r'-isysroot\s+ \S+(?:\s|$)' , ' ' , flags )
352+ flags = re .sub (r'-isysroot\s* \S+(?:\s|$)' , ' ' , flags )
299353 _save_modified_value (_config_vars , cv , flags )
300354
301355 return _config_vars
@@ -320,7 +374,7 @@ def compiler_fixup(compiler_so, cc_args):
320374 stripArch = stripSysroot = True
321375 else :
322376 stripArch = '-arch' in cc_args
323- stripSysroot = '-isysroot' in cc_args
377+ stripSysroot = any ( arg for arg in cc_args if arg . startswith ( '-isysroot' ))
324378
325379 if stripArch or 'ARCHFLAGS' in os .environ :
326380 while True :
@@ -331,36 +385,52 @@ def compiler_fixup(compiler_so, cc_args):
331385 except ValueError :
332386 break
333387
388+ elif not _supports_arm64_builds ():
389+ # Look for "-arch arm64" and drop that
390+ for idx in reversed (range (len (compiler_so ))):
391+ if compiler_so [idx ] == '-arch' and compiler_so [idx + 1 ] == "arm64" :
392+ del compiler_so [idx :idx + 2 ]
393+
334394 if 'ARCHFLAGS' in os .environ and not stripArch :
335395 # User specified different -arch flags in the environ,
336396 # see also distutils.sysconfig
337397 compiler_so = compiler_so + os .environ ['ARCHFLAGS' ].split ()
338398
339399 if stripSysroot :
340400 while True :
341- try :
342- index = compiler_so .index ('-isysroot' )
401+ indices = [i for i ,x in enumerate (compiler_so ) if x .startswith ('-isysroot' )]
402+ if not indices :
403+ break
404+ index = indices [0 ]
405+ if compiler_so [index ] == '-isysroot' :
343406 # Strip this argument and the next one:
344407 del compiler_so [index :index + 2 ]
345- except ValueError :
346- break
408+ else :
409+ # It's '-isysroot/some/path' in one arg
410+ del compiler_so [index :index + 1 ]
347411
348412 # Check if the SDK that is used during compilation actually exists,
349413 # the universal build requires the usage of a universal SDK and not all
350414 # users have that installed by default.
351415 sysroot = None
352- if '-isysroot' in cc_args :
353- idx = cc_args .index ('-isysroot' )
354- sysroot = cc_args [idx + 1 ]
355- elif '-isysroot' in compiler_so :
356- idx = compiler_so .index ('-isysroot' )
357- sysroot = compiler_so [idx + 1 ]
416+ argvar = cc_args
417+ indices = [i for i ,x in enumerate (cc_args ) if x .startswith ('-isysroot' )]
418+ if not indices :
419+ argvar = compiler_so
420+ indices = [i for i ,x in enumerate (compiler_so ) if x .startswith ('-isysroot' )]
421+
422+ for idx in indices :
423+ if argvar [idx ] == '-isysroot' :
424+ sysroot = argvar [idx + 1 ]
425+ break
426+ else :
427+ sysroot = argvar [idx ][len ('-isysroot' ):]
428+ break
358429
359430 if sysroot and not os .path .isdir (sysroot ):
360- from distutils import log
361- log .warn ("Compiling with an SDK that doesn't seem to exist: %s" ,
362- sysroot )
363- log .warn ("Please check your Xcode installation" )
431+ sys .stderr .write (f"Compiling with an SDK that doesn't seem to exist: { sysroot } \n " )
432+ sys .stderr .write ("Please check your Xcode installation\n " )
433+ sys .stderr .flush ()
364434
365435 return compiler_so
366436
@@ -411,7 +481,7 @@ def customize_compiler(_config_vars):
411481
412482 This customization is performed when the first
413483 extension module build is requested
414- in distutils.sysconfig.customize_compiler) .
484+ in distutils.sysconfig.customize_compiler.
415485 """
416486
417487 # Find a compiler to use for extension module builds
@@ -454,10 +524,10 @@ def get_platform_osx(_config_vars, osname, release, machine):
454524 try :
455525 macrelease = tuple (int (i ) for i in macrelease .split ('.' )[0 :2 ])
456526 except ValueError :
457- macrelease = (10 , 0 )
527+ macrelease = (10 , 3 )
458528 else :
459529 # assume no universal support
460- macrelease = (10 , 0 )
530+ macrelease = (10 , 3 )
461531
462532 if (macrelease >= (10 , 4 )) and '-arch' in cflags .strip ():
463533 # The universal build will build fat binaries, but not on
@@ -470,6 +540,8 @@ def get_platform_osx(_config_vars, osname, release, machine):
470540
471541 if len (archs ) == 1 :
472542 machine = archs [0 ]
543+ elif archs == ('arm64' , 'x86_64' ):
544+ machine = 'universal2'
473545 elif archs == ('i386' , 'ppc' ):
474546 machine = 'fat'
475547 elif archs == ('i386' , 'x86_64' ):
0 commit comments