From 3c01efcbb07cb1af8da0e13d8edca79457188062 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Tue, 10 May 2022 16:11:53 +0000 Subject: [PATCH] Reland "[build] Fix Android build for ARM64 Mac." Account for simarm_x64 in TargetCpuForArch. TEST=local Bug: https://github.com/dart-lang/sdk/issues/48792 Change-Id: I820cb49ee8925c50196cb2472266f9e248c9089d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/243642 Reviewed-by: Daco Harkes Commit-Queue: Ryan Macnak --- DEPS | 10 +- build/config/android/config.gni | 3 + runtime/platform/globals.h | 10 +- .../vm/compiler/assembler/disassembler_arm.cc | 4 +- runtime/vm/dart.cc | 4 +- runtime/vm/globals.h | 2 +- tools/gn.py | 116 +++++++++++------- tools/utils.py | 70 +++++++---- 8 files changed, 134 insertions(+), 85 deletions(-) diff --git a/DEPS b/DEPS index b6d3a6b5fb7..2075bbbb51b 100644 --- a/DEPS +++ b/DEPS @@ -54,7 +54,7 @@ vars = { # Checkout Android dependencies only on Mac and Linux. "download_android_deps": - "(host_os == mac or host_os == linux) and host_cpu == x64", + "host_os == mac or (host_os == linux and host_cpu == x64)", # Checkout extra javascript engines for testing or benchmarking. # d8, the V8 shell, is always checked out. @@ -528,7 +528,7 @@ deps = { Var("dart_root") + "/third_party/android_tools/ndk": { "packages": [ { - "package": "flutter/android/ndk/${{platform}}", + "package": "flutter/android/ndk/${{os}}-amd64", "version": "version:r21.0.6113669" } ], @@ -539,7 +539,7 @@ deps = { Var("dart_root") + "/third_party/android_tools/sdk/build-tools": { "packages": [ { - "package": "flutter/android/sdk/build-tools/${{platform}}", + "package": "flutter/android/sdk/build-tools/${{os}}-amd64", "version": "version:30.0.1" } ], @@ -550,7 +550,7 @@ deps = { Var("dart_root") + "/third_party/android_tools/sdk/platform-tools": { "packages": [ { - "package": "flutter/android/sdk/platform-tools/${{platform}}", + "package": "flutter/android/sdk/platform-tools/${{os}}-amd64", "version": "version:29.0.2" } ], @@ -572,7 +572,7 @@ deps = { Var("dart_root") + "/third_party/android_tools/sdk/tools": { "packages": [ { - "package": "flutter/android/sdk/tools/${{platform}}", + "package": "flutter/android/sdk/tools/${{os}}-amd64", "version": "version:26.1.1" } ], diff --git a/build/config/android/config.gni b/build/config/android/config.gni index c61d41acad6..f5def03da64 100644 --- a/build/config/android/config.gni +++ b/build/config/android/config.gni @@ -26,6 +26,9 @@ if (is_android) { # architecture, which is different than the names GN uses. if (host_cpu == "x64" || host_cpu == "x86") { android_host_arch = "x86_64" + } else if (host_cpu == "arm64") { + # Run existing Android toolchain via Rosetta. + android_host_arch = "x86_64" } else { assert(false, "Need Android toolchain support for your build CPU arch.") } diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h index 0f8cabfa900..d71457b27b7 100644 --- a/runtime/platform/globals.h +++ b/runtime/platform/globals.h @@ -339,10 +339,10 @@ struct simd128_value_t { #endif // !defined(ARCH_IS_64_BIT) && !defined(FFI_UNIT_TESTS) #elif defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) || \ defined(TARGET_ARCH_RISCV32) -#if defined(HOST_ARCH_X64) && defined(TARGET_ARCH_ARM) -// This is simarm_x64, which is the only case where host/target architecture -// mismatch is allowed. Unless, we're running FFI unit tests. -#define IS_SIMARM_X64 1 +#if defined(ARCH_IS_64_BIT) && defined(TARGET_ARCH_ARM) +// This is simarm_x64 or simarm_arm64, which is the only case where host/target +// architecture mismatch is allowed. Unless, we're running FFI unit tests. +#define IS_SIMARM_HOST64 1 #elif !defined(ARCH_IS_32_BIT) && !defined(FFI_UNIT_TESTS) #error Mismatched Host/Target architectures. #endif // !defined(ARCH_IS_32_BIT) && !defined(FFI_UNIT_TESTS) @@ -360,7 +360,7 @@ struct simd128_value_t { #elif defined(TARGET_ARCH_ARM) #if !defined(HOST_ARCH_ARM) #define TARGET_HOST_MISMATCH 1 -#if !defined(IS_SIMARM_X64) +#if !defined(IS_SIMARM_HOST64) #define USING_SIMULATOR 1 #endif #endif diff --git a/runtime/vm/compiler/assembler/disassembler_arm.cc b/runtime/vm/compiler/assembler/disassembler_arm.cc index 51bb5687fca..4d860a5a625 100644 --- a/runtime/vm/compiler/assembler/disassembler_arm.cc +++ b/runtime/vm/compiler/assembler/disassembler_arm.cc @@ -1512,14 +1512,14 @@ void Disassembler::DecodeInstruction(char* hex_buffer, *object = NULL; // TODO(36839): Make DecodeLoadObjectFromPoolOrThread work on simarm_x64. -#if !defined(IS_SIMARM_X64) +#if !defined(IS_SIMARM_HOST64) if (!code.IsNull()) { *object = &Object::Handle(); if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { *object = NULL; } } -#endif // !defined(IS_SIMARM_X64) +#endif // !defined(IS_SIMARM_HOST64) } #endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER) diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc index bf4c995ab00..2ccf2151ede 100644 --- a/runtime/vm/dart.cc +++ b/runtime/vm/dart.cc @@ -155,7 +155,7 @@ class DartInitializationState { static DartInitializationState init_state_; static void CheckOffsets() { -#if !defined(IS_SIMARM_X64) +#if !defined(IS_SIMARM_HOST64) // These offsets are embedded in precompiled instructions. We need the // compiler and the runtime to agree. bool ok = true; @@ -241,7 +241,7 @@ static void CheckOffsets() { #undef CHECK_CONSTANT #undef CHECK_OFFSET #undef CHECK_PAYLOAD_SIZEOF -#endif // !defined(IS_SIMARM_X64) +#endif // !defined(IS_SIMARM_HOST64) } char* Dart::DartInit(const Dart_InitializeParams* params) { diff --git a/runtime/vm/globals.h b/runtime/vm/globals.h index c564a48eebc..559dc44b306 100644 --- a/runtime/vm/globals.h +++ b/runtime/vm/globals.h @@ -112,7 +112,7 @@ const intptr_t kDefaultNewGenSemiMaxSize = (kWordSize <= 4) ? 8 : 16; #define SUPPORT_TIMELINE 1 #endif -#if defined(ARCH_IS_64_BIT) && !defined(IS_SIMARM_X64) +#if defined(ARCH_IS_64_BIT) && !defined(IS_SIMARM_HOST64) #define HASH_IN_OBJECT_HEADER 1 #endif diff --git a/tools/gn.py b/tools/gn.py index a89e8a303d0..647f045d061 100755 --- a/tools/gn.py +++ b/tools/gn.py @@ -67,61 +67,82 @@ def ToCommandLine(gn_args): return [merge(x, y) for x, y in gn_args.items()] -# Runs true if the currently executing python interpreter is running under -# Rosetta. I.e., python3 is an x64 executable and we're on an arm64 Mac. -def IsRosetta(): - if platform.system() == 'Darwin': - p = subprocess.Popen(['sysctl', '-in', 'sysctl.proc_translated'], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT) - output, _ = p.communicate() - return output.decode('utf-8').strip() == '1' - return False - - +# The C compiler's host. def HostCpuForArch(arch): - # Check for Rosetta before checking platform.machine(), as the latter - # returns 'x86_64' when running under Rosetta. - if IsRosetta(): - if arch in ['x64', 'x64c']: - # Without this case, we would try to build with - # host_cpu="arm64" - # target_cpu="x64" - # dart_target_arch="x64" - # Which requires the VM to use an x64 simulator in the host - # arm64 binaries, and this simulator is unimplemented. - return 'x64' - else: - return 'arm64' - - m = platform.machine() - if m == 'aarch64' or m == 'arm64': - return 'arm64' - if m == 'armv7l': - return 'arm' - - if arch in ['ia32', 'arm', 'simarm', 'simarm_x64', 'riscv32', 'simriscv32']: - return 'x86' - if arch in [ - 'x64', 'arm64', 'simarm64', 'arm_x64', 'x64c', 'arm64c', - 'simarm64c', 'riscv64', 'simriscv64' - ]: + if arch.endswith('_x64'): return 'x64' + if arch.endswith('_arm64'): + return 'arm64' + if arch.endswith('_riscv64'): + return 'riscv64' + + # For each target architecture, we prefer in descending order + # - using the same architecture for the host (supports all architectures) + # - using a host architecture with the same word size (supports arm and riscv, which have simulators) + # - using a host architecture with a different word size (supports only AOT and only 32-bit target on 64-bit host) + if arch in ['ia32']: + candidates = ['x86'] + elif arch in ['x64', 'x64c']: + candidates = ['x64'] + elif arch in ['arm', 'simarm']: + candidates = ['arm', 'x86', 'riscv32', 'arm64', 'x64', 'riscv64'] + elif arch in ['arm64', 'arm64c', 'simarm64', 'simarm64c']: + candidates = ['arm64', 'x64', 'riscv64'] + elif arch in ['riscv32', 'simriscv32']: + candidates = ['riscv32', 'arm', 'x86', 'riscv64', 'arm64', 'x64'] + elif arch in ['riscv64', 'simriscv64']: + candidates = ['riscv64', 'arm64', 'x64'] + else: + raise Exception("Unknown Dart architecture: %s" % arch) + + available = utils.HostArchitectures() + for candidate in candidates: + if candidate in available: + return candidate + + raise Exception( + "Failed to find a C host architecture for %s. Need one of %s but only %s are available." + % (arch, candidates, available)) # The C compiler's target. def TargetCpuForArch(arch, target_os): - if arch in ['ia32', 'simarm', 'simriscv32']: + # Real target architectures + if arch in ['ia32']: return 'x86' - if arch in [ - 'x64', 'simarm64', 'simarm_x64', 'simriscv64', 'x64c', 'simarm64c' - ]: + elif arch in ['x64', 'x64c']: return 'x64' - if arch == 'arm_x64': + elif arch in ['arm', 'arm_x64', 'arm_arm64', 'arm_riscv64']: return 'arm' - if arch == 'arm64c': + elif arch in ['arm64', 'arm64c']: return 'arm64' - return arch + elif arch in ['riscv32', 'riscv32_x64', 'riscv32_arm64', 'riscv32_riscv64']: + return 'riscv32' + elif arch in ['riscv64']: + return 'riscv64' + + # Simulators + if arch in ['simarm_x64', 'simriscv32_x64']: + return 'x64' + elif arch in ['simarm_arm64', 'simriscv32_arm64']: + return 'arm64' + elif arch in ['simarm_riscv64', 'simriscv32_riscv64']: + return 'riscv64' + elif arch in ['simarm', 'simriscv32']: + candidates = ['arm', 'riscv32', 'x86'] + elif arch in ['simarm64', 'simarm64c', 'simriscv64']: + candidates = ['arm64', 'riscv64', 'x64'] + else: + raise Exception("Unknown Dart architecture: %s" % arch) + + available = utils.HostArchitectures() + for candidate in candidates: + if candidate in available: + return candidate + + raise Exception( + "Failed to find a C target architecture for %s. Need one of %s but only %s are available." + % (arch, candidates, available)) # The Dart compiler's target. @@ -130,7 +151,10 @@ def DartTargetCpuForArch(arch): return 'ia32' if arch in ['x64', 'x64c']: return 'x64' - if arch in ['arm', 'simarm', 'simarm_x64', 'arm_x64']: + if arch in [ + 'arm', 'simarm', 'simarm_x64', 'arm_x64', 'simarm_arm64', + 'arm_arm64' + ]: return 'arm' if arch in ['arm64', 'simarm64', 'arm64c', 'simarm64c']: return 'arm64' diff --git a/tools/utils.py b/tools/utils.py index 2f42263ff9f..d3401f15035 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -67,9 +67,11 @@ ARCH_FAMILY = { 'arm': 'arm', 'arm64': 'arm', 'arm_x64': 'arm', + 'arm_arm64': 'arm', 'simarm': 'ia32', 'simarm64': 'ia32', 'simarm_x64': 'ia32', + 'simarm_arm64': 'arm', 'x64c': 'ia32', 'arm64c': 'arm', 'simarm64c': 'ia32', @@ -149,27 +151,44 @@ def GuessOS(): return None +# Runs true if the currently executing python interpreter is running under +# Rosetta. I.e., python3 is an x64 executable and we're on an arm64 Mac. +def IsRosetta(): + if platform.system() == 'Darwin': + p = subprocess.Popen(['sysctl', '-in', 'sysctl.proc_translated'], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + output, _ = p.communicate() + return output.decode('utf-8').strip() == '1' + return False + + +# Returns the architectures that can run on the current machine. +def HostArchitectures(): + m = platform.machine() + if platform.system() == 'Darwin': + if m == 'arm64' or IsRosetta(): + # ARM64 Macs also support X64. + return ['arm64', 'x64'] + if m == 'x86_64': + # X64 Macs no longer support IA32. + return ['x64'] + else: + if m in ['aarch64', 'arm64', 'arm64e']: + return ['arm64'] + if m in ['armv7l']: + return ['arm'] + if m in ['i386', 'i686', 'ia32', 'x86']: + return ['x86', 'ia32'] + if m in ['x64', 'x86-64', 'x86_64', 'AMD64']: + return ['x64', 'x86', 'ia32'] + raise Exception('Failed to determine host architectures for %s %s', + platform.machine(), platform.system()) + + # Try to guess the host architecture. def GuessArchitecture(): - os_id = platform.machine() - if os_id.startswith('aarch64') or os_id == 'arm64': - return 'arm64' - elif os_id.startswith('arm'): - return 'arm' - elif '64' in os_id: - return 'x64' - elif (not os_id) or (not re.match('(x|i[3-6])86', os_id) is None): - return 'ia32' - elif os_id == 'i86pc': - return 'ia32' - - guess_os = GuessOS() - print('Warning: Guessing architecture {} based on os {}\n'.format( - os_id, guess_os)) - if guess_os == 'win32': - return 'ia32' - return None - + return HostArchitectures()[0] # Try to guess the number of cpus on this machine. def GuessCpus(): @@ -242,9 +261,13 @@ def ListDartArgCallback(option, value, parser): def IsCrossBuild(target_os, arch): - host_arch = GuessArchitecture() - return ((GetArchFamily(host_arch) != GetArchFamily(arch)) or - (target_os != GuessOS())) + if (target_os not in [None, 'host']) and (target_os != GuessOS()): + return True + if arch.startswith('sim'): + return False + if arch in HostArchitectures(): + return False + return True def GetBuildConf(mode, arch, conf_os=None, sanitizer=None): @@ -253,9 +276,8 @@ def GetBuildConf(mode, arch, conf_os=None, sanitizer=None): arch.upper()) # Ask for a cross build if the host and target architectures don't match. - host_arch = GuessArchitecture() cross_build = '' - if GetArchFamily(host_arch) != GetArchFamily(arch): + if IsCrossBuild(conf_os, arch): cross_build = 'X' return '{}{}{}{}'.format(GetBuildMode(mode), GetBuildSanitizer(sanitizer), cross_build, arch.upper())