blob: 37975fe8a3eefa63dcb485f407a8df63c31d8f0e [file] [log] [blame]
Ned Deilydf8aa2b2012-07-21 05:36:30 -07001"""Shared OS X support functions."""
2
3import os
4import re
5import sys
6
7__all__ = [
8 'compiler_fixup',
9 'customize_config_vars',
10 'customize_compiler',
11 'get_platform_osx',
12]
13
14# configuration variables that may contain universal build flags,
15# like "-arch" or "-isdkroot", that may need customization for
16# the user environment
17_UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS',
18 'BLDSHARED', 'LDSHARED', 'CC', 'CXX',
19 'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS',
stratakiscf10a752018-12-19 18:19:01 +010020 'PY_CORE_CFLAGS', 'PY_CORE_LDFLAGS')
Ned Deilydf8aa2b2012-07-21 05:36:30 -070021
22# configuration variables that may contain compiler calls
23_COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX')
24
25# prefix added to original configuration variable names
26_INITPRE = '_OSX_SUPPORT_INITIAL_'
27
28
29def _find_executable(executable, path=None):
30 """Tries to find 'executable' in the directories listed in 'path'.
31
32 A string listing directories separated by 'os.pathsep'; defaults to
33 os.environ['PATH']. Returns the complete filename or None if not found.
34 """
35 if path is None:
36 path = os.environ['PATH']
37
38 paths = path.split(os.pathsep)
39 base, ext = os.path.splitext(executable)
40
Jesus Cea4791a242012-10-05 03:15:39 +020041 if (sys.platform == 'win32') and (ext != '.exe'):
Ned Deilydf8aa2b2012-07-21 05:36:30 -070042 executable = executable + '.exe'
43
44 if not os.path.isfile(executable):
45 for p in paths:
46 f = os.path.join(p, executable)
47 if os.path.isfile(f):
48 # the file exists, we have a shot at spawn working
49 return f
50 return None
51 else:
52 return executable
53
54
Ronald Oussoren404a7192020-11-22 06:14:25 +010055def _read_output(commandstring, capture_stderr=False):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +030056 """Output from successful command execution or None"""
Ned Deilydf8aa2b2012-07-21 05:36:30 -070057 # Similar to os.popen(commandstring, "r").read(),
58 # but without actually using os.popen because that
59 # function is not usable during python bootstrap.
60 # tempfile is also not available then.
61 import contextlib
62 try:
63 import tempfile
64 fp = tempfile.NamedTemporaryFile()
Brett Cannoncd171c82013-07-04 17:43:24 -040065 except ImportError:
Ned Deilydf8aa2b2012-07-21 05:36:30 -070066 fp = open("/tmp/_osx_support.%s"%(
67 os.getpid(),), "w+b")
68
69 with contextlib.closing(fp) as fp:
Ronald Oussoren404a7192020-11-22 06:14:25 +010070 if capture_stderr:
71 cmd = "%s >'%s' 2>&1" % (commandstring, fp.name)
72 else:
73 cmd = "%s 2>/dev/null >'%s'" % (commandstring, fp.name)
Ned Deilydf8aa2b2012-07-21 05:36:30 -070074 return fp.read().decode('utf-8').strip() if not os.system(cmd) else None
75
76
77def _find_build_tool(toolname):
78 """Find a build tool on current path or using xcrun"""
79 return (_find_executable(toolname)
80 or _read_output("/usr/bin/xcrun -find %s" % (toolname,))
81 or ''
82 )
83
84_SYSTEM_VERSION = None
85
86def _get_system_version():
87 """Return the OS X system version as a string"""
88 # Reading this plist is a documented way to get the system
89 # version (see the documentation for the Gestalt Manager)
90 # We avoid using platform.mac_ver to avoid possible bootstrap issues during
91 # the build of Python itself (distutils is used to build standard library
92 # extensions).
93
94 global _SYSTEM_VERSION
95
96 if _SYSTEM_VERSION is None:
97 _SYSTEM_VERSION = ''
98 try:
99 f = open('/System/Library/CoreServices/SystemVersion.plist')
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200100 except OSError:
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700101 # We're on a plain darwin box, fall back to the default
102 # behaviour.
103 pass
104 else:
105 try:
106 m = re.search(r'<key>ProductUserVisibleVersion</key>\s*'
107 r'<string>(.*?)</string>', f.read())
108 finally:
109 f.close()
110 if m is not None:
111 _SYSTEM_VERSION = '.'.join(m.group(1).split('.')[:2])
112 # else: fall back to the default behaviour
113
114 return _SYSTEM_VERSION
115
Ronald Oussoren41761932020-11-08 10:05:27 +0100116_SYSTEM_VERSION_TUPLE = None
117def _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
Ronald Oussoren442746a2020-11-22 03:17:18 +0100134
Ronald Oussoren41761932020-11-08 10:05:27 +0100135
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700136def _remove_original_values(_config_vars):
137 """Remove original unmodified values for testing"""
138 # This is needed for higher-level cross-platform tests of get_platform.
139 for k in list(_config_vars):
140 if k.startswith(_INITPRE):
141 del _config_vars[k]
142
143def _save_modified_value(_config_vars, cv, newvalue):
144 """Save modified and original unmodified value of configuration var"""
145
146 oldvalue = _config_vars.get(cv, '')
147 if (oldvalue != newvalue) and (_INITPRE + cv not in _config_vars):
148 _config_vars[_INITPRE + cv] = oldvalue
149 _config_vars[cv] = newvalue
150
Ronald Oussoren404a7192020-11-22 06:14:25 +0100151
152_cache_default_sysroot = None
153def _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
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700178def _supports_universal_builds():
179 """Returns True if universal builds are supported on this system"""
180 # As an approximation, we assume that if we are running on 10.4 or above,
181 # then we are running with an Xcode environment that supports universal
182 # builds, in particular -isysroot and -arch arguments to the compiler. This
183 # is in support of allowing 10.4 universal builds to run on 10.3.x systems.
184
Ronald Oussoren41761932020-11-08 10:05:27 +0100185 osx_version = _get_system_version_tuple()
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700186 return bool(osx_version >= (10, 4)) if osx_version else False
187
Ronald Oussoren41761932020-11-08 10:05:27 +0100188def _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
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700197
198def _find_appropriate_compiler(_config_vars):
199 """Find appropriate C compiler for extension module builds"""
200
201 # Issue #13590:
202 # The OSX location for the compiler varies between OSX
203 # (or rather Xcode) releases. With older releases (up-to 10.5)
204 # the compiler is in /usr/bin, with newer releases the compiler
205 # can only be found inside Xcode.app if the "Command Line Tools"
206 # are not installed.
207 #
Martin Panter46f50722016-05-26 05:35:26 +0000208 # Furthermore, the compiler that can be used varies between
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300209 # Xcode releases. Up to Xcode 4 it was possible to use 'gcc-4.2'
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700210 # as the compiler, after that 'clang' should be used because
211 # gcc-4.2 is either not present, or a copy of 'llvm-gcc' that
212 # miscompiles Python.
213
Martin Pantere26da7c2016-06-02 10:07:09 +0000214 # skip checks if the compiler was overridden with a CC env variable
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700215 if 'CC' in os.environ:
216 return _config_vars
217
218 # The CC config var might contain additional arguments.
219 # Ignore them while searching.
220 cc = oldcc = _config_vars['CC'].split()[0]
221 if not _find_executable(cc):
222 # Compiler is not found on the shell search PATH.
223 # Now search for clang, first on PATH (if the Command LIne
224 # Tools have been installed in / or if the user has provided
225 # another location via CC). If not found, try using xcrun
226 # to find an uninstalled clang (within a selected Xcode).
227
228 # NOTE: Cannot use subprocess here because of bootstrap
229 # issues when building Python itself (and os.popen is
230 # implemented on top of subprocess and is therefore not
231 # usable as well)
232
233 cc = _find_build_tool('clang')
234
235 elif os.path.basename(cc).startswith('gcc'):
236 # Compiler is GCC, check if it is LLVM-GCC
237 data = _read_output("'%s' --version"
238 % (cc.replace("'", "'\"'\"'"),))
Ned Deilyf31b4782014-04-19 13:25:29 -0700239 if data and 'llvm-gcc' in data:
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700240 # Found LLVM-GCC, fall back to clang
241 cc = _find_build_tool('clang')
242
243 if not cc:
244 raise SystemError(
245 "Cannot locate working compiler")
246
247 if cc != oldcc:
248 # Found a replacement compiler.
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300249 # Modify config vars using new compiler, if not already explicitly
Martin Pantere26da7c2016-06-02 10:07:09 +0000250 # overridden by an env variable, preserving additional arguments.
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700251 for cv in _COMPILER_CONFIG_VARS:
252 if cv in _config_vars and cv not in os.environ:
253 cv_split = _config_vars[cv].split()
254 cv_split[0] = cc if cv != 'CXX' else cc + '++'
255 _save_modified_value(_config_vars, cv, ' '.join(cv_split))
256
257 return _config_vars
258
259
260def _remove_universal_flags(_config_vars):
261 """Remove all universal build arguments from config vars"""
262
263 for cv in _UNIVERSAL_CONFIG_VARS:
Martin Pantere26da7c2016-06-02 10:07:09 +0000264 # Do not alter a config var explicitly overridden by env var
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700265 if cv in _config_vars and cv not in os.environ:
266 flags = _config_vars[cv]
Jack McCrackence040f62017-04-14 08:28:55 -0400267 flags = re.sub(r'-arch\s+\w+\s', ' ', flags, flags=re.ASCII)
Joshua Rootb3107002020-04-22 17:44:10 +1000268 flags = re.sub(r'-isysroot\s*\S+', ' ', flags)
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700269 _save_modified_value(_config_vars, cv, flags)
270
271 return _config_vars
272
273
274def _remove_unsupported_archs(_config_vars):
275 """Remove any unsupported archs from config vars"""
276 # Different Xcode releases support different sets for '-arch'
277 # flags. In particular, Xcode 4.x no longer supports the
278 # PPC architectures.
279 #
280 # This code automatically removes '-arch ppc' and '-arch ppc64'
281 # when these are not supported. That makes it possible to
282 # build extensions on OSX 10.7 and later with the prebuilt
283 # 32-bit installer on the python.org website.
284
Martin Pantere26da7c2016-06-02 10:07:09 +0000285 # skip checks if the compiler was overridden with a CC env variable
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700286 if 'CC' in os.environ:
287 return _config_vars
288
R David Murray44b548d2016-09-08 13:59:53 -0400289 if re.search(r'-arch\s+ppc', _config_vars['CFLAGS']) is not None:
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700290 # NOTE: Cannot use subprocess here because of bootstrap
291 # issues when building Python itself
Ned Deily87adb6e2013-10-18 21:09:56 -0700292 status = os.system(
293 """echo 'int main{};' | """
294 """'%s' -c -arch ppc -x c -o /dev/null /dev/null 2>/dev/null"""
295 %(_config_vars['CC'].replace("'", "'\"'\"'"),))
296 if status:
297 # The compile failed for some reason. Because of differences
298 # across Xcode and compiler versions, there is no reliable way
299 # to be sure why it failed. Assume here it was due to lack of
300 # PPC support and remove the related '-arch' flags from each
Martin Pantere26da7c2016-06-02 10:07:09 +0000301 # config variables not explicitly overridden by an environment
Ned Deily87adb6e2013-10-18 21:09:56 -0700302 # variable. If the error was for some other reason, we hope the
303 # failure will show up again when trying to compile an extension
304 # module.
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700305 for cv in _UNIVERSAL_CONFIG_VARS:
306 if cv in _config_vars and cv not in os.environ:
307 flags = _config_vars[cv]
R David Murray44b548d2016-09-08 13:59:53 -0400308 flags = re.sub(r'-arch\s+ppc\w*\s', ' ', flags)
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700309 _save_modified_value(_config_vars, cv, flags)
310
311 return _config_vars
312
313
314def _override_all_archs(_config_vars):
315 """Allow override of all archs with ARCHFLAGS env var"""
316 # NOTE: This name was introduced by Apple in OSX 10.5 and
317 # is used by several scripting languages distributed with
318 # that OS release.
319 if 'ARCHFLAGS' in os.environ:
320 arch = os.environ['ARCHFLAGS']
321 for cv in _UNIVERSAL_CONFIG_VARS:
322 if cv in _config_vars and '-arch' in _config_vars[cv]:
323 flags = _config_vars[cv]
R David Murray44b548d2016-09-08 13:59:53 -0400324 flags = re.sub(r'-arch\s+\w+\s', ' ', flags)
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700325 flags = flags + ' ' + arch
326 _save_modified_value(_config_vars, cv, flags)
327
328 return _config_vars
329
330
331def _check_for_unavailable_sdk(_config_vars):
332 """Remove references to any SDKs not available"""
333 # If we're on OSX 10.5 or later and the user tries to
334 # compile an extension using an SDK that is not present
335 # on the current machine it is better to not use an SDK
336 # than to fail. This is particularly important with
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300337 # the standalone Command Line Tools alternative to a
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700338 # full-blown Xcode install since the CLT packages do not
339 # provide SDKs. If the SDK is not present, it is assumed
340 # that the header files and dev libs have been installed
341 # to /usr and /System/Library by either a standalone CLT
342 # package or the CLT component within Xcode.
343 cflags = _config_vars.get('CFLAGS', '')
Joshua Rootb3107002020-04-22 17:44:10 +1000344 m = re.search(r'-isysroot\s*(\S+)', cflags)
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700345 if m is not None:
346 sdk = m.group(1)
347 if not os.path.exists(sdk):
348 for cv in _UNIVERSAL_CONFIG_VARS:
Martin Pantere26da7c2016-06-02 10:07:09 +0000349 # Do not alter a config var explicitly overridden by env var
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700350 if cv in _config_vars and cv not in os.environ:
351 flags = _config_vars[cv]
Joshua Rootb3107002020-04-22 17:44:10 +1000352 flags = re.sub(r'-isysroot\s*\S+(?:\s|$)', ' ', flags)
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700353 _save_modified_value(_config_vars, cv, flags)
354
355 return _config_vars
356
357
358def compiler_fixup(compiler_so, cc_args):
359 """
360 This function will strip '-isysroot PATH' and '-arch ARCH' from the
361 compile flags if the user has specified one them in extra_compile_flags.
362
363 This is needed because '-arch ARCH' adds another architecture to the
364 build, without a way to remove an architecture. Furthermore GCC will
365 barf if multiple '-isysroot' arguments are present.
366 """
367 stripArch = stripSysroot = False
368
369 compiler_so = list(compiler_so)
370
371 if not _supports_universal_builds():
372 # OSX before 10.4.0, these don't support -arch and -isysroot at
373 # all.
374 stripArch = stripSysroot = True
375 else:
376 stripArch = '-arch' in cc_args
Joshua Rootb3107002020-04-22 17:44:10 +1000377 stripSysroot = any(arg for arg in cc_args if arg.startswith('-isysroot'))
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700378
379 if stripArch or 'ARCHFLAGS' in os.environ:
380 while True:
381 try:
382 index = compiler_so.index('-arch')
383 # Strip this argument and the next one:
384 del compiler_so[index:index+2]
385 except ValueError:
386 break
387
Ronald Oussoren41761932020-11-08 10:05:27 +0100388 elif not _supports_arm64_builds():
389 # Look for "-arch arm64" and drop that
Ronald Oussoren442746a2020-11-22 03:17:18 +0100390 for idx in reversed(range(len(compiler_so))):
Ronald Oussoren41761932020-11-08 10:05:27 +0100391 if compiler_so[idx] == '-arch' and compiler_so[idx+1] == "arm64":
392 del compiler_so[idx:idx+2]
393
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700394 if 'ARCHFLAGS' in os.environ and not stripArch:
395 # User specified different -arch flags in the environ,
396 # see also distutils.sysconfig
397 compiler_so = compiler_so + os.environ['ARCHFLAGS'].split()
398
399 if stripSysroot:
400 while True:
Joshua Rootb3107002020-04-22 17:44:10 +1000401 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':
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700406 # Strip this argument and the next one:
407 del compiler_so[index:index+2]
Joshua Rootb3107002020-04-22 17:44:10 +1000408 else:
409 # It's '-isysroot/some/path' in one arg
410 del compiler_so[index:index+1]
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700411
412 # Check if the SDK that is used during compilation actually exists,
413 # the universal build requires the usage of a universal SDK and not all
414 # users have that installed by default.
415 sysroot = None
Joshua Rootb3107002020-04-22 17:44:10 +1000416 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
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700429
430 if sysroot and not os.path.isdir(sysroot):
431 from distutils import log
432 log.warn("Compiling with an SDK that doesn't seem to exist: %s",
433 sysroot)
434 log.warn("Please check your Xcode installation")
435
436 return compiler_so
437
438
439def customize_config_vars(_config_vars):
440 """Customize Python build configuration variables.
441
442 Called internally from sysconfig with a mutable mapping
443 containing name/value pairs parsed from the configured
444 makefile used to build this interpreter. Returns
445 the mapping updated as needed to reflect the environment
446 in which the interpreter is running; in the case of
447 a Python from a binary installer, the installed
448 environment may be very different from the build
449 environment, i.e. different OS levels, different
450 built tools, different available CPU architectures.
451
452 This customization is performed whenever
453 distutils.sysconfig.get_config_vars() is first
454 called. It may be used in environments where no
455 compilers are present, i.e. when installing pure
456 Python dists. Customization of compiler paths
457 and detection of unavailable archs is deferred
Ezio Melotti30b9d5d2013-08-17 15:50:46 +0300458 until the first extension module build is
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700459 requested (in distutils.sysconfig.customize_compiler).
460
461 Currently called from distutils.sysconfig
462 """
463
464 if not _supports_universal_builds():
465 # On Mac OS X before 10.4, check if -arch and -isysroot
466 # are in CFLAGS or LDFLAGS and remove them if they are.
467 # This is needed when building extensions on a 10.3 system
468 # using a universal build of python.
469 _remove_universal_flags(_config_vars)
470
471 # Allow user to override all archs with ARCHFLAGS env var
472 _override_all_archs(_config_vars)
473
474 # Remove references to sdks that are not found
475 _check_for_unavailable_sdk(_config_vars)
476
477 return _config_vars
478
479
480def customize_compiler(_config_vars):
481 """Customize compiler path and configuration variables.
482
483 This customization is performed when the first
484 extension module build is requested
485 in distutils.sysconfig.customize_compiler).
486 """
487
488 # Find a compiler to use for extension module builds
489 _find_appropriate_compiler(_config_vars)
490
491 # Remove ppc arch flags if not supported here
492 _remove_unsupported_archs(_config_vars)
493
494 # Allow user to override all archs with ARCHFLAGS env var
495 _override_all_archs(_config_vars)
496
497 return _config_vars
498
499
500def get_platform_osx(_config_vars, osname, release, machine):
501 """Filter values for get_platform()"""
502 # called from get_platform() in sysconfig and distutils.util
503 #
504 # For our purposes, we'll assume that the system version from
505 # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set
506 # to. This makes the compatibility story a bit more sane because the
507 # machine is going to compile and link as if it were
508 # MACOSX_DEPLOYMENT_TARGET.
509
510 macver = _config_vars.get('MACOSX_DEPLOYMENT_TARGET', '')
511 macrelease = _get_system_version() or macver
512 macver = macver or macrelease
513
514 if macver:
515 release = macver
516 osname = "macosx"
517
518 # Use the original CFLAGS value, if available, so that we
519 # return the same machine type for the platform string.
520 # Otherwise, distutils may consider this a cross-compiling
521 # case and disallow installs.
522 cflags = _config_vars.get(_INITPRE+'CFLAGS',
523 _config_vars.get('CFLAGS', ''))
Ned Deily04cdfa12014-06-25 13:36:14 -0700524 if macrelease:
525 try:
526 macrelease = tuple(int(i) for i in macrelease.split('.')[0:2])
527 except ValueError:
528 macrelease = (10, 0)
529 else:
530 # assume no universal support
531 macrelease = (10, 0)
532
533 if (macrelease >= (10, 4)) and '-arch' in cflags.strip():
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700534 # The universal build will build fat binaries, but not on
535 # systems before 10.4
536
537 machine = 'fat'
538
R David Murray44b548d2016-09-08 13:59:53 -0400539 archs = re.findall(r'-arch\s+(\S+)', cflags)
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700540 archs = tuple(sorted(set(archs)))
541
542 if len(archs) == 1:
543 machine = archs[0]
Ronald Oussoren41761932020-11-08 10:05:27 +0100544 elif archs == ('arm64', 'x86_64'):
545 machine = 'universal2'
Ned Deilydf8aa2b2012-07-21 05:36:30 -0700546 elif archs == ('i386', 'ppc'):
547 machine = 'fat'
548 elif archs == ('i386', 'x86_64'):
549 machine = 'intel'
550 elif archs == ('i386', 'ppc', 'x86_64'):
551 machine = 'fat3'
552 elif archs == ('ppc64', 'x86_64'):
553 machine = 'fat64'
554 elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'):
555 machine = 'universal'
556 else:
557 raise ValueError(
558 "Don't know machine value for archs=%r" % (archs,))
559
560 elif machine == 'i386':
561 # On OSX the machine type returned by uname is always the
562 # 32-bit variant, even if the executable architecture is
563 # the 64-bit variant
564 if sys.maxsize >= 2**32:
565 machine = 'x86_64'
566
567 elif machine in ('PowerPC', 'Power_Macintosh'):
568 # Pick a sane name for the PPC architecture.
569 # See 'i386' case
570 if sys.maxsize >= 2**32:
571 machine = 'ppc64'
572 else:
573 machine = 'ppc'
574
575 return (osname, release, machine)