# HG changeset patch # User Ned Deily # Date 1292746514 28800 # Branch py3k # Node ID 0523170361b9911f2a36f05684db9e7b3dc8152b # Parent 7c7de73eaa49903af56962d74fd1b5efab5b7ddc Issue10735: platform.architecture() now returns meaningful values for bits and linkage with OS X multi-architecture executables diff -r 7c7de73eaa49 -r 0523170361b9 Doc/library/platform.rst --- Doc/library/platform.rst Sun Dec 19 07:02:31 2010 +0100 +++ Doc/library/platform.rst Sun Dec 19 00:15:14 2010 -0800 @@ -36,6 +36,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() @@ -186,7 +195,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 7c7de73eaa49 -r 0523170361b9 Lib/platform.py --- Lib/platform.py Sun Dec 19 07:02:31 2010 +0100 +++ Lib/platform.py Sun Dec 19 00:15:14 2010 -0800 @@ -1016,6 +1016,8 @@ 'dos': ('','MSDOS'), } +_mach_o_cache = None + def architecture(executable=sys.executable,bits='',linkage=''): """ Queries the given executable (defaults to the Python interpreter @@ -1037,6 +1039,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: @@ -1071,7 +1075,10 @@ 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 @@ -1092,6 +1099,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 7c7de73eaa49 -r 0523170361b9 Lib/test/test_platform.py --- Lib/test/test_platform.py Sun Dec 19 07:02:31 2010 +0100 +++ Lib/test/test_platform.py Sun Dec 19 00:15:14 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.assertRegex(linkage, (r'MachO')) + self.assertRegex(linkage, (r'32bit|64bit')) + self.assertRegex(linkage, (r'ppc|i386|ppc64|x86_64')) + def test_dist(self): res = platform.dist()