From b3cab4081c846255f8a2b06949118d6adab8efe7 Mon Sep 17 00:00:00 2001 From: Katie Mancini Date: Tue, 3 Jan 2023 13:32:41 -0800 Subject: [PATCH] properly distringuish arm and intel macs Summary: M1 macbooks appear to have a default system Python3 version of 3.8.x, with a "universal" executable that incorrectly reports the platform (`platform.machine()`) as `x86_64`. This causes Watchman's `./autogen.sh` which uses `getdeps.py build` to try to build for `x86_64`, which eventually causes linker errors with pre-installed dependencies eg `building for macOS-x86_64 but attempting to link with file built for macOS-arm64`. See also https://github.com/pyinstaller/pyinstaller/issues/5315 PR: https://github.com/facebook/watchman/pull/1081 attempted to resolve by noting a higher python version where platform.machine() does the right thing. We can work around this though by using `os.uname()` which correctly distinguishes intel and M1. ``` > python3 >>> platform.machine() 'x86_64' >>> os.uname().version 'Darwin Kernel Version 21.6.0: Thu Sep 29 20:13:56 PDT 2022; root:xnu-8020.240.7~1/RELEASE_ARM64_T6000' ``` Reviewed By: mshroyer Differential Revision: D42182936 fbshipit-source-id: 0d0484a86600da102450e9035c621c01d250cbf7 --- build/fbcode_builder/getdeps/platform.py | 34 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/build/fbcode_builder/getdeps/platform.py b/build/fbcode_builder/getdeps/platform.py index edce96c3b..fc0521414 100644 --- a/build/fbcode_builder/getdeps/platform.py +++ b/build/fbcode_builder/getdeps/platform.py @@ -3,6 +3,7 @@ # This source code is licensed under the MIT license found in the # LICENSE file in the root directory of this source tree. +import os import platform import re import shlex @@ -186,8 +187,23 @@ def get_available_ram() -> int: ) +def is_current_host_arm() -> bool: + if sys.platform.startswith("darwin"): + # platform.machine() can be fooled by rosetta for python < 3.9.2 + return "ARM64" in os.uname().version + else: + machine = platform.machine().lower() + return "arm" in machine or "aarch" in machine + + class HostType(object): def __init__(self, ostype=None, distro=None, distrovers=None) -> None: + # Maybe we should allow callers to indicate whether this machine uses + # an ARM architecture, but we need to change HostType serialization + # and deserialization in that case and hunt down anywhere that is + # persisting that serialized data. + isarm = False + if ostype is None: distro = None distrovers = None @@ -204,21 +220,29 @@ class HostType(object): else: ostype = sys.platform + isarm = is_current_host_arm() + # The operating system type self.ostype = ostype # The distribution, if applicable self.distro = distro # The OS/distro version if known self.distrovers = distrovers - machine = platform.machine().lower() - if "arm" in machine or "aarch" in machine: - self.isarm = True - else: - self.isarm = False + # Does the CPU use an ARM architecture? ARM includes Apple Silicon + # Macs as well as other ARM systems that might be running Linux or + # something. + self.isarm = isarm def is_windows(self): return self.ostype == "windows" + # is_arm is kinda half implemented at the moment. This method is only + # intended to be used when HostType represents information about the + # current machine we are running on. + # When HostType is being used to enumerate platform types (represent + # information about machine types that we may or may not be running on) + # the result could be nonsense (under the current implementation its always + # false.) def is_arm(self): return self.isarm