From ad15bc4b47a02fa71d2705fd96f896950d2aa881 Mon Sep 17 00:00:00 2001 From: Ivan Inozemtsev Date: Tue, 3 Sep 2024 19:53:58 +0000 Subject: [PATCH] Add support for iOS target os - `build/mac/find_sdk.py` can search for iPhone and Watch SDKs and their simulators - `tools/build.py` supports `--os=ios` and `-os=ios_simulator` now. Treating simulator as a separate os to minimize changes and avoid an additional dimension for configs. - `vm-mac-(release|debug)-arm64-try` tryjobs make sure a shared library builds successfully for ios. TEST=ci Change-Id: I76358ec8fd33752260bf0b8462da22a13cd7562e Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/381623 Auto-Submit: Ivan Inozemtsev Commit-Queue: Ryan Macnak Reviewed-by: Alexander Thomas Reviewed-by: Ryan Macnak --- build/config/BUILDCONFIG.gn | 26 ++++++- build/config/compiler/BUILD.gn | 18 ++--- build/config/ios/BUILD.gn | 9 +++ build/config/ios/ios_sdk.gni | 66 +++++++++++++++++ build/mac/find_sdk.py | 32 +++++++-- .../secondary/third_party/libcxxabi/BUILD.gn | 5 +- build/toolchain/mac/BUILD.gn | 72 +++++++++++++++++++ runtime/BUILD.gn | 13 +++- runtime/bin/BUILD.gn | 6 +- tools/bots/test_matrix.json | 41 ++++++++++- tools/gn.py | 12 +++- tools/utils.py | 6 +- 12 files changed, 279 insertions(+), 27 deletions(-) create mode 100644 build/config/ios/BUILD.gn create mode 100644 build/config/ios/ios_sdk.gni diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn index 8022fe525e5..f5a30cc3114 100644 --- a/build/config/BUILDCONFIG.gn +++ b/build/config/BUILDCONFIG.gn @@ -210,13 +210,23 @@ if (current_os == "win") { is_nacl = false is_posix = true is_win = false +} else if (current_os == "ios") { + is_android = false + is_chromeos = false + is_fuchsia = false + is_ios = true + is_linux = false + is_mac = false + is_nacl = false + is_posix = true + is_win = false } # ============================================================================= # BUILD OPTIONS # ============================================================================= -use_flutter_cxx = is_clang && (is_msan || is_tsan) +use_flutter_cxx = is_clang && (is_msan || is_tsan || is_ios) # ============================================================================= # TARGET DEFAULTS @@ -280,6 +290,8 @@ if (is_linux) { _native_compiler_configs += [ "//build/config/linux:sdk" ] } else if (is_mac) { _native_compiler_configs += [ "//build/config/mac:sdk" ] +} else if (is_ios) { + _native_compiler_configs += [ "//build/config/ios:sdk" ] } else if (is_android) { _native_compiler_configs += [ "//build/config/android:sdk" ] } @@ -416,6 +428,18 @@ if (is_win) { } else if (is_mac) { host_toolchain = "//build/toolchain/mac:clang_$host_cpu" set_default_toolchain("//build/toolchain/mac:clang_$current_cpu") +} else if (is_ios) { + import("//build/config/ios/ios_sdk.gni") # For use_ios_simulator + host_toolchain = "//build/toolchain/mac:clang_$host_cpu" + if (use_ios_simulator) { + if (target_cpu == "arm64") { + set_default_toolchain("//build/toolchain/mac:ios_clang_arm64_sim") + } else { + set_default_toolchain("//build/toolchain/mac:ios_clang_x64_sim") + } + } else { + set_default_toolchain("//build/toolchain/mac:ios_clang_arm64") + } } else if (is_fuchsia) { assert(host_cpu == "x64") if (host_os == "linux") { diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn index 29ada988abb..62fffd5f111 100644 --- a/build/config/compiler/BUILD.gn +++ b/build/config/compiler/BUILD.gn @@ -101,13 +101,13 @@ config("compiler") { cflags_objcc += common_flags # Linker warnings. - if (current_cpu != "arm" && !is_mac) { + if (current_cpu != "arm" && !is_mac && !is_ios) { # TODO(jochen): Enable this on ChromeOS on arm. http://crbug.com/356580 ldflags += [ "-Wl,--fatal-warnings" ] } # Enable mitigations for Cortex-A53 Erratum #843419 bug. - if (current_cpu == "arm64" && is_clang && !is_mac) { + if (current_cpu == "arm64" && is_clang && !is_mac && !is_ios) { ldflags += [ "-Wl,--fix-cortex-a53-843419" ] } @@ -166,7 +166,7 @@ config("compiler") { # Mac-specific compiler flags setup. # ---------------------------------- - if (is_mac) { + if (is_mac || is_ios) { # These flags are shared between the C compiler and linker. common_mac_flags = [] @@ -249,7 +249,7 @@ config("compiler") { ] } - if (is_android || is_linux || is_mac || is_fuchsia) { + if (is_android || is_linux || is_mac || is_ios || is_fuchsia) { if (use_flutter_cxx) { # shared_library_config isn't transitive, so we don't automatically get # another versions of libcxx with and without -fPIC. Properly setting this @@ -391,17 +391,17 @@ config("compiler") { # changes since artifacts from an older version of the toolchain may or may # not be compatible with newer ones. To achieve this, we insert a synthetic # define into the compile line. - if (is_clang && (is_linux || is_mac) && dart_sysroot != "alpine") { + if (is_clang && (is_linux || is_mac || is_ios) && dart_sysroot != "alpine") { if (is_linux && host_cpu == "arm64") { toolchain_stamp_file = "//buildtools/linux-arm64/clang/.versions/clang.cipd_version" } else if (is_linux) { toolchain_stamp_file = "//buildtools/linux-x64/clang/.versions/clang.cipd_version" - } else if (is_mac && host_cpu == "arm64") { + } else if ((is_mac || is_ios) && host_cpu == "arm64") { toolchain_stamp_file = "//buildtools/mac-arm64/clang/.versions/clang.cipd_version" - } else if (is_mac) { + } else if (is_mac || is_ios) { toolchain_stamp_file = "//buildtools/mac-x64/clang/.versions/clang.cipd_version" } @@ -649,7 +649,7 @@ if (is_win) { ] } - if (is_mac) { + if (is_mac || is_ios) { # TODO(abarth): Re-enable once https://github.com/domokit/mojo/issues/728 # is fixed. # default_warning_flags += [ "-Wnewline-eof" ] @@ -825,7 +825,7 @@ if (is_win) { ] } - if (is_mac) { + if (is_mac || is_ios) { # Mac dead code stripping requires symbols. common_optimize_on_ldflags += [ "-Wl,-dead_strip" ] } else { diff --git a/build/config/ios/BUILD.gn b/build/config/ios/BUILD.gn new file mode 100644 index 00000000000..d8a577b5690 --- /dev/null +++ b/build/config/ios/BUILD.gn @@ -0,0 +1,9 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +import("//build/config/sysroot.gni") +import("../clang/clang.gni") + +config("sdk") { + # We statically link a libcxx built from source on iOS. +} diff --git a/build/config/ios/ios_sdk.gni b/build/config/ios/ios_sdk.gni new file mode 100644 index 00000000000..4ee46a366e9 --- /dev/null +++ b/build/config/ios/ios_sdk.gni @@ -0,0 +1,66 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//build/toolchain/rbe.gni") + +declare_args() { + # SDK path to use. When empty this will use the default SDK based on the + # value of use_ios_simulator. + ios_sdk_path = "" + + # Set to true when targeting a simulator build on iOS. False means that the + # target is for running on the device. The default value is to use the + # Simulator except when targeting GYP's Xcode builds (for compat with the + # existing GYP build). + use_ios_simulator = false + + # Minimum supported version of the iOS SDK. + ios_sdk_min = "12.0" + + # The path to the iOS device SDK. + ios_device_sdk_path = "" + + # The path to the iOS simulator SDK. + ios_simulator_sdk_path = "" + + ios_enable_relative_sdk_path = use_rbe +} + +if (ios_sdk_path == "") { + _find_sdk_args = [ + "--print_sdk_path", + ios_sdk_min, + ] + + if (use_rbe) { + _find_sdk_args += [ + "--create_symlink_at", + + # $root_build_dir starts with "//", which is removed by rebase_path(). + rebase_path("$root_build_dir/sdk/xcode_links", "//"), + ] + } + + if (use_ios_simulator && ios_simulator_sdk_path == "") { + _find_sdk_args += [ "--platform=iphone_simulator" ] + _find_sdk_result = + exec_script("//build/mac/find_sdk.py", _find_sdk_args, "list lines") + ios_simulator_sdk_path = _find_sdk_result[0] + } + + if (!use_ios_simulator && ios_device_sdk_path == "") { + _find_sdk_args += [ "--platform=iphone" ] + _find_sdk_result = + exec_script("//build/mac/find_sdk.py", _find_sdk_args, "list lines") + ios_device_sdk_path = _find_sdk_result[0] + } + + if (use_ios_simulator) { + assert(ios_simulator_sdk_path != "") + ios_sdk_path = ios_simulator_sdk_path + } else { + assert(ios_device_sdk_path != "") + ios_sdk_path = ios_device_sdk_path + } +} diff --git a/build/mac/find_sdk.py b/build/mac/find_sdk.py index 0b2c46b5325..04a06f93432 100755 --- a/build/mac/find_sdk.py +++ b/build/mac/find_sdk.py @@ -34,7 +34,7 @@ def CreateSymlinkForSDKAt(src, dst): dst = os.path.join(ROOT_SRC_DIR, dst) if not os.path.isdir(dst): - os.makedirs(dst) + os.makedirs(dst, exist_ok=True) dst = os.path.join(dst, os.path.basename(src)) @@ -85,6 +85,16 @@ def main(): help= "Create symlink to SDK at given location and return symlink path as SDK " "info instead of the original location.") + parser.add_option("--platform", + action="store", + type="choice", + choices=[ + "mac", "iphone", "iphone_simulator", "watch", + "watch_simulator" + ], + dest="platform", + default="mac", + help="SDK Platform") (options, args) = parser.parse_args() min_sdk_version = args[0] @@ -92,20 +102,28 @@ def main(): stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + platform = { + 'mac': 'MacOSX', + 'iphone': 'iPhoneOS', + 'iphone_simulator': 'iPhoneSimulator', + 'watch': 'WatchOS', + 'watch_simulator': 'WatchSimulator' + }[options.platform] out, err = job.communicate() if job.returncode != 0: print(out, file=sys.stderr) print(err, file=sys.stderr) raise Exception('Error %d running xcode-select' % job.returncode) sdk_dir = os.path.join(out.rstrip(), - 'Platforms/MacOSX.platform/Developer/SDKs') + f'Platforms/{platform}.platform/Developer/SDKs') if not os.path.isdir(sdk_dir): raise Exception( 'Install Xcode, launch it, accept the license ' + 'agreement, and run `sudo xcode-select -s /path/to/Xcode.app` ' + 'to continue.') sdks = [ - re.findall('^MacOSX(\d+\.\d+)\.sdk$', s) for s in os.listdir(sdk_dir) + re.findall(fr'^{platform}(\d+\.\d+)\.sdk$', s) + for s in os.listdir(sdk_dir) ] sdks = [s[0] for s in sdks if s] # [['10.5'], ['10.6']] => ['10.5', '10.6'] sdks = [ @@ -130,9 +148,11 @@ Either install it, or explicitly set mac_sdk in your GYP_DEFINES. return min_sdk_version if options.print_sdk_path: - sdk_path = subprocess.check_output( - ['xcodebuild', '-version', '-sdk', 'macosx' + best_sdk, 'Path'], - universal_newlines=True).strip() + sdk_path = subprocess.check_output([ + 'xcodebuild', '-version', '-sdk', + platform.lower() + best_sdk, 'Path' + ], + universal_newlines=True).strip() if options.create_symlink_at: print(CreateSymlinkForSDKAt(sdk_path, options.create_symlink_at)) else: diff --git a/build/secondary/third_party/libcxxabi/BUILD.gn b/build/secondary/third_party/libcxxabi/BUILD.gn index 7a101ac04ea..a086276cc2e 100644 --- a/build/secondary/third_party/libcxxabi/BUILD.gn +++ b/build/secondary/third_party/libcxxabi/BUILD.gn @@ -57,7 +57,6 @@ source_set("libcxxabi") { "src/cxa_exception_storage.cpp", "src/cxa_handlers.cpp", "src/cxa_personality.cpp", - "src/cxa_thread_atexit.cpp", "src/cxa_vector.cpp", "src/cxa_virtual.cpp", "src/fallback_malloc.cpp", @@ -70,4 +69,8 @@ source_set("libcxxabi") { if (!(is_tsan && is_linux)) { sources += [ "src/cxa_guard.cpp" ] } + + if (is_fuchsia || (is_posix && !is_ios && !is_macos)) { + sources += [ "src/cxa_thread_atexit.cpp" ] + } } diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn index 21a228cfc31..e0310ef0bf0 100644 --- a/build/toolchain/mac/BUILD.gn +++ b/build/toolchain/mac/BUILD.gn @@ -6,6 +6,7 @@ # some enhancements since the commands on Mac are slightly different than on # Linux. +import("//build/config/ios/ios_sdk.gni") import("//build/config/mac/mac_sdk.gni") assert(host_os == "mac") @@ -269,6 +270,77 @@ template("mac_toolchain") { } } +# Toolchain used for iOS device targets. +mac_toolchain("ios_clang_arm64") { + toolchain_cpu = "arm64" + toolchain_os = "mac" + prefix = rebased_clang_dir + cc = "${compiler_prefix}${prefix}/clang" + cxx = "${compiler_prefix}${prefix}/clang++" + if (use_rbe) { + cc = "${cc} --target=arm64-apple-darwin" + cxx = "${cxx} --target=arm64-apple-darwin" + } + asm = "${assembler_prefix}${prefix}/clang" + ar = "${prefix}/llvm-ar" + ld = "${link_prefix}${prefix}/clang++" + strip = "${prefix}/llvm-strip" + nm = "${prefix}/llvm-nm" + is_clang = true + if (ios_enable_relative_sdk_path) { + ios_sdk_path = rebase_path(ios_sdk_path, root_build_dir) + } + sysroot_flags = "-isysroot $ios_sdk_path -miphoneos-version-min=$ios_sdk_min" +} + +# Toolchain used for iOS simulator targets (arm64). +mac_toolchain("ios_clang_arm64_sim") { + toolchain_cpu = "arm64" + toolchain_os = "mac" + prefix = rebased_clang_dir + cc = "${compiler_prefix}${prefix}/clang" + cxx = "${compiler_prefix}${prefix}/clang++" + if (use_rbe) { + cc = "${cc} --target=arm64-apple-darwin" + cxx = "${cxx} --target=arm64-apple-darwin" + } + asm = "${assembler_prefix}${prefix}/clang" + ar = "${prefix}/llvm-ar" + ld = "${link_prefix}${prefix}/clang++" + strip = "${prefix}/llvm-strip" + nm = "${prefix}/llvm-nm" + is_clang = true + if (ios_enable_relative_sdk_path) { + ios_sdk_path = rebase_path(ios_sdk_path, root_build_dir) + } + sysroot_flags = + "-isysroot $ios_sdk_path -mios-simulator-version-min=$ios_sdk_min" +} + +# Toolchain used for iOS simulator targets (x64). +mac_toolchain("ios_clang_x64_sim") { + toolchain_cpu = "x64" + toolchain_os = "mac" + prefix = rebased_clang_dir + cc = "${compiler_prefix}${prefix}/clang" + cxx = "${compiler_prefix}${prefix}/clang++" + if (use_rbe) { + cc = "${cc} --target=x86_64-apple-darwin" + cxx = "${cxx} --target=x86_64-apple-darwin" + } + asm = "${assembler_prefix}${prefix}/clang" + ar = "${prefix}/llvm-ar" + ld = "${link_prefix}${prefix}/clang++" + strip = "${prefix}/llvm-strip" + nm = "${prefix}/llvm-nm" + is_clang = true + if (ios_enable_relative_sdk_path) { + ios_sdk_path = rebase_path(ios_sdk_path, root_build_dir) + } + sysroot_flags = + "-isysroot $ios_sdk_path -mios-simulator-version-min=$ios_sdk_min" +} + mac_toolchain("clang_x64") { toolchain_cpu = "x64" toolchain_os = "mac" diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 90dfa343e31..4ee557c1a78 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -60,7 +60,7 @@ config("dart_precompiled_runtime_config") { } config("add_empty_macho_section_config") { - if (is_mac) { + if (is_mac || is_ios) { # We create an empty __space_for_note section in a __CUSTOM segment to # reserve the header space needed for inserting a snapshot into the # executable when creating standalone executables. This segment and section @@ -330,6 +330,17 @@ library_for_all_configs("libdart") { ] } +shared_library("dart_jit_library") { + output_name = "dart_jit" + ldflags = [ "-Wl,-install_name,@rpath/Dart.framework/Dart" ] + public = [ "include/dart_api.h" ] + deps = [ ":libdart_jit" ] + public_configs = [ + ":dart_public_config", + ":dart_shared_lib", + ] +} + action("generate_version_cc_file") { inputs = [ "../tools/utils.py", diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn index a284e70de56..b2582caf52f 100644 --- a/runtime/bin/BUILD.gn +++ b/runtime/bin/BUILD.gn @@ -38,7 +38,7 @@ config("export_api_symbols") { } else if (is_asan || is_lsan || is_msan || is_tsan || is_ubsan) { # Export everything so the sanitizers can intercept whatever they want. ldflags = [ "-rdynamic" ] - } else if (is_mac) { + } else if (is_mac || is_ios) { ldflags = [ "-Wl,-exported_symbol", "-Wl,_Dart_*", @@ -251,7 +251,7 @@ template("build_gen_snapshot") { deps = [ ":${target_name}_set" ] + extra_deps - if (is_mac) { + if (is_mac || is_ios) { frameworks = [ "CoreFoundation.framework", "CoreServices.framework", @@ -465,7 +465,7 @@ template("dart_io") { "Foundation.framework", ] - if (is_mac) { + if (is_mac || is_ios) { frameworks += [ "CoreServices.framework" ] } } diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index c098873b6c3..fdc7bcf47e1 100644 --- a/tools/bots/test_matrix.json +++ b/tools/bots/test_matrix.json @@ -976,8 +976,6 @@ "vm-linux-debug-ia32", "vm-linux-release-ia32", "vm-linux-release-x64", - "vm-mac-debug-arm64", - "vm-mac-release-arm64", "vm-win-debug-x64", "vm-win-release-ia32", "vm-win-release-x64" @@ -1008,6 +1006,45 @@ } ] }, + { + "builders": [ + "vm-mac-debug-arm64", + "vm-mac-release-arm64" + ], + "meta": { + "description": "This configuration is used by the VM JIT builders on mac arm64. Includes VM service testing and building shared libraries for iOS target." + }, + "steps": [ + { + "name": "build dart", + "script": "tools/build.py", + "arguments": [ + "--codesigning-identity=-", + "runtime" + ] + }, + { + "name": "vm tests", + "arguments": [ + "-nvm-${system}-${mode}-${arch}", + "--default-suites", + "co19", + "pkg/pkg/vm_service/" + ], + "fileset": "vm", + "shards": 16 + }, + { + "name": "build iOS shared library", + "script": "tools/build.py", + "arguments": [ + "--codesigning-identity=-", + "--os=ios", + "runtime:dart_jit_library" + ] + } + ] + }, { "builders": [ "vm-linux-debug-simriscv64", diff --git a/tools/gn.py b/tools/gn.py index 9dc23863341..a9f4a14e729 100755 --- a/tools/gn.py +++ b/tools/gn.py @@ -196,6 +196,9 @@ def ToGnArgs(args, mode, arch, target_os, sanitizer, verify_sdk_hash, host_os = HostOsForGn(HOST_OS) if target_os == 'host': gn_args['target_os'] = host_os + elif target_os == 'ios_simulator': + gn_args['target_os'] = 'ios' + gn_args['use_ios_simulator'] = True else: gn_args['target_os'] = target_os @@ -354,7 +357,8 @@ def ProcessOptions(args): oses = [ProcessOsOption(os_name) for os_name in args.os] for os_name in oses: if not os_name in [ - 'android', 'freebsd', 'linux', 'macos', 'win32', 'fuchsia' + 'android', 'freebsd', 'linux', 'macos', 'win32', 'fuchsia', + 'ios', 'ios_simulator' ]: print("Unknown os %s" % os_name) return False @@ -389,6 +393,10 @@ def ProcessOptions(args): "Cross-compilation to %s is not supported for architecture %s." % (os_name, arch)) return False + elif os_name == 'ios' or os_name == 'ios_simulator': + if not HOST_OS in ['macos']: + print(f'Target os {os_name} is only supported on macOS') + return False elif os_name != HOST_OS: print("Unsupported target os %s" % os_name) return False @@ -557,7 +565,7 @@ def AddCommonConfigurationArgs(parser): parser.add_argument('--os', type=str, help='Target OSs (comma-separated).', - metavar='[all,host,android,fuchsia]', + metavar='[all,host,android,fuchsia,ios,ios_simulator]', default='host') parser.add_argument('--sanitizer', type=str, diff --git a/tools/utils.py b/tools/utils.py index d3b38c5090e..2886fa8f814 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -335,8 +335,10 @@ def IsCrossBuild(target_os, arch): def GetBuildConf(mode, arch, conf_os=None, sanitizer=None): if conf_os is not None and conf_os != GuessOS() and conf_os != 'host': - return '{}{}{}'.format(GetBuildMode(mode), conf_os.title(), - arch.upper()) + os_fragment = conf_os.title() + if (conf_os == 'ios_simulator'): + os_fragment = 'IosSim' + return '{}{}{}'.format(GetBuildMode(mode), os_fragment, arch.upper()) # Ask for a cross build if the host and target architectures don't match. cross_build = ''