| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  | """Shared OS X support functions.""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import os | 
					
						
							|  |  |  | import re | 
					
						
							|  |  |  | import sys | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __all__ = [ | 
					
						
							|  |  |  |     'compiler_fixup', | 
					
						
							|  |  |  |     'customize_config_vars', | 
					
						
							|  |  |  |     'customize_compiler', | 
					
						
							|  |  |  |     'get_platform_osx', | 
					
						
							|  |  |  | ] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # configuration variables that may contain universal build flags, | 
					
						
							|  |  |  | # like "-arch" or "-isdkroot", that may need customization for | 
					
						
							|  |  |  | # the user environment | 
					
						
							|  |  |  | _UNIVERSAL_CONFIG_VARS = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS', 'BASECFLAGS', | 
					
						
							|  |  |  |                             'BLDSHARED', 'LDSHARED', 'CC', 'CXX', | 
					
						
							|  |  |  |                             'PY_CFLAGS', 'PY_LDFLAGS', 'PY_CPPFLAGS', | 
					
						
							|  |  |  |                             'PY_CORE_CFLAGS') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # configuration variables that may contain compiler calls | 
					
						
							|  |  |  | _COMPILER_CONFIG_VARS = ('BLDSHARED', 'LDSHARED', 'CC', 'CXX') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # prefix added to original configuration variable names | 
					
						
							|  |  |  | _INITPRE = '_OSX_SUPPORT_INITIAL_' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _find_executable(executable, path=None): | 
					
						
							|  |  |  |     """Tries to find 'executable' in the directories listed in 'path'.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     A string listing directories separated by 'os.pathsep'; defaults to | 
					
						
							|  |  |  |     os.environ['PATH'].  Returns the complete filename or None if not found. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     if path is None: | 
					
						
							|  |  |  |         path = os.environ['PATH'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     paths = path.split(os.pathsep) | 
					
						
							|  |  |  |     base, ext = os.path.splitext(executable) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-05 03:15:39 +02:00
										 |  |  |     if (sys.platform == 'win32') and (ext != '.exe'): | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |         executable = executable + '.exe' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not os.path.isfile(executable): | 
					
						
							|  |  |  |         for p in paths: | 
					
						
							|  |  |  |             f = os.path.join(p, executable) | 
					
						
							|  |  |  |             if os.path.isfile(f): | 
					
						
							|  |  |  |                 # the file exists, we have a shot at spawn working | 
					
						
							|  |  |  |                 return f | 
					
						
							|  |  |  |         return None | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         return executable | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _read_output(commandstring): | 
					
						
							| 
									
										
										
										
											2013-08-17 15:50:46 +03:00
										 |  |  |     """Output from successful command execution or None""" | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |     # Similar to os.popen(commandstring, "r").read(), | 
					
						
							|  |  |  |     # but without actually using os.popen because that | 
					
						
							|  |  |  |     # function is not usable during python bootstrap. | 
					
						
							|  |  |  |     # tempfile is also not available then. | 
					
						
							|  |  |  |     import contextlib | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         import tempfile | 
					
						
							|  |  |  |         fp = tempfile.NamedTemporaryFile() | 
					
						
							| 
									
										
										
										
											2013-07-04 17:43:24 -04:00
										 |  |  |     except ImportError: | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |         fp = open("/tmp/_osx_support.%s"%( | 
					
						
							|  |  |  |             os.getpid(),), "w+b") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     with contextlib.closing(fp) as fp: | 
					
						
							|  |  |  |         cmd = "%s 2>/dev/null >'%s'" % (commandstring, fp.name) | 
					
						
							|  |  |  |         return fp.read().decode('utf-8').strip() if not os.system(cmd) else None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _find_build_tool(toolname): | 
					
						
							|  |  |  |     """Find a build tool on current path or using xcrun""" | 
					
						
							|  |  |  |     return (_find_executable(toolname) | 
					
						
							|  |  |  |                 or _read_output("/usr/bin/xcrun -find %s" % (toolname,)) | 
					
						
							|  |  |  |                 or '' | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | _SYSTEM_VERSION = None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _get_system_version(): | 
					
						
							|  |  |  |     """Return the OS X system version as a string""" | 
					
						
							|  |  |  |     # Reading this plist is a documented way to get the system | 
					
						
							|  |  |  |     # version (see the documentation for the Gestalt Manager) | 
					
						
							|  |  |  |     # We avoid using platform.mac_ver to avoid possible bootstrap issues during | 
					
						
							|  |  |  |     # the build of Python itself (distutils is used to build standard library | 
					
						
							|  |  |  |     # extensions). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     global _SYSTEM_VERSION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if _SYSTEM_VERSION is None: | 
					
						
							|  |  |  |         _SYSTEM_VERSION = '' | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             f = open('/System/Library/CoreServices/SystemVersion.plist') | 
					
						
							| 
									
										
										
										
											2012-12-25 16:47:37 +02:00
										 |  |  |         except OSError: | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |             # We're on a plain darwin box, fall back to the default | 
					
						
							|  |  |  |             # behaviour. | 
					
						
							|  |  |  |             pass | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 m = re.search(r'<key>ProductUserVisibleVersion</key>\s*' | 
					
						
							|  |  |  |                               r'<string>(.*?)</string>', f.read()) | 
					
						
							|  |  |  |             finally: | 
					
						
							|  |  |  |                 f.close() | 
					
						
							|  |  |  |             if m is not None: | 
					
						
							|  |  |  |                 _SYSTEM_VERSION = '.'.join(m.group(1).split('.')[:2]) | 
					
						
							|  |  |  |             # else: fall back to the default behaviour | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _SYSTEM_VERSION | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _remove_original_values(_config_vars): | 
					
						
							|  |  |  |     """Remove original unmodified values for testing""" | 
					
						
							|  |  |  |     # This is needed for higher-level cross-platform tests of get_platform. | 
					
						
							|  |  |  |     for k in list(_config_vars): | 
					
						
							|  |  |  |         if k.startswith(_INITPRE): | 
					
						
							|  |  |  |             del _config_vars[k] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _save_modified_value(_config_vars, cv, newvalue): | 
					
						
							|  |  |  |     """Save modified and original unmodified value of configuration var""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     oldvalue = _config_vars.get(cv, '') | 
					
						
							|  |  |  |     if (oldvalue != newvalue) and (_INITPRE + cv not in _config_vars): | 
					
						
							|  |  |  |         _config_vars[_INITPRE + cv] = oldvalue | 
					
						
							|  |  |  |     _config_vars[cv] = newvalue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _supports_universal_builds(): | 
					
						
							|  |  |  |     """Returns True if universal builds are supported on this system""" | 
					
						
							|  |  |  |     # As an approximation, we assume that if we are running on 10.4 or above, | 
					
						
							|  |  |  |     # then we are running with an Xcode environment that supports universal | 
					
						
							|  |  |  |     # builds, in particular -isysroot and -arch arguments to the compiler. This | 
					
						
							|  |  |  |     # is in support of allowing 10.4 universal builds to run on 10.3.x systems. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     osx_version = _get_system_version() | 
					
						
							|  |  |  |     if osx_version: | 
					
						
							|  |  |  |         try: | 
					
						
							|  |  |  |             osx_version = tuple(int(i) for i in osx_version.split('.')) | 
					
						
							|  |  |  |         except ValueError: | 
					
						
							|  |  |  |             osx_version = '' | 
					
						
							|  |  |  |     return bool(osx_version >= (10, 4)) if osx_version else False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _find_appropriate_compiler(_config_vars): | 
					
						
							|  |  |  |     """Find appropriate C compiler for extension module builds""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 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. | 
					
						
							|  |  |  |     # | 
					
						
							| 
									
										
										
										
											2016-05-26 05:35:26 +00:00
										 |  |  |     #    Furthermore, the compiler that can be used varies between | 
					
						
							| 
									
										
										
										
											2013-08-17 15:50:46 +03:00
										 |  |  |     #    Xcode releases. Up to Xcode 4 it was possible to use 'gcc-4.2' | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |     #    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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 10:07:09 +00:00
										 |  |  |     # skip checks if the compiler was overridden with a CC env variable | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |     if 'CC' in os.environ: | 
					
						
							|  |  |  |         return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # The CC config var might contain additional arguments. | 
					
						
							|  |  |  |     # Ignore them while searching. | 
					
						
							|  |  |  |     cc = oldcc = _config_vars['CC'].split()[0] | 
					
						
							|  |  |  |     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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         cc = _find_build_tool('clang') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     elif os.path.basename(cc).startswith('gcc'): | 
					
						
							|  |  |  |         # Compiler is GCC, check if it is LLVM-GCC | 
					
						
							|  |  |  |         data = _read_output("'%s' --version" | 
					
						
							|  |  |  |                              % (cc.replace("'", "'\"'\"'"),)) | 
					
						
							| 
									
										
										
										
											2014-04-19 13:25:29 -07:00
										 |  |  |         if data and 'llvm-gcc' in data: | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |             # Found LLVM-GCC, fall back to clang | 
					
						
							|  |  |  |             cc = _find_build_tool('clang') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not cc: | 
					
						
							|  |  |  |         raise SystemError( | 
					
						
							|  |  |  |                "Cannot locate working compiler") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if cc != oldcc: | 
					
						
							|  |  |  |         # Found a replacement compiler. | 
					
						
							| 
									
										
										
										
											2013-08-17 15:50:46 +03:00
										 |  |  |         # Modify config vars using new compiler, if not already explicitly | 
					
						
							| 
									
										
										
										
											2016-06-02 10:07:09 +00:00
										 |  |  |         # overridden by an env variable, preserving additional arguments. | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |         for cv in _COMPILER_CONFIG_VARS: | 
					
						
							|  |  |  |             if cv in _config_vars and cv not in os.environ: | 
					
						
							|  |  |  |                 cv_split = _config_vars[cv].split() | 
					
						
							|  |  |  |                 cv_split[0] = cc if cv != 'CXX' else cc + '++' | 
					
						
							|  |  |  |                 _save_modified_value(_config_vars, cv, ' '.join(cv_split)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _remove_universal_flags(_config_vars): | 
					
						
							|  |  |  |     """Remove all universal build arguments from config vars""" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for cv in _UNIVERSAL_CONFIG_VARS: | 
					
						
							| 
									
										
										
										
											2016-06-02 10:07:09 +00:00
										 |  |  |         # Do not alter a config var explicitly overridden by env var | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |         if cv in _config_vars and cv not in os.environ: | 
					
						
							|  |  |  |             flags = _config_vars[cv] | 
					
						
							| 
									
										
										
										
											2017-04-14 08:28:55 -04:00
										 |  |  |             flags = re.sub(r'-arch\s+\w+\s', ' ', flags, flags=re.ASCII) | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |             flags = re.sub('-isysroot [^ \t]*', ' ', flags) | 
					
						
							|  |  |  |             _save_modified_value(_config_vars, cv, flags) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _remove_unsupported_archs(_config_vars): | 
					
						
							|  |  |  |     """Remove any unsupported archs from config vars""" | 
					
						
							|  |  |  |     # 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. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-02 10:07:09 +00:00
										 |  |  |     # skip checks if the compiler was overridden with a CC env variable | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |     if 'CC' in os.environ: | 
					
						
							|  |  |  |         return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-08 13:59:53 -04:00
										 |  |  |     if re.search(r'-arch\s+ppc', _config_vars['CFLAGS']) is not None: | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |         # NOTE: Cannot use subprocess here because of bootstrap | 
					
						
							|  |  |  |         # issues when building Python itself | 
					
						
							| 
									
										
										
										
											2013-10-18 21:09:56 -07:00
										 |  |  |         status = os.system( | 
					
						
							|  |  |  |             """echo 'int main{};' | """ | 
					
						
							|  |  |  |             """'%s' -c -arch ppc -x c -o /dev/null /dev/null 2>/dev/null""" | 
					
						
							|  |  |  |             %(_config_vars['CC'].replace("'", "'\"'\"'"),)) | 
					
						
							|  |  |  |         if status: | 
					
						
							|  |  |  |             # The compile failed for some reason.  Because of differences | 
					
						
							|  |  |  |             # across Xcode and compiler versions, there is no reliable way | 
					
						
							|  |  |  |             # to be sure why it failed.  Assume here it was due to lack of | 
					
						
							|  |  |  |             # PPC support and remove the related '-arch' flags from each | 
					
						
							| 
									
										
										
										
											2016-06-02 10:07:09 +00:00
										 |  |  |             # config variables not explicitly overridden by an environment | 
					
						
							| 
									
										
										
										
											2013-10-18 21:09:56 -07:00
										 |  |  |             # variable.  If the error was for some other reason, we hope the | 
					
						
							|  |  |  |             # failure will show up again when trying to compile an extension | 
					
						
							|  |  |  |             # module. | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |             for cv in _UNIVERSAL_CONFIG_VARS: | 
					
						
							|  |  |  |                 if cv in _config_vars and cv not in os.environ: | 
					
						
							|  |  |  |                     flags = _config_vars[cv] | 
					
						
							| 
									
										
										
										
											2016-09-08 13:59:53 -04:00
										 |  |  |                     flags = re.sub(r'-arch\s+ppc\w*\s', ' ', flags) | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |                     _save_modified_value(_config_vars, cv, flags) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _override_all_archs(_config_vars): | 
					
						
							|  |  |  |     """Allow override of all archs with ARCHFLAGS env var""" | 
					
						
							|  |  |  |     # 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 cv in _UNIVERSAL_CONFIG_VARS: | 
					
						
							|  |  |  |             if cv in _config_vars and '-arch' in _config_vars[cv]: | 
					
						
							|  |  |  |                 flags = _config_vars[cv] | 
					
						
							| 
									
										
										
										
											2016-09-08 13:59:53 -04:00
										 |  |  |                 flags = re.sub(r'-arch\s+\w+\s', ' ', flags) | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |                 flags = flags + ' ' + arch | 
					
						
							|  |  |  |                 _save_modified_value(_config_vars, cv, flags) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _check_for_unavailable_sdk(_config_vars): | 
					
						
							|  |  |  |     """Remove references to any SDKs not available""" | 
					
						
							|  |  |  |     # If we're on OSX 10.5 or later and the user tries to | 
					
						
							|  |  |  |     # compile an extension using an SDK that is not present | 
					
						
							|  |  |  |     # on the current machine it is better to not use an SDK | 
					
						
							|  |  |  |     # than to fail.  This is particularly important with | 
					
						
							| 
									
										
										
										
											2013-08-17 15:50:46 +03:00
										 |  |  |     # the standalone Command Line Tools alternative to a | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |     # full-blown Xcode install since the CLT packages do not | 
					
						
							|  |  |  |     # provide SDKs.  If the SDK is not present, it is assumed | 
					
						
							|  |  |  |     # that the header files and dev libs have been installed | 
					
						
							|  |  |  |     # to /usr and /System/Library by either a standalone CLT | 
					
						
							|  |  |  |     # package or the CLT component within Xcode. | 
					
						
							|  |  |  |     cflags = _config_vars.get('CFLAGS', '') | 
					
						
							|  |  |  |     m = re.search(r'-isysroot\s+(\S+)', cflags) | 
					
						
							|  |  |  |     if m is not None: | 
					
						
							|  |  |  |         sdk = m.group(1) | 
					
						
							|  |  |  |         if not os.path.exists(sdk): | 
					
						
							|  |  |  |             for cv in _UNIVERSAL_CONFIG_VARS: | 
					
						
							| 
									
										
										
										
											2016-06-02 10:07:09 +00:00
										 |  |  |                 # Do not alter a config var explicitly overridden by env var | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |                 if cv in _config_vars and cv not in os.environ: | 
					
						
							|  |  |  |                     flags = _config_vars[cv] | 
					
						
							|  |  |  |                     flags = re.sub(r'-isysroot\s+\S+(?:\s|$)', ' ', flags) | 
					
						
							|  |  |  |                     _save_modified_value(_config_vars, cv, flags) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def compiler_fixup(compiler_so, cc_args): | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     This function will strip '-isysroot PATH' and '-arch ARCH' from the | 
					
						
							|  |  |  |     compile flags if the user has specified one them in extra_compile_flags. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This is needed because '-arch ARCH' adds another architecture to the | 
					
						
							|  |  |  |     build, without a way to remove an architecture. Furthermore GCC will | 
					
						
							|  |  |  |     barf if multiple '-isysroot' arguments are present. | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     stripArch = stripSysroot = False | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     compiler_so = list(compiler_so) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not _supports_universal_builds(): | 
					
						
							|  |  |  |         # OSX before 10.4.0, these don't support -arch and -isysroot at | 
					
						
							|  |  |  |         # all. | 
					
						
							|  |  |  |         stripArch = stripSysroot = True | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         stripArch = '-arch' in cc_args | 
					
						
							|  |  |  |         stripSysroot = '-isysroot' in cc_args | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if stripArch or 'ARCHFLAGS' in os.environ: | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 index = compiler_so.index('-arch') | 
					
						
							|  |  |  |                 # Strip this argument and the next one: | 
					
						
							|  |  |  |                 del compiler_so[index:index+2] | 
					
						
							|  |  |  |             except ValueError: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if 'ARCHFLAGS' in os.environ and not stripArch: | 
					
						
							|  |  |  |         # User specified different -arch flags in the environ, | 
					
						
							|  |  |  |         # see also distutils.sysconfig | 
					
						
							|  |  |  |         compiler_so = compiler_so + os.environ['ARCHFLAGS'].split() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if stripSysroot: | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 index = compiler_so.index('-isysroot') | 
					
						
							|  |  |  |                 # Strip this argument and the next one: | 
					
						
							|  |  |  |                 del compiler_so[index:index+2] | 
					
						
							|  |  |  |             except ValueError: | 
					
						
							|  |  |  |                 break | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Check if the SDK that is used during compilation actually exists, | 
					
						
							|  |  |  |     # the universal build requires the usage of a universal SDK and not all | 
					
						
							|  |  |  |     # users have that installed by default. | 
					
						
							|  |  |  |     sysroot = None | 
					
						
							|  |  |  |     if '-isysroot' in cc_args: | 
					
						
							|  |  |  |         idx = cc_args.index('-isysroot') | 
					
						
							|  |  |  |         sysroot = cc_args[idx+1] | 
					
						
							|  |  |  |     elif '-isysroot' in compiler_so: | 
					
						
							|  |  |  |         idx = compiler_so.index('-isysroot') | 
					
						
							|  |  |  |         sysroot = compiler_so[idx+1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if sysroot and not os.path.isdir(sysroot): | 
					
						
							|  |  |  |         from distutils import log | 
					
						
							|  |  |  |         log.warn("Compiling with an SDK that doesn't seem to exist: %s", | 
					
						
							|  |  |  |                 sysroot) | 
					
						
							|  |  |  |         log.warn("Please check your Xcode installation") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return compiler_so | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def customize_config_vars(_config_vars): | 
					
						
							|  |  |  |     """Customize Python build configuration variables.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Called internally from sysconfig with a mutable mapping | 
					
						
							|  |  |  |     containing name/value pairs parsed from the configured | 
					
						
							|  |  |  |     makefile used to build this interpreter.  Returns | 
					
						
							|  |  |  |     the mapping updated as needed to reflect the environment | 
					
						
							|  |  |  |     in which the interpreter is running; in the case of | 
					
						
							|  |  |  |     a Python from a binary installer, the installed | 
					
						
							|  |  |  |     environment may be very different from the build | 
					
						
							|  |  |  |     environment, i.e. different OS levels, different | 
					
						
							|  |  |  |     built tools, different available CPU architectures. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This customization is performed whenever | 
					
						
							|  |  |  |     distutils.sysconfig.get_config_vars() is first | 
					
						
							|  |  |  |     called.  It may be used in environments where no | 
					
						
							|  |  |  |     compilers are present, i.e. when installing pure | 
					
						
							|  |  |  |     Python dists.  Customization of compiler paths | 
					
						
							|  |  |  |     and detection of unavailable archs is deferred | 
					
						
							| 
									
										
										
										
											2013-08-17 15:50:46 +03:00
										 |  |  |     until the first extension module build is | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |     requested (in distutils.sysconfig.customize_compiler). | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Currently called from distutils.sysconfig | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if not _supports_universal_builds(): | 
					
						
							|  |  |  |         # On Mac OS X before 10.4, check if -arch and -isysroot | 
					
						
							|  |  |  |         # are in CFLAGS or LDFLAGS and remove them if they are. | 
					
						
							|  |  |  |         # This is needed when building extensions on a 10.3 system | 
					
						
							|  |  |  |         # using a universal build of python. | 
					
						
							|  |  |  |         _remove_universal_flags(_config_vars) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Allow user to override all archs with ARCHFLAGS env var | 
					
						
							|  |  |  |     _override_all_archs(_config_vars) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Remove references to sdks that are not found | 
					
						
							|  |  |  |     _check_for_unavailable_sdk(_config_vars) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def customize_compiler(_config_vars): | 
					
						
							|  |  |  |     """Customize compiler path and configuration variables.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     This customization is performed when the first | 
					
						
							|  |  |  |     extension module build is requested | 
					
						
							|  |  |  |     in distutils.sysconfig.customize_compiler). | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Find a compiler to use for extension module builds | 
					
						
							|  |  |  |     _find_appropriate_compiler(_config_vars) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Remove ppc arch flags if not supported here | 
					
						
							|  |  |  |     _remove_unsupported_archs(_config_vars) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # Allow user to override all archs with ARCHFLAGS env var | 
					
						
							|  |  |  |     _override_all_archs(_config_vars) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return _config_vars | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def get_platform_osx(_config_vars, osname, release, machine): | 
					
						
							|  |  |  |     """Filter values for get_platform()""" | 
					
						
							|  |  |  |     # called from get_platform() in sysconfig and distutils.util | 
					
						
							|  |  |  |     # | 
					
						
							|  |  |  |     # For our purposes, we'll assume that the system version from | 
					
						
							|  |  |  |     # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set | 
					
						
							|  |  |  |     # to. This makes the compatibility story a bit more sane because the | 
					
						
							|  |  |  |     # machine is going to compile and link as if it were | 
					
						
							|  |  |  |     # MACOSX_DEPLOYMENT_TARGET. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     macver = _config_vars.get('MACOSX_DEPLOYMENT_TARGET', '') | 
					
						
							|  |  |  |     macrelease = _get_system_version() or macver | 
					
						
							|  |  |  |     macver = macver or macrelease | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if macver: | 
					
						
							|  |  |  |         release = macver | 
					
						
							|  |  |  |         osname = "macosx" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # Use the original CFLAGS value, if available, so that we | 
					
						
							|  |  |  |         # return the same machine type for the platform string. | 
					
						
							|  |  |  |         # Otherwise, distutils may consider this a cross-compiling | 
					
						
							|  |  |  |         # case and disallow installs. | 
					
						
							|  |  |  |         cflags = _config_vars.get(_INITPRE+'CFLAGS', | 
					
						
							|  |  |  |                                     _config_vars.get('CFLAGS', '')) | 
					
						
							| 
									
										
										
										
											2014-06-25 13:36:14 -07:00
										 |  |  |         if macrelease: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 macrelease = tuple(int(i) for i in macrelease.split('.')[0:2]) | 
					
						
							|  |  |  |             except ValueError: | 
					
						
							|  |  |  |                 macrelease = (10, 0) | 
					
						
							|  |  |  |         else: | 
					
						
							|  |  |  |             # assume no universal support | 
					
						
							|  |  |  |             macrelease = (10, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (macrelease >= (10, 4)) and '-arch' in cflags.strip(): | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |             # The universal build will build fat binaries, but not on | 
					
						
							|  |  |  |             # systems before 10.4 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             machine = 'fat' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-08 13:59:53 -04:00
										 |  |  |             archs = re.findall(r'-arch\s+(\S+)', cflags) | 
					
						
							| 
									
										
										
										
											2012-07-21 05:36:30 -07:00
										 |  |  |             archs = tuple(sorted(set(archs))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if len(archs) == 1: | 
					
						
							|  |  |  |                 machine = archs[0] | 
					
						
							|  |  |  |             elif archs == ('i386', 'ppc'): | 
					
						
							|  |  |  |                 machine = 'fat' | 
					
						
							|  |  |  |             elif archs == ('i386', 'x86_64'): | 
					
						
							|  |  |  |                 machine = 'intel' | 
					
						
							|  |  |  |             elif archs == ('i386', 'ppc', 'x86_64'): | 
					
						
							|  |  |  |                 machine = 'fat3' | 
					
						
							|  |  |  |             elif archs == ('ppc64', 'x86_64'): | 
					
						
							|  |  |  |                 machine = 'fat64' | 
					
						
							|  |  |  |             elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): | 
					
						
							|  |  |  |                 machine = 'universal' | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 raise ValueError( | 
					
						
							|  |  |  |                    "Don't know machine value for archs=%r" % (archs,)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         elif machine == 'i386': | 
					
						
							|  |  |  |             # On OSX the machine type returned by uname is always the | 
					
						
							|  |  |  |             # 32-bit variant, even if the executable architecture is | 
					
						
							|  |  |  |             # the 64-bit variant | 
					
						
							|  |  |  |             if sys.maxsize >= 2**32: | 
					
						
							|  |  |  |                 machine = 'x86_64' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         elif machine in ('PowerPC', 'Power_Macintosh'): | 
					
						
							|  |  |  |             # Pick a sane name for the PPC architecture. | 
					
						
							|  |  |  |             # See 'i386' case | 
					
						
							|  |  |  |             if sys.maxsize >= 2**32: | 
					
						
							|  |  |  |                 machine = 'ppc64' | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 machine = 'ppc' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return (osname, release, machine) |