2

When running a Python universal binary (x86_64, arm64), how can I check from within Python whether it is running the x86_64 or arm64 executable? It seems that os.uname() and platform.machine() would always give the actual system architecture (i.e. "arm64"), and sysconfig.get_platform() would always give "universal2" (also not helping).

So how to tell the difference between Python being run as python3 or arch -x86_64 python3?

Florian Krause
  • 183
  • 1
  • 2
  • 8
  • You can get a lot of info like this: `import sysconfig, pprint; pprint.pprint(sysconfig.get_config_vars())` which will tell you information about how the current python executable was built. – flakes Mar 20 '22 at 15:43
  • Specifically, HOST_GNU_TYPE, MACHDEP, and MULTIARCH keys look useful. – flakes Mar 20 '22 at 15:46
  • Thanks for pointing me to these. The problem is that I don't have access to an M1 Mac, so I cannot verify what they say. On my Intel Mac, only HOST_GNU_TYPE includes an architecture (but again, I don't know if this is from the machine, or from the running interpreter). – Florian Krause Mar 20 '22 at 19:33
  • Mmh, this here states that Rosetta actually changes what `uname` returns: https://indiespark.top/software/detecting-apple-silicon-shell-script/. This implies that if I call `platform.machine()`, which under the hood just calls `uname -m`, would return the right thing, because it is called from the Python process that is run with Rosetta... – Florian Krause Mar 20 '22 at 19:51
  • `import sysconfig; sysconfig.get_config_vars()['HOST_GNU_TYPE']` should print something like 'arm64-apple-darwin20.0.0' on Apple Silicon, not running under Rosetta 2 x86 emulation. – Henk Poley Aug 28 '22 at 04:00

1 Answers1

2

Okay, I think the following function should report the correct machine architectures (i.e. that of the running interpreter, not that of the system), also for other OS:

def get_platform():
"""Return a string with current platform (system and machine architecture).

This attempts to improve upon `sysconfig.get_platform` by fixing some
issues when running a Python interpreter with a different architecture than
that of the system (e.g. 32bit on 64bit system, or a multiarch build),
which should return the machine architecture of the currently running
interpreter rather than that of the system (which didn't seem to work
properly). The reported machine architectures follow platform-specific
naming conventions (e.g. "x86_64" on Linux, but "x64" on Windows).

Example output strings for common platforms:

    darwin_(ppc|ppc64|i368|x86_64|arm64)
    linux_(i686|x86_64|armv7l|aarch64)
    windows_(x86|x64|arm32|arm64)

"""

system = platform.system().lower()
machine = sysconfig.get_platform().split("-")[-1].lower()
is_64bit = sys.maxsize > 2 ** 32

if system == "darwin": # get machine architecture of multiarch binaries
    if any([x in machine for x in ("fat", "intel", "universal")]):
        machine = platform.machine().lower()

elif system == "linux":  # fix running 32bit interpreter on 64bit system
    if not is_64bit and machine == "x86_64":
        machine = "i686"
    elif not is_64bit and machine == "aarch64":
            machine = "armv7l"

elif system == "windows": # return more precise machine architecture names
    if machine == "amd64":
        machine = "x64"
    elif machine == "win32":
        if is_64bit:
            machine = platform.machine().lower()
        else:
            machine = "x86"

# some more fixes based on examples in https://en.wikipedia.org/wiki/Uname
if not is_64bit and machine in ("x86_64", "amd64"):
    if any([x in system for x in ("cygwin", "mingw", "msys")]):
        machine = "i686"
    else:
        machine = "i386"

return f"{system}_{machine}"

I unfortunately don't have access to a M1 Mac to double check. If someone could confirm that this works, that would be great.

Florian Krause
  • 183
  • 1
  • 2
  • 8