chromium/build/config/ios/BUILD.gn

# Copyright 2014 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import("//build/config/ios/ios_sdk.gni")
import("//build/toolchain/apple/toolchain.gni")
import("//build/toolchain/rbe.gni")
import("//build/toolchain/siso.gni")
import("//build/toolchain/toolchain.gni")
import("//build_overrides/build.gni")

# This is included by reference in the //build/config/compiler config that
# is applied to all targets. It is here to separate out the logic.
config("compiler") {
  # These flags are shared between the C compiler and linker.
  common_flags = []

  # CPU architecture.
  if (current_cpu == "x64") {
    triplet_cpu = "x86_64"
  } else if (current_cpu == "x86") {
    triplet_cpu = "i386"
  } else if (current_cpu == "arm" || current_cpu == "armv7") {
    triplet_cpu = "armv7"
  } else if (current_cpu == "arm64") {
    triplet_cpu = "arm64"
  } else {
    assert(false, "unsupported cpu: $current_cpu")
  }

  # Environment.
  if (target_environment == "simulator") {
    triplet_environment = "-simulator"
  } else if (target_environment == "device") {
    triplet_environment = ""
  } else if (target_environment == "catalyst") {
    triplet_environment = "-macabi"
  } else {
    assert(false, "unsupported environment: $target_environment")
  }

  # OS.
  triplet_os = "apple-ios"

  # Set target.
  common_flags = [
    "-target",
    "$triplet_cpu-$triplet_os$ios_deployment_target$triplet_environment",
  ]

  # This is here so that all files get recompiled after an Xcode update.
  # (defines are passed via the command line, and build system rebuild things
  # when their commandline changes). Nothing should ever read this define.
  defines = [ "CR_XCODE_VERSION=$xcode_version" ]

  asmflags = common_flags
  cflags = common_flags
  swiftflags = common_flags

  swiftflags += [
    "-swift-version",
    "5",
  ]

  cflags_objcc = [
    # When using -std=c++20 or higher, clang automatically returns true for
    # `__has_feature(modules)` as it enables cxx modules. This is problematic
    # because Objective-C code uses this to detect whether `@import` can be
    # used (this feature is also named modules).
    #
    # Since Chromium does not yet enable cxx modules, nor clang modules,
    # force disable the cxx modules, which cause `__has_features(modules)`
    # to return false unless clang modules are explicitly enabled.
    "-Xclang",
    "-fno-cxx-modules",
  ]
  if (ios_chrome_generate_order_file) {
    cflags_objcc += [ "-fsanitize-coverage=func,trace-pc-guard" ]
  }

  ldflags = common_flags

  # This is on by default in ld64 for our deployment target, but not yet
  # in ld64.lld. Force it on.
  if (ios_deployment_target != "11.0" && ios_deployment_target != "12.0" &&
      ios_deployment_target != "13.0" && ios_deployment_target != "13.4" &&
      ios_deployment_target != "14.0") {
    ldflags += [ "-Wl,-fixup_chains" ]
  }

  if (ios_is_app_extension) {
    ldflags += [ "-fapplication-extension" ]
    cflags += [ "-fapplication-extension" ]
  }
}

# This is included by reference in the //build/config/compiler:runtime_library
# config that is applied to all targets. It is here to separate out the logic
# that is iOS-only. Please see that target for advice on what should go in
# :runtime_library vs. :compiler.
config("runtime_library") {
  # The variable ios_sdk_path is relative to root_build_dir when using RBE
  # and system Xcode (since RBE only supports paths relative to source).
  # Rebase the value in that case since gn does not convert paths in compiler
  # flags (since it is not aware they are paths).
  _sdk_root = ios_sdk_path
  if (ios_use_xcode_symlinks) {
    _sdk_root = rebase_path(ios_sdk_path, root_build_dir)
  }

  common_flags = [
    "-isysroot",
    _sdk_root,
  ]
  swiftflags = [
    "-sdk",
    _sdk_root,
  ]

  if (target_environment == "catalyst") {
    common_flags += [
      "-isystem",
      "$_sdk_root/System/iOSSupport/usr/include",
      "-iframework",
      "$_sdk_root/System/iOSSupport/System/Library/Frameworks",
    ]

    swiftflags += [
      "-isystem",
      "$_sdk_root/System/iOSSupport/usr/include",
      "-Fsystem",
      "$_sdk_root/System/iOSSupport/System/Library/Frameworks",
    ]
  }

  asmflags = common_flags
  cflags = common_flags
  ldflags = common_flags
}

config("ios_executable_flags") {
  ldflags = []

  # On "catalyst", the bundle structure is different (uses the same structure
  # as a regular macOS app), so an additional -rpath is required.
  if (target_environment == "catalyst") {
    ldflags += [ "-Wl,-rpath,@loader_path/../Frameworks" ]
  }

  ldflags += [ "-Wl,-rpath,@executable_path/Frameworks" ]
}

config("ios_extension_executable_flags") {
  configs = default_executable_configs

  ldflags = [
    "-e",
    "_NSExtensionMain",
  ]

  # On "catalyst", the bundle structure is different (uses the same structure
  # as a regular macOS app), so an additional -rpath is required.
  if (target_environment == "catalyst") {
    ldflags += [ "-Wl,-rpath,@loader_path/../../../../Frameworks" ]
  }

  ldflags += [ "-Wl,-rpath,@executable_path/../../Frameworks" ]
}

config("ios_dynamic_flags") {
  ldflags = [
    # Always load Objective-C categories and class.
    "-Wl,-ObjC",
  ]

  # The path to the Swift compatibility libraries (required to run code built
  # with version N of the SDK on older version of the OS) is relative to the
  # toolchains directory and changes with the environment when using the
  # system toolchain. When using the hermetic swift toolchain instead, those
  # libraries are relative to $swift_toolchain_path.
  if (swift_toolchain_path == "") {
    _swift_compatibility_libs_prefix = ios_toolchains_path
  } else {
    _swift_compatibility_libs_prefix = swift_toolchain_path
  }

  if (target_environment == "simulator") {
    _swift_compatibility_libs_suffix = "iphonesimulator"
  } else if (target_environment == "device") {
    _swift_compatibility_libs_suffix = "iphoneos"
  } else if (target_environment == "catalyst") {
    # The Swift compatibility libraries have changed location starting with
    # Xcode 13.0, so check the version of Xcode when deciding which path to
    # use.
    if (xcode_version_int >= 1300) {
      _swift_compatibility_libs_suffix = "macosx"
    } else {
      _swift_compatibility_libs_suffix = "maccatalyst"
    }
  }

  lib_dirs = [
    "$ios_sdk_path/usr/lib/swift",
    "$_swift_compatibility_libs_prefix/usr/lib/swift/" +
        "$_swift_compatibility_libs_suffix",
  ]

  # When building for catalyst, some Swift support libraries are in a
  # different directory which needs to be added to the search path.
  if (target_environment == "catalyst") {
    lib_dirs += [ "$ios_sdk_path/System/iOSSupport/usr/lib/swift" ]
  }
}

config("ios_shared_library_flags") {
  ldflags = [
    "-Wl,-rpath,@executable_path/Frameworks",
    "-Wl,-rpath,@loader_path/Frameworks",
  ]
}

config("xctest_config") {
  # Add some directories to the system framework search path to make
  # them available to the compiler while silencing warnings in the
  # framework headers. This is required for XCTest.
  common_flags = [
    "-iframework",
    rebase_path("$ios_sdk_platform_path/Developer/Library/Frameworks",
                root_build_dir),
    "-iframework",
    rebase_path("$ios_sdk_path/Developer/Library/Frameworks", root_build_dir),
  ]
  cflags = common_flags
  ldflags = common_flags
  swiftflags = common_flags

  include_dirs = [ "$ios_sdk_platform_path/Developer/usr/lib" ]
  lib_dirs = [ "$ios_sdk_platform_path/Developer/usr/lib" ]
  frameworks = [
    "Foundation.framework",
    "XCTest.framework",
  ]
}

# TODO(crbug.com/40911785): any target that uses this config will miscompile.
# This needs to be fixed if we want to use Swift - C++ interop.
config("enable_swift_cxx_interop") {
  swiftflags = [ "-enable-experimental-cxx-interop" ]
}

group("xctest") {
  public_configs = [ ":xctest_config" ]
}

_xctrunner_path =
    "$ios_sdk_platform_path/Developer/Library/Xcode/Agents/XCTRunner.app"

# When building with RBE, $ios_sdk_platform_path corresponds to a symlink
# below $root_build_dir that points to the real SDK to use. Because the files
# are below $root_build_dir, it is not possible to list them as a target input
# without gn complaining (as it can't find a target creating those files).
#
# The symlinks are created by //build/config/apple/sdk_info.py script invoked
# via exec_script() from //build/config/{ios/ios_sdk.gni,mac/mac_sdk.gni}.
# As the invocation is done by exec_script, there is no target that can list
# those files as output.
#
# To workaround this, add a target that pretends to create those files
# (but does nothing). See https://crbug.com/1061487 for why this is needed.
if (ios_use_xcode_symlinks) {
  action("copy_xctrunner_app") {
    testonly = true
    script = "//build/noop.py"
    outputs = [
      "$_xctrunner_path/Info.plist",
      "$_xctrunner_path/PkgInfo",
      "$_xctrunner_path/XCTRunner",
    ]
  }
}

# When creating the test runner for an XCUITest, the arm64e slice of the binary
# must be removed (at least until the app ships with arm64e slice which is not
# yet supported by Apple).
action("xctest_runner_without_arm64e") {
  testonly = true
  script = "//build/config/ios/strip_arm64e.py"
  sources = [ "$_xctrunner_path/XCTRunner" ]
  outputs = [ "$target_out_dir/XCTRunner" ]
  args = [
    "--output",
    rebase_path(outputs[0], root_build_dir),
    "--input",
    rebase_path(sources[0], root_build_dir),
    "--xcode-version",
    xcode_version,
  ]

  # When running under ASan, the ASan runtime library must be packaged alongside
  # the test runner binary.
  deps = [ "//build/config/sanitizers:deps" ]
  if (ios_use_xcode_symlinks) {
    deps += [ ":copy_xctrunner_app" ]
  }
}