# HG changeset patch # User Ned Deily # Date 1292748795 28800 # Branch release27-maint # Node ID d68d2ebd9626877825ca03b1a21cfce5781f0e44 # Parent 382f045b2f59ea8d27f75af29fec9e0553133c50 Issue10735: platform.architecture() now returns meaningful values for bits and linkage with OS X multi-architecture executables [2.7 backport] diff -r 382f045b2f59 -r d68d2ebd9626 Doc/library/platform.rst --- Doc/library/platform.rst Sat Dec 18 20:43:05 2010 +0100 +++ Doc/library/platform.rst Sun Dec 19 00:53:15 2010 -0800 @@ -38,6 +38,15 @@ and then only if the executable points to the Python interpreter. Reasonable defaults are used when the above needs are not met. + .. note:: + + On Mac OS X platforms, executable files may be universal files containing + multiple architectures. If *executable* refers to the running Python + interpreter binary on Mac OS X, the ``bits`` value returned will be that + of the running interpreter process, ``'32bit'`` or ``'64bit'``, and the + *linkage* string will contain information about all architectures + contained in the executable file. + .. function:: machine() @@ -194,7 +203,7 @@ .. note:: - Note: this function works best with Mark Hammond's + This function works best with Mark Hammond's :mod:`win32all` package installed, but also on Python 2.3 and later (support for this was added in Python 2.6). It obviously only runs on Win32 compatible platforms. diff -r 382f045b2f59 -r d68d2ebd9626 Lib/platform.py --- Lib/platform.py Sat Dec 18 20:43:05 2010 +0100 +++ Lib/platform.py Sun Dec 19 00:53:15 2010 -0800 @@ -1046,6 +1046,8 @@ _architecture_split = re.compile(r'[\s,]').split +_mach_o_cache = None + def architecture(executable=sys.executable,bits='',linkage=''): """ Queries the given executable (defaults to the Python interpreter @@ -1067,6 +1069,8 @@ binary defaults from _default_architecture are used. """ + global _mach_o_cache + # Use the sizeof(pointer) as default number of bits if nothing # else is given as default. if not bits: @@ -1080,11 +1084,11 @@ # Get data from the 'file' system command if executable: - output = _syscmd_file(executable, '') + fileout = _syscmd_file(executable, '') else: - output = '' + fileout = '' - if not output and \ + if not fileout and \ executable == sys.executable: # "file" command did not return anything; we'll try to provide # some sensible defaults then... @@ -1096,15 +1100,15 @@ linkage = l return bits, linkage - # Split the output into a list of strings omitting the filename - fileout = _architecture_split(output)[1:] - if 'executable' not in fileout: # Format not supported return bits,linkage # Bits - if '32-bit' in fileout: + if (executable == sys.executable and + 'Mach-O universal' in fileout): + pass # use sizeof(pointer) results from our process + elif '32-bit' in fileout: bits = '32bit' elif 'N32' in fileout: # On Irix only @@ -1125,6 +1129,20 @@ linkage = 'COFF' elif 'MS-DOS' in fileout: linkage = 'MSDOS' + elif ('Mach-O executable' in fileout + or 'Mach-O 64-bit executable' in fileout): + if _mach_o_cache is None: + _mach_o_cache = re.compile(r'Mach-O .*executable (.*)(?:\n|$)') + archs = re.findall(_mach_o_cache, fileout) + linkage = ['MachO', None, None] + for arch in archs: + if arch in ('i386', 'ppc'): + linkage[1] = '32bit' + elif arch in ('x86_64', 'ppc64'): + linkage[2] = '64bit' + linkage.append(arch) + linkage = ' '.join(l for l in linkage if l) + # "Mach 32bit 64bit ppc i386 ppc64 x86_64" else: # XXX the A.OUT format also falls under this class... pass diff -r 382f045b2f59 -r d68d2ebd9626 Lib/test/test_platform.py --- Lib/test/test_platform.py Sat Dec 18 20:43:05 2010 +0100 +++ Lib/test/test_platform.py Sun Dec 19 00:53:15 2010 -0800 @@ -214,6 +214,24 @@ self.assertEqual(cpid, pid) self.assertEqual(sts, 0) + @unittest.skipUnless(sys.platform == 'darwin', "OSX only test") + def test_mac_architecture_bits(self): + bits, _ = platform.architecture() + self.assertIn(bits, ('32bit', '64bit')) + if bits == '32bit': + self.assertEqual(sys.maxsize, 2**31 - 1) + else: + self.assertEqual(sys.maxsize, 2**63 - 1) + + @unittest.skipUnless(sys.platform == 'darwin', "OSX only test") + def test_mac_architecture_linkage(self): + _, linkage = platform.architecture() + # results should be some substring of: + # "MachO executable 32bit 64bit ppc i386 ppc64 x86_64" + self.assertRegexpMatches(linkage, (r'MachO')) + self.assertRegexpMatches(linkage, (r'32bit|64bit')) + self.assertRegexpMatches(linkage, (r'ppc|i386|ppc64|x86_64')) + def test_dist(self): res = platform.dist()