diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:47:29 +0000 |
commit | 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch) | |
tree | a31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/libwebrtc/build/config/ios/rules.gni | |
parent | Initial commit. (diff) | |
download | firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip |
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/build/config/ios/rules.gni')
-rw-r--r-- | third_party/libwebrtc/build/config/ios/rules.gni | 2173 |
1 files changed, 2173 insertions, 0 deletions
diff --git a/third_party/libwebrtc/build/config/ios/rules.gni b/third_party/libwebrtc/build/config/ios/rules.gni new file mode 100644 index 0000000000..04d605dd97 --- /dev/null +++ b/third_party/libwebrtc/build/config/ios/rules.gni @@ -0,0 +1,2173 @@ +# 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/apple/apple_info_plist.gni") +import("//build/config/apple/symbols.gni") +import("//build/config/ios/ios_sdk.gni") +import("//build/toolchain/goma.gni") +import("//build/toolchain/toolchain.gni") +import("//build_overrides/build.gni") + +declare_args() { + # Set to true if an Xcode project is generated for this build. Set this to + # false if you do not plan to run `gn gen --ide=xcode` in this directory. + # This will speed up the generation at the cost of generating an invalid + # Xcode project if `gn gen --ide=xcode` is used. Defaults to true (favor + # correctness over speed). + ios_set_attributes_for_xcode_project_generation = true +} + +# Constants corresponding to the bundle type identifiers use application, +# application extension, XCTest and XCUITest targets respectively. +_ios_xcode_app_bundle_id = "com.apple.product-type.application" +_ios_xcode_appex_bundle_id = "com.apple.product-type.app-extension" +_ios_xcode_xctest_bundle_id = "com.apple.product-type.bundle.unit-test" +_ios_xcode_xcuitest_bundle_id = "com.apple.product-type.bundle.ui-testing" + +# Invokes lipo on multiple arch-specific binaries to create a fat binary. +# +# Arguments +# +# arch_binary_target +# name of the target generating the arch-specific binaries, they must +# be named $target_out_dir/$toolchain_cpu/$arch_binary_output. +# +# arch_binary_output +# (optional, defaults to the name of $arch_binary_target) base name of +# the arch-specific binary generated by arch_binary_target. +# +# output_name +# (optional, defaults to $target_name) base name of the target output, +# the full path will be $target_out_dir/$output_name. +# +# configs +# (optional) a list of configurations, this is used to check whether +# the binary should be stripped, when "enable_stripping" is true. +# +template("lipo_binary") { + assert(defined(invoker.arch_binary_target), + "arch_binary_target must be defined for $target_name") + + assert(!is_fat_secondary_toolchain, + "lipo_binary can only be used in the primary toolchain of a fat build") + + _target_name = target_name + _output_name = target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + _all_target_cpu = [ target_cpu ] + additional_target_cpus + _all_toolchains = [ current_toolchain ] + additional_toolchains + + _arch_binary_target = invoker.arch_binary_target + _arch_binary_output = get_label_info(_arch_binary_target, "name") + if (defined(invoker.arch_binary_output)) { + _arch_binary_output = invoker.arch_binary_output + } + + action(_target_name) { + forward_variables_from(invoker, + "*", + [ + "arch_binary_output", + "arch_binary_target", + "configs", + "output_name", + ]) + + script = "//build/toolchain/apple/linker_driver.py" + + # http://crbug.com/762840. Fix for bots running out of memory. + pool = "//build/toolchain:link_pool($default_toolchain)" + + outputs = [ "$target_out_dir/$_output_name" ] + + deps = [] + _index = 0 + inputs = [] + foreach(_cpu, _all_target_cpu) { + _toolchain = _all_toolchains[_index] + _index = _index + 1 + + inputs += + [ get_label_info("$_arch_binary_target($_toolchain)", + "target_out_dir") + "/$_cpu/$_arch_binary_output" ] + + deps += [ "$_arch_binary_target($_toolchain)" ] + } + + args = [ + "xcrun", + "lipo", + "-create", + "-output", + rebase_path("$target_out_dir/$_output_name", root_build_dir), + ] + rebase_path(inputs, root_build_dir) + + if (enable_dsyms) { + _dsyms_output_dir = "$root_out_dir/$_output_name.dSYM" + outputs += [ + "$_dsyms_output_dir/", + "$_dsyms_output_dir/Contents/Info.plist", + "$_dsyms_output_dir/Contents/Resources/DWARF/$_output_name", + ] + args += [ "-Wcrl,dsym," + rebase_path("$root_out_dir/.", root_build_dir) ] + if (!use_xcode_clang) { + args += [ "-Wcrl,dsymutilpath," + + rebase_path("//tools/clang/dsymutil/bin/dsymutil", + root_build_dir) ] + } + } + + if (enable_stripping) { + args += [ "-Wcrl,strip,-x,-S" ] + if (save_unstripped_output) { + outputs += [ "$root_out_dir/$_output_name.unstripped" ] + args += [ "-Wcrl,unstripped," + + rebase_path("$root_out_dir/.", root_build_dir) ] + } + } + } +} + +# Wrapper around create_bundle taking care of code signature settings. +# +# Arguments +# +# product_type +# string, product type for the generated Xcode project. +# +# bundle_gen_dir +# (optional) directory where the bundle is generated; must be below +# root_out_dir and defaults to root_out_dir if omitted. +# +# bundle_deps +# (optional) list of additional dependencies. +# +# bundle_deps_filter +# (optional) list of dependencies to filter (for more information +# see "gn help bundle_deps_filter"). +# +# bundle_extension +# string, extension of the bundle, used to generate bundle name. +# +# bundle_binary_target +# (optional) string, label of the target generating the bundle main +# binary. This target and bundle_binary_path are mutually exclusive. +# +# bundle_binary_output +# (optional) string, base name of the binary generated by the +# bundle_binary_target target, defaults to the target name. +# +# bundle_binary_path +# (optional) string, path to the bundle main binary. This target and +# bundle_binary_target are mutually exclusive. +# +# output_name: +# (optional) string, name of the generated application, if omitted, +# defaults to the target_name. +# +# extra_system_frameworks +# (optional) list of system framework to copy to the bundle. +# +# enable_code_signing +# (optional) boolean, control whether code signing is enabled or not, +# default to ios_enable_code_signing if not defined. +# +# entitlements_path: +# (optional) path to the template to use to generate the application +# entitlements by performing variable substitutions, defaults to +# //build/config/ios/entitlements.plist. +# +# entitlements_target: +# (optional) label of the target generating the application +# entitlements (must generate a single file as output); cannot be +# defined if entitlements_path is set. +# +# has_public_headers: +# (optional) boolean, defaults to false; only meaningful if the bundle +# is a framework bundle; if true, then the frameworks includes public +# headers +# +# disable_entitlements +# (optional, defaults to false) boolean, control whether entitlements willi +# be embedded in the application during signature. If false and no +# entitlements are provided, default empty entitlements will be used. +# +# disable_embedded_mobileprovision +# (optional, default to false) boolean, control whether mobile provisions +# will be embedded in the bundle. If true, the existing +# embedded.mobileprovision will be deleted. +# +# xcode_extra_attributes +# (optional) scope, extra attributes for Xcode projects. +# +# xcode_test_application_name: +# (optional) string, name of the test application for Xcode unit or ui +# test target. +# +# xcode_product_bundle_id: +# (optional) string, the bundle ID that will be added in the XCode +# attributes to enable some features when debugging (e.g. MetricKit). +# +# primary_info_plist: +# (optional) path to Info.plist to merge with the $partial_info_plist +# generated by the compilation of the asset catalog. +# +# partial_info_plist: +# (optional) path to the partial Info.plist generated by the asset +# catalog compiler; if defined $primary_info_plist must also be defined. +# +template("create_signed_bundle") { + assert(defined(invoker.product_type), + "product_type must be defined for $target_name") + assert(defined(invoker.bundle_extension), + "bundle_extension must be defined for $target_name") + assert(defined(invoker.bundle_binary_target) != + defined(invoker.bundle_binary_path), + "Only one of bundle_binary_target or bundle_binary_path may be " + + "specified for $target_name") + assert(!defined(invoker.partial_info_plist) || + defined(invoker.primary_info_plist), + "primary_info_plist must be defined when partial_info_plist is " + + "defined for $target_name") + + if (defined(invoker.xcode_test_application_name)) { + assert( + invoker.product_type == _ios_xcode_xctest_bundle_id || + invoker.product_type == _ios_xcode_xcuitest_bundle_id, + "xcode_test_application_name can be only defined for Xcode unit or ui test target.") + } + + _target_name = target_name + _output_name = target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + if (defined(invoker.bundle_binary_path)) { + _bundle_binary_path = invoker.bundle_binary_path + } else { + _bundle_binary_target = invoker.bundle_binary_target + _bundle_binary_output = get_label_info(_bundle_binary_target, "name") + if (defined(invoker.bundle_binary_output)) { + _bundle_binary_output = invoker.bundle_binary_output + } + _bundle_binary_path = + get_label_info(_bundle_binary_target, "target_out_dir") + + "/$_bundle_binary_output" + } + + _bundle_gen_dir = root_out_dir + if (defined(invoker.bundle_gen_dir)) { + _bundle_gen_dir = invoker.bundle_gen_dir + } + + _bundle_extension = invoker.bundle_extension + + _enable_embedded_mobileprovision = true + if (defined(invoker.disable_embedded_mobileprovision)) { + _enable_embedded_mobileprovision = !invoker.disable_embedded_mobileprovision + } + + if (target_environment == "catalyst") { + _enable_embedded_mobileprovision = false + } + + _enable_entitlements = true + if (defined(invoker.disable_entitlements)) { + _enable_entitlements = !invoker.disable_entitlements + } + + if (_enable_entitlements) { + if (!defined(invoker.entitlements_target)) { + _entitlements_path = "//build/config/ios/entitlements.plist" + if (defined(invoker.entitlements_path)) { + _entitlements_path = invoker.entitlements_path + } + } else { + assert(!defined(invoker.entitlements_path), + "Cannot define both entitlements_path and entitlements_target " + + "for $target_name") + + _entitlements_target_outputs = + get_target_outputs(invoker.entitlements_target) + _entitlements_path = _entitlements_target_outputs[0] + } + } + + _enable_code_signing = ios_enable_code_signing + if (defined(invoker.enable_code_signing)) { + _enable_code_signing = invoker.enable_code_signing + } + + if (!ios_set_attributes_for_xcode_project_generation) { + not_needed(invoker, + [ + "xcode_product_bundle_id", + "xcode_extra_attributes", + ]) + } + + create_bundle(_target_name) { + forward_variables_from(invoker, + [ + "bundle_deps_filter", + "data_deps", + "deps", + "partial_info_plist", + "product_type", + "public_configs", + "public_deps", + "testonly", + "visibility", + "xcode_test_application_name", + ]) + + bundle_root_dir = "$_bundle_gen_dir/$_output_name$_bundle_extension" + if (target_environment == "simulator" || target_environment == "device") { + bundle_contents_dir = bundle_root_dir + bundle_resources_dir = bundle_contents_dir + bundle_executable_dir = bundle_contents_dir + } else if (target_environment == "catalyst") { + if (_bundle_extension != ".framework") { + bundle_contents_dir = "$bundle_root_dir/Contents" + bundle_resources_dir = "$bundle_contents_dir/Resources" + bundle_executable_dir = "$bundle_contents_dir/MacOS" + } else { + bundle_contents_dir = "$bundle_root_dir/Versions/A" + bundle_resources_dir = "$bundle_contents_dir/Resources" + bundle_executable_dir = bundle_contents_dir + } + } + + if (!defined(public_deps)) { + public_deps = [] + } + + if (ios_set_attributes_for_xcode_project_generation) { + _xcode_product_bundle_id = "" + if (defined(invoker.xcode_product_bundle_id)) { + _xcode_product_bundle_id = invoker.xcode_product_bundle_id + } + + if (_xcode_product_bundle_id != "") { + _ios_provisioning_profile_info = + exec_script("//build/config/ios/codesign.py", + [ + "find-provisioning-profile", + "-b=" + _xcode_product_bundle_id, + ], + "json") + } + + xcode_extra_attributes = { + IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target + if (_xcode_product_bundle_id != "") { + CODE_SIGN_IDENTITY = "iPhone Developer" + DEVELOPMENT_TEAM = _ios_provisioning_profile_info.team_identifier + PRODUCT_BUNDLE_IDENTIFIER = _xcode_product_bundle_id + PROVISIONING_PROFILE_SPECIFIER = _ios_provisioning_profile_info.name + } + + # If invoker has defined extra attributes, they override the defaults. + if (defined(invoker.xcode_extra_attributes)) { + forward_variables_from(invoker.xcode_extra_attributes, "*") + } + } + } + + if (defined(invoker.bundle_binary_target)) { + public_deps += [ invoker.bundle_binary_target ] + } + + if (defined(invoker.bundle_deps)) { + if (!defined(deps)) { + deps = [] + } + deps += invoker.bundle_deps + } + if (!defined(deps)) { + deps = [] + } + + code_signing_script = "//build/config/ios/codesign.py" + code_signing_sources = [ _bundle_binary_path ] + if (_enable_entitlements) { + if (defined(invoker.entitlements_target)) { + deps += [ invoker.entitlements_target ] + } + code_signing_sources += [ _entitlements_path ] + } + code_signing_outputs = [ "$bundle_executable_dir/$_output_name" ] + if (_enable_code_signing) { + code_signing_outputs += + [ "$bundle_contents_dir/_CodeSignature/CodeResources" ] + } + if (ios_code_signing_identity != "" && target_environment == "device" && + _enable_embedded_mobileprovision) { + code_signing_outputs += + [ "$bundle_contents_dir/embedded.mobileprovision" ] + } + if (_bundle_extension == ".framework") { + if (target_environment == "catalyst") { + code_signing_outputs += [ + "$bundle_root_dir/Versions/Current", + "$bundle_root_dir/$_output_name", + ] + + if (defined(invoker.has_public_headers) && invoker.has_public_headers) { + code_signing_outputs += [ + "$bundle_root_dir/Headers", + "$bundle_root_dir/Modules", + ] + } + } else { + not_needed(invoker, [ "has_public_headers" ]) + } + } + + if (defined(invoker.extra_system_frameworks)) { + foreach(_framework, invoker.extra_system_frameworks) { + code_signing_outputs += [ "$bundle_contents_dir/Frameworks/" + + get_path_info(_framework, "file") ] + } + } + + code_signing_args = [ + "code-sign-bundle", + "-t=" + ios_sdk_name, + "-i=" + ios_code_signing_identity, + "-b=" + rebase_path(_bundle_binary_path, root_build_dir), + ] + if (_enable_entitlements) { + code_signing_args += + [ "-e=" + rebase_path(_entitlements_path, root_build_dir) ] + } + if (!_enable_embedded_mobileprovision) { + code_signing_args += [ "--disable-embedded-mobileprovision" ] + } + code_signing_args += [ rebase_path(bundle_root_dir, root_build_dir) ] + if (!_enable_code_signing) { + code_signing_args += [ "--disable-code-signature" ] + } + if (defined(invoker.extra_system_frameworks)) { + # All framework in extra_system_frameworks are expected to be system + # framework and the path to be already system absolute so do not use + # rebase_path here unless using Goma RBE and system Xcode (as in that + # case the system framework are found via a symlink in root_build_dir). + foreach(_framework, invoker.extra_system_frameworks) { + if (use_system_xcode && use_goma) { + _framework_path = rebase_path(_framework, root_build_dir) + } else { + _framework_path = _framework + } + code_signing_args += [ "-F=$_framework_path" ] + } + } + if (defined(invoker.partial_info_plist)) { + _partial_info_plists = [ + invoker.primary_info_plist, + invoker.partial_info_plist, + ] + + _plist_compiler_path = "//build/apple/plist_util.py" + + code_signing_sources += _partial_info_plists + code_signing_sources += [ _plist_compiler_path ] + if (target_environment != "catalyst" || + _bundle_extension != ".framework") { + code_signing_outputs += [ "$bundle_contents_dir/Info.plist" ] + } else { + code_signing_outputs += [ "$bundle_resources_dir/Info.plist" ] + } + + code_signing_args += + [ "-P=" + rebase_path(_plist_compiler_path, root_build_dir) ] + foreach(_partial_info_plist, _partial_info_plists) { + code_signing_args += + [ "-p=" + rebase_path(_partial_info_plist, root_build_dir) ] + } + } + } +} + +# Generates Info.plist files for Mac apps and frameworks. +# +# Arguments +# +# info_plist: +# (optional) string, path to the Info.plist file that will be used for +# the bundle. +# +# info_plist_target: +# (optional) string, if the info_plist is generated from an action, +# rather than a regular source file, specify the target name in lieu +# of info_plist. The two arguments are mutually exclusive. +# +# executable_name: +# string, name of the generated target used for the product +# and executable name as specified in the output Info.plist. +# +# extra_substitutions: +# (optional) string array, 'key=value' pairs for extra fields which are +# specified in a source Info.plist template. +template("ios_info_plist") { + assert(defined(invoker.info_plist) != defined(invoker.info_plist_target), + "Only one of info_plist or info_plist_target may be specified in " + + target_name) + + if (defined(invoker.info_plist)) { + _info_plist = invoker.info_plist + } else { + _info_plist_target_output = get_target_outputs(invoker.info_plist_target) + _info_plist = _info_plist_target_output[0] + } + + apple_info_plist(target_name) { + format = "binary1" + extra_substitutions = [] + if (defined(invoker.extra_substitutions)) { + extra_substitutions = invoker.extra_substitutions + } + extra_substitutions += [ + "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix", + "IOS_PLATFORM_BUILD=$ios_platform_build", + "IOS_PLATFORM_NAME=$ios_sdk_name", + "IOS_PLATFORM_VERSION=$ios_sdk_version", + "IOS_SDK_BUILD=$ios_sdk_build", + "IOS_SDK_NAME=$ios_sdk_name$ios_sdk_version", + "IOS_SUPPORTED_PLATFORM=$ios_sdk_platform", + "BUILD_MACHINE_OS_BUILD=$machine_os_build", + "IOS_DEPLOYMENT_TARGET=$ios_deployment_target", + "XCODE_BUILD=$xcode_build", + "XCODE_VERSION=$xcode_version", + ] + plist_templates = [ + "//build/config/ios/BuildInfo.plist", + _info_plist, + ] + if (defined(invoker.info_plist_target)) { + deps = [ invoker.info_plist_target ] + } + forward_variables_from(invoker, + [ + "executable_name", + "output_name", + "visibility", + "testonly", + ]) + } +} + +# Template to build an application bundle for iOS. +# +# This should be used instead of "executable" built-in target type on iOS. +# As the template forward the generation of the application executable to +# an "executable" target, all arguments supported by "executable" targets +# are also supported by this template. +# +# Arguments +# +# output_name: +# (optional) string, name of the generated application, if omitted, +# defaults to the target_name. +# +# extra_substitutions: +# (optional) list of string in "key=value" format, each value will +# be used as an additional variable substitution rule when generating +# the application Info.plist +# +# info_plist: +# (optional) string, path to the Info.plist file that will be used for +# the bundle. +# +# info_plist_target: +# (optional) string, if the info_plist is generated from an action, +# rather than a regular source file, specify the target name in lieu +# of info_plist. The two arguments are mutually exclusive. +# +# entitlements_path: +# (optional) path to the template to use to generate the application +# entitlements by performing variable substitutions, defaults to +# //build/config/ios/entitlements.plist. +# +# entitlements_target: +# (optional) label of the target generating the application +# entitlements (must generate a single file as output); cannot be +# defined if entitlements_path is set. +# +# product_type +# (optional) string, product type for the generated Xcode project, +# default to "com.apple.product-type.application". Should only be +# overriden when building application extension. +# +# enable_code_signing +# (optional) boolean, control whether code signing is enabled or not, +# default to ios_enable_code_signing if not defined. +# +# variants +# (optional) list of scopes, each scope needs to define the attributes +# "name" and "bundle_deps"; if defined and non-empty, then one bundle +# named $target_out_dir/$variant/$output_name will be created for each +# variant with the same binary but the correct bundle_deps, the bundle +# at $target_out_dir/$output_name will be a copy of the first variant. +# +# xcode_product_bundle_id: +# (optional) string, the bundle ID that will be added in the XCode +# attributes to enable some features when debugging (e.g. MetricKit). +# defaults to "$ios_app_bundle_id_prefix.$output_name". +# +# For more information, see "gn help executable". +template("ios_app_bundle") { + _output_name = target_name + _target_name = target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + _primary_toolchain = current_toolchain + if (is_fat_secondary_toolchain) { + _primary_toolchain = primary_fat_toolchain_name + } + + assert( + !defined(invoker.bundle_extension), + "bundle_extension must not be set for ios_app_bundle template for $target_name") + + _xcode_product_bundle_id = "$ios_app_bundle_id_prefix.$_output_name" + if (defined(invoker.xcode_product_bundle_id)) { + _xcode_product_bundle_id = invoker.xcode_product_bundle_id + _xcode_product_bundle_id = + "$ios_app_bundle_id_prefix.$_xcode_product_bundle_id" + } else if (defined(invoker.bundle_id)) { + _xcode_product_bundle_id = invoker.bundle_id + } + + # Bundle ID should respect rfc1034 and replace _ with -. + _xcode_product_bundle_id = + string_replace("$_xcode_product_bundle_id", "_", "-") + + _arch_executable_source = _target_name + "_arch_executable_sources" + _arch_executable_target = _target_name + "_arch_executable" + _lipo_executable_target = _target_name + "_executable" + + if (defined(invoker.variants) && invoker.variants != []) { + _variants = [] + + foreach(_variant, invoker.variants) { + assert(defined(_variant.name) && _variant.name != "", + "name must be defined for all $target_name variants") + + assert(defined(_variant.bundle_deps), + "bundle_deps must be defined for all $target_name variants") + + _variants += [ + { + name = _variant.name + bundle_deps = _variant.bundle_deps + target_name = "${_target_name}_variants_${_variant.name}" + bundle_gen_dir = "$root_out_dir/variants/${_variant.name}" + }, + ] + } + } else { + # If no variants are passed to the template, use a fake variant with + # no name to avoid duplicating code. As no variant can have an empty + # name except this fake variant, it is possible to know if a variant + # is fake or not. + _variants = [ + { + name = "" + bundle_deps = [] + target_name = _target_name + bundle_gen_dir = root_out_dir + }, + ] + } + + _default_variant = _variants[0] + + source_set(_arch_executable_source) { + forward_variables_from(invoker, + "*", + [ + "bundle_deps", + "bundle_deps_filter", + "bundle_extension", + "enable_code_signing", + "entitlements_path", + "entitlements_target", + "extra_substitutions", + "extra_system_frameworks", + "info_plist", + "info_plist_target", + "output_name", + "product_type", + "visibility", + "xcode_extra_attributes", + ]) + + visibility = [ ":$_arch_executable_target" ] + } + + if (!is_fat_secondary_toolchain || target_environment == "simulator") { + _generate_entitlements_target = _target_name + "_gen_entitlements" + _generate_entitlements_output = + get_label_info(":$_generate_entitlements_target($_primary_toolchain)", + "target_out_dir") + "/$_output_name.xcent" + } + + _product_type = _ios_xcode_app_bundle_id + if (defined(invoker.product_type)) { + _product_type = invoker.product_type + } + + if (_product_type == _ios_xcode_app_bundle_id) { + _bundle_extension = ".app" + } else if (_product_type == _ios_xcode_appex_bundle_id) { + _bundle_extension = ".appex" + } else { + assert(false, "unknown product_type \"$product_type\" for $_target_name") + } + + _is_app_bundle = _product_type == _ios_xcode_app_bundle_id + + executable(_arch_executable_target) { + forward_variables_from(invoker, + "*", + [ + "bundle_deps", + "bundle_deps_filter", + "bundle_extension", + "enable_code_signing", + "entitlements_path", + "entitlements_target", + "extra_substitutions", + "extra_system_frameworks", + "info_plist", + "info_plist_target", + "output_name", + "product_type", + "sources", + "visibility", + "xcode_extra_attributes", + ]) + + visibility = [ ":$_lipo_executable_target($_primary_toolchain)" ] + if (is_fat_secondary_toolchain) { + visibility += [ ":$_target_name" ] + } + + if (!defined(deps)) { + deps = [] + } + deps += [ ":$_arch_executable_source" ] + + if (!defined(frameworks)) { + frameworks = [] + } + frameworks += [ "UIKit.framework" ] + + if (target_environment == "simulator") { + deps += [ ":$_generate_entitlements_target($_primary_toolchain)" ] + + if (!defined(inputs)) { + inputs = [] + } + inputs += [ _generate_entitlements_output ] + + if (!defined(ldflags)) { + ldflags = [] + } + ldflags += [ "-Wl,-sectcreate,__TEXT,__entitlements," + + rebase_path(_generate_entitlements_output, root_build_dir) ] + } + + output_name = _output_name + output_prefix_override = true + output_dir = "$target_out_dir/$target_cpu" + } + + if (is_fat_secondary_toolchain) { + # For fat builds, only the default toolchain will generate an application + # bundle. For the other toolchains, the template is only used for building + # the arch-specific binary, thus the default target is just a group(). + + group(_target_name) { + forward_variables_from(invoker, + [ + "visibility", + "testonly", + ]) + public_deps = [ ":$_arch_executable_target" ] + } + } else { + lipo_binary(_lipo_executable_target) { + forward_variables_from(invoker, + [ + "configs", + "testonly", + ]) + + visibility = [] + foreach(_variant, _variants) { + visibility += [ ":${_variant.target_name}" ] + } + + output_name = _output_name + arch_binary_target = ":$_arch_executable_target" + arch_binary_output = _output_name + } + + _generate_info_plist = target_name + "_generate_info_plist" + ios_info_plist(_generate_info_plist) { + forward_variables_from(invoker, + [ + "extra_substitutions", + "info_plist", + "info_plist_target", + ]) + + executable_name = _output_name + } + + if (!is_fat_secondary_toolchain) { + if (!defined(invoker.entitlements_target)) { + _entitlements_path = "//build/config/ios/entitlements.plist" + if (defined(invoker.entitlements_path)) { + _entitlements_path = invoker.entitlements_path + } + } else { + assert(!defined(invoker.entitlements_path), + "Cannot define both entitlements_path and entitlements_target" + + "for $_target_name") + + _entitlements_target_outputs = + get_target_outputs(invoker.entitlements_target) + _entitlements_path = _entitlements_target_outputs[0] + } + + action(_generate_entitlements_target) { + _gen_info_plist_outputs = get_target_outputs(":$_generate_info_plist") + _info_plist_path = _gen_info_plist_outputs[0] + + script = "//build/config/ios/codesign.py" + deps = [ ":$_generate_info_plist" ] + if (defined(invoker.entitlements_target)) { + deps += [ invoker.entitlements_target ] + } + sources = [ + _entitlements_path, + _info_plist_path, + ] + outputs = [ _generate_entitlements_output ] + + args = [ + "generate-entitlements", + "-e=" + rebase_path(_entitlements_path, root_build_dir), + "-p=" + rebase_path(_info_plist_path, root_build_dir), + ] + rebase_path(outputs, root_build_dir) + } + } + + # Only write PkgInfo for real application, not application extension. + if (_is_app_bundle) { + _create_pkg_info = target_name + "_pkg_info" + action(_create_pkg_info) { + forward_variables_from(invoker, [ "testonly" ]) + script = "//build/apple/write_pkg_info.py" + inputs = [ "//build/apple/plist_util.py" ] + sources = get_target_outputs(":$_generate_info_plist") + outputs = [ + # Cannot name the output PkgInfo as the name will not be unique if + # multiple ios_app_bundle are defined in the same BUILD.gn file. The + # file is renamed in the bundle_data outputs to the correct name. + "$target_gen_dir/$target_name", + ] + args = [ "--plist" ] + rebase_path(sources, root_build_dir) + + [ "--output" ] + rebase_path(outputs, root_build_dir) + deps = [ ":$_generate_info_plist" ] + } + + _bundle_data_pkg_info = target_name + "_bundle_data_pkg_info" + bundle_data(_bundle_data_pkg_info) { + forward_variables_from(invoker, [ "testonly" ]) + sources = get_target_outputs(":$_create_pkg_info") + outputs = [ "{{bundle_resources_dir}}/PkgInfo" ] + public_deps = [ ":$_create_pkg_info" ] + } + } + + foreach(_variant, _variants) { + create_signed_bundle(_variant.target_name) { + forward_variables_from(invoker, + [ + "bundle_deps", + "bundle_deps_filter", + "data_deps", + "deps", + "enable_code_signing", + "entitlements_path", + "entitlements_target", + "extra_system_frameworks", + "public_configs", + "public_deps", + "testonly", + "visibility", + "xcode_extra_attributes", + ]) + + output_name = _output_name + bundle_gen_dir = _variant.bundle_gen_dir + bundle_binary_target = ":$_lipo_executable_target" + bundle_binary_output = _output_name + bundle_extension = _bundle_extension + product_type = _product_type + xcode_product_bundle_id = _xcode_product_bundle_id + + _generate_info_plist_outputs = + get_target_outputs(":$_generate_info_plist") + primary_info_plist = _generate_info_plist_outputs[0] + partial_info_plist = + "$target_gen_dir/${_variant.target_name}_partial_info.plist" + + if (!defined(deps)) { + deps = [] + } + deps += [ ":$_generate_info_plist" ] + + if (!defined(bundle_deps)) { + bundle_deps = [] + } + if (_is_app_bundle) { + bundle_deps += [ ":$_bundle_data_pkg_info" ] + } + bundle_deps += _variant.bundle_deps + + if (target_environment == "simulator") { + if (!defined(data_deps)) { + data_deps = [] + } + data_deps += [ "//testing/iossim" ] + } + } + } + + if (_default_variant.name != "") { + _bundle_short_name = "$_output_name$_bundle_extension" + action(_target_name) { + forward_variables_from(invoker, [ "testonly" ]) + + script = "//build/config/ios/hardlink.py" + public_deps = [] + foreach(_variant, _variants) { + public_deps += [ ":${_variant.target_name}" ] + } + + sources = [ "${_default_variant.bundle_gen_dir}/$_bundle_short_name" ] + outputs = [ "$root_out_dir/$_bundle_short_name" ] + + args = rebase_path(sources, root_build_dir) + + rebase_path(outputs, root_build_dir) + } + } + } + + if (is_fat_secondary_toolchain) { + not_needed("*") + } +} + +set_defaults("ios_app_bundle") { + configs = default_executable_configs +} + +# Template to build an application extension bundle for iOS. +# +# This should be used instead of "executable" built-in target type on iOS. +# As the template forward the generation of the application executable to +# an "executable" target, all arguments supported by "executable" targets +# are also supported by this template. +# +# Arguments +# +# output_name: +# (optional) string, name of the generated application, if omitted, +# defaults to the target_name. +# +# extra_substitutions: +# (optional) list of string in "key=value" format, each value will +# be used as an additional variable substitution rule when generating +# the application Info.plist +# +# info_plist: +# (optional) string, path to the Info.plist file that will be used for +# the bundle. +# +# info_plist_target: +# (optional) string, if the info_plist is generated from an action, +# rather than a regular source file, specify the target name in lieu +# of info_plist. The two arguments are mutually exclusive. +# +# For more information, see "gn help executable". +template("ios_appex_bundle") { + ios_app_bundle(target_name) { + forward_variables_from(invoker, + "*", + [ + "bundle_extension", + "product_type", + ]) + product_type = _ios_xcode_appex_bundle_id + } +} + +set_defaults("ios_appex_bundle") { + configs = [ "//build/config/ios:ios_extension_executable_flags" ] +} + +# Template to compile .xib and .storyboard files. +# +# Arguments +# +# sources: +# list of string, sources to compile +# +# ibtool_flags: +# (optional) list of string, additional flags to pass to the ibtool +template("compile_ib_files") { + action_foreach(target_name) { + forward_variables_from(invoker, + [ + "testonly", + "visibility", + ]) + assert(defined(invoker.sources), + "sources must be specified for $target_name") + assert(defined(invoker.output_extension), + "output_extension must be specified for $target_name") + + ibtool_flags = [] + if (defined(invoker.ibtool_flags)) { + ibtool_flags = invoker.ibtool_flags + } + + _output_extension = invoker.output_extension + + script = "//build/config/ios/compile_ib_files.py" + sources = invoker.sources + outputs = [ + "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension", + ] + args = [ + "--input", + "{{source}}", + "--output", + rebase_path( + "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension", + root_build_dir), + ] + args += ibtool_flags + } +} + +# Compile a xib or storyboard file and add it to a bundle_data so that it is +# available at runtime in the bundle. +# +# Arguments +# +# source: +# string, path of the xib or storyboard to compile. +# +# Forwards all variables to the bundle_data target. +template("bundle_data_ib_file") { + assert(defined(invoker.source), "source needs to be defined for $target_name") + + _source_extension = get_path_info(invoker.source, "extension") + assert(_source_extension == "xib" || _source_extension == "storyboard", + "source must be a .xib or .storyboard for $target_name") + + _target_name = target_name + if (_source_extension == "xib") { + _compile_ib_file = target_name + "_compile_xib" + _output_extension = "nib" + } else { + _compile_ib_file = target_name + "_compile_storyboard" + _output_extension = "storyboardc" + } + + compile_ib_files(_compile_ib_file) { + sources = [ invoker.source ] + output_extension = _output_extension + visibility = [ ":$_target_name" ] + ibtool_flags = [ + "--minimum-deployment-target", + ios_deployment_target, + "--auto-activate-custom-fonts", + "--target-device", + "iphone", + "--target-device", + "ipad", + ] + } + + bundle_data(_target_name) { + forward_variables_from(invoker, "*", [ "source" ]) + + if (!defined(public_deps)) { + public_deps = [] + } + public_deps += [ ":$_compile_ib_file" ] + + sources = get_target_outputs(":$_compile_ib_file") + + outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] + } +} + +# Compile a strings file and add it to a bundle_data so that it is available +# at runtime in the bundle. +# +# Arguments +# +# source: +# string, path of the strings file to compile. +# +# output: +# string, path of the compiled file in the final bundle. +# +# Forwards all variables to the bundle_data target. +template("bundle_data_strings") { + assert(defined(invoker.source), "source needs to be defined for $target_name") + assert(defined(invoker.output), "output needs to be defined for $target_name") + + _source_extension = get_path_info(invoker.source, "extension") + assert(_source_extension == "strings", + "source must be a .strings for $target_name") + + _target_name = target_name + _convert_target = target_name + "_compile_strings" + + convert_plist(_convert_target) { + visibility = [ ":$_target_name" ] + source = invoker.source + output = + "$target_gen_dir/$_target_name/" + get_path_info(invoker.source, "file") + format = "binary1" + } + + bundle_data(_target_name) { + forward_variables_from(invoker, + "*", + [ + "source", + "output", + ]) + + if (!defined(public_deps)) { + public_deps = [] + } + public_deps += [ ":$_convert_target" ] + + sources = get_target_outputs(":$_convert_target") + + outputs = [ invoker.output ] + } +} + +# Template to package a shared library into an iOS framework bundle. +# +# By default, the bundle target this template generates does not link the +# resulting framework into anything that depends on it. If a dependency wants +# a link-time (as well as build-time) dependency on the framework bundle, +# depend against "$target_name+link". If only the build-time dependency is +# required (e.g., for copying into another bundle), then use "$target_name". +# +# Arguments +# +# output_name: +# (optional) string, name of the generated framework without the +# .framework suffix. If omitted, defaults to target_name. +# +# public_headers: +# (optional) list of paths to header file that needs to be copied +# into the framework bundle Headers subdirectory. If omitted or +# empty then the Headers subdirectory is not created. +# +# sources +# (optional) list of files. Needs to be defined and non-empty if +# public_headers is defined and non-empty. +# +# enable_code_signing +# (optional) boolean, control whether code signing is enabled or not, +# default to ios_enable_code_signing if not defined. +# +# This template provides two targets for the resulting framework bundle. The +# link-time behavior varies depending on which of the two targets below is +# added as a dependency: +# - $target_name only adds a build-time dependency. Targets that depend on +# it will not link against the framework. +# - $target_name+link adds a build-time and link-time dependency. Targets +# that depend on it will link against the framework. +# +# The build-time-only dependency is used for when a target needs to use the +# framework either only for resources, or because the target loads it at run- +# time, via dlopen() or NSBundle. The link-time dependency will cause the +# dependee to have the framework loaded by dyld at launch. +# +# Example of build-time only dependency: +# +# framework_bundle("CoreTeleportation") { +# sources = [ ... ] +# } +# +# bundle_data("core_teleportation_bundle_data") { +# deps = [ ":CoreTeleportation" ] +# sources = [ "$root_out_dir/CoreTeleportation.framework" ] +# outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] +# } +# +# app_bundle("GoatTeleporter") { +# sources = [ ... ] +# deps = [ +# ":core_teleportation_bundle_data", +# ] +# } +# +# The GoatTeleporter.app will not directly link against +# CoreTeleportation.framework, but it will be included in the bundle's +# Frameworks directory. +# +# Example of link-time dependency: +# +# framework_bundle("CoreTeleportation") { +# sources = [ ... ] +# ldflags = [ +# "-install_name", +# "@executable_path/../Frameworks/$target_name.framework" +# ] +# } +# +# bundle_data("core_teleportation_bundle_data") { +# deps = [ ":CoreTeleportation+link" ] +# sources = [ "$root_out_dir/CoreTeleportation.framework" ] +# outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] +# } +# +# app_bundle("GoatTeleporter") { +# sources = [ ... ] +# deps = [ +# ":core_teleportation_bundle_data", +# ] +# } +# +# Note that the framework is still copied to the app's bundle, but dyld will +# load this library when the app is launched because it uses the "+link" +# target as a dependency. This also requires that the framework set its +# install_name so that dyld can locate it. +# +# See "gn help shared_library" for more information on arguments supported +# by shared library target. +template("ios_framework_bundle") { + _target_name = target_name + _output_name = target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + _has_public_headers = + defined(invoker.public_headers) && invoker.public_headers != [] + + _primary_toolchain = current_toolchain + if (is_fat_secondary_toolchain) { + _primary_toolchain = primary_fat_toolchain_name + } + + # Public configs are not propagated across toolchain (see crbug.com/675224) + # so some configs have to be defined for both default_toolchain and all others + # toolchains when performing a fat build. Use "get_label_info" to construct + # the path since they need to be relative to the default_toolchain. + + _default_toolchain_root_out_dir = + get_label_info("$_target_name($_primary_toolchain)", "root_out_dir") + + _arch_shared_library_source = _target_name + "_arch_shared_library_sources" + _arch_shared_library_target = _target_name + "_arch_shared_library" + _lipo_shared_library_target = _target_name + "_shared_library" + _link_target_name = _target_name + "+link" + + if (_has_public_headers) { + _default_toolchain_target_gen_dir = + get_label_info("$_target_name($_primary_toolchain)", "target_gen_dir") + + _framework_headers_target = _target_name + "_framework_headers" + + _headers_map_config = _target_name + "_headers_map" + _header_map_filename = + "$_default_toolchain_target_gen_dir/$_output_name.headers.hmap" + config(_headers_map_config) { + visibility = [ + ":${_arch_shared_library_source}", + ":${_target_name}_signed_bundle", + ] + include_dirs = [ _header_map_filename ] + } + } + + _framework_headers_config = _target_name + "_framework_headers_config" + config(_framework_headers_config) { + framework_dirs = [ _default_toolchain_root_out_dir ] + } + + _framework_public_config = _target_name + "_public_config" + config(_framework_public_config) { + configs = [ ":$_framework_headers_config" ] + frameworks = [ "$_output_name.framework" ] + } + + source_set(_arch_shared_library_source) { + forward_variables_from(invoker, + "*", + [ + "bundle_deps", + "bundle_deps_filter", + "data_deps", + "enable_code_signing", + "extra_substitutions", + "info_plist", + "info_plist_target", + "output_name", + "public_configs", + "visibility", + ]) + + visibility = [ ":$_arch_shared_library_target" ] + + if (_has_public_headers) { + configs += [ ":$_headers_map_config" ] + + if (!defined(deps)) { + deps = [] + } + deps += [ ":$_framework_headers_target($_primary_toolchain)" ] + } + } + + shared_library(_arch_shared_library_target) { + forward_variables_from(invoker, + "*", + [ + "bundle_deps", + "bundle_deps_filter", + "data_deps", + "enable_code_signing", + "extra_substitutions", + "info_plist", + "info_plist_target", + "output_name", + "sources", + "public_configs", + "visibility", + ]) + + visibility = [ ":$_lipo_shared_library_target($_primary_toolchain)" ] + if (is_fat_secondary_toolchain) { + visibility += [ + ":${_target_name}", + ":${_target_name}_signed_bundle", + ] + } + + if (!defined(deps)) { + deps = [] + } + deps += [ ":$_arch_shared_library_source" ] + if (_has_public_headers) { + deps += [ ":$_framework_headers_target($_primary_toolchain)" ] + } + if (!defined(ldflags)) { + ldflags = [] + } + ldflags += + [ "-Wl,-install_name,@rpath/$_output_name.framework/$_output_name" ] + + output_extension = "" + output_name = _output_name + output_prefix_override = true + output_dir = "$target_out_dir/$target_cpu" + } + + if (is_fat_secondary_toolchain) { + # For fat builds, only the default toolchain will generate a framework + # bundle. For the other toolchains, the template is only used for building + # the arch-specific binary, thus the default target is just a group(). + + group(_target_name) { + forward_variables_from(invoker, + [ + "visibility", + "testonly", + ]) + public_deps = [ ":$_arch_shared_library_target" ] + } + + group(_link_target_name) { + forward_variables_from(invoker, + [ + "public_configs", + "visibility", + "testonly", + ]) + public_deps = [ ":$_link_target_name($_primary_toolchain)" ] + + if (_has_public_headers) { + if (!defined(public_configs)) { + public_configs = [] + } + public_configs += [ ":$_framework_headers_config" ] + } + if (!defined(all_dependent_configs)) { + all_dependent_configs = [] + } + all_dependent_configs += [ ":$_framework_public_config" ] + } + + group("$_target_name+bundle") { + forward_variables_from(invoker, [ "testonly" ]) + public_deps = [ ":$_target_name+bundle($_primary_toolchain)" ] + } + + not_needed(invoker, "*") + } else { + if (_has_public_headers) { + _public_headers = invoker.public_headers + + _framework_root_dir = "$root_out_dir/$_output_name.framework" + if (target_environment == "simulator" || target_environment == "device") { + _framework_contents_dir = _framework_root_dir + } else if (target_environment == "catalyst") { + _framework_contents_dir = "$_framework_root_dir/Versions/A" + } + + _compile_headers_map_target = _target_name + "_compile_headers_map" + action(_compile_headers_map_target) { + visibility = [ ":$_framework_headers_target" ] + forward_variables_from(invoker, + [ + "deps", + "public_deps", + "testonly", + ]) + script = "//build/config/ios/write_framework_hmap.py" + outputs = [ _header_map_filename ] + + # The header map generation only wants the list of headers, not all of + # sources, so filter any non-header source files from "sources". It is + # less error prone that having the developer duplicate the list of all + # headers in addition to "sources". + sources = [] + foreach(_source, invoker.sources) { + if (get_path_info(_source, "extension") == "h") { + sources += [ _source ] + } + } + + args = [ + rebase_path(_header_map_filename), + rebase_path(_framework_root_dir, root_build_dir), + ] + rebase_path(sources, root_build_dir) + } + + _create_module_map_target = _target_name + "_module_map" + action(_create_module_map_target) { + visibility = [ ":$_framework_headers_target" ] + script = "//build/config/ios/write_framework_modulemap.py" + outputs = [ "$_framework_contents_dir/Modules/module.modulemap" ] + args = [ + _output_name, + rebase_path("$_framework_contents_dir/Modules", root_build_dir), + ] + } + + _copy_public_headers_target = _target_name + "_copy_public_headers" + copy(_copy_public_headers_target) { + forward_variables_from(invoker, + [ + "testonly", + "deps", + ]) + visibility = [ ":$_framework_headers_target" ] + sources = _public_headers + outputs = [ "$_framework_contents_dir/Headers/{{source_file_part}}" ] + + # Do not use forward_variables_from for "public_deps" as + # we do not want to forward those dependencies. + if (defined(invoker.public_deps)) { + if (!defined(deps)) { + deps = [] + } + deps += invoker.public_deps + } + } + + group(_framework_headers_target) { + forward_variables_from(invoker, [ "testonly" ]) + deps = [ + ":$_compile_headers_map_target", + ":$_create_module_map_target", + ] + public_deps = [ ":$_copy_public_headers_target" ] + } + } + + lipo_binary(_lipo_shared_library_target) { + forward_variables_from(invoker, + [ + "configs", + "testonly", + ]) + + visibility = [ ":${_target_name}_signed_bundle" ] + output_name = _output_name + arch_binary_target = ":$_arch_shared_library_target" + arch_binary_output = _output_name + } + + _info_plist_target = _target_name + "_info_plist" + _info_plist_bundle = _target_name + "_info_plist_bundle" + ios_info_plist(_info_plist_target) { + visibility = [ ":$_info_plist_bundle" ] + executable_name = _output_name + forward_variables_from(invoker, + [ + "extra_substitutions", + "info_plist", + "info_plist_target", + ]) + } + + bundle_data(_info_plist_bundle) { + visibility = [ ":${_target_name}_signed_bundle" ] + forward_variables_from(invoker, [ "testonly" ]) + sources = get_target_outputs(":$_info_plist_target") + public_deps = [ ":$_info_plist_target" ] + + if (target_environment != "catalyst") { + outputs = [ "{{bundle_contents_dir}}/Info.plist" ] + } else { + outputs = [ "{{bundle_resources_dir}}/Info.plist" ] + } + } + + create_signed_bundle(_target_name + "_signed_bundle") { + forward_variables_from(invoker, + [ + "bundle_deps", + "bundle_deps_filter", + "data_deps", + "deps", + "enable_code_signing", + "public_configs", + "public_deps", + "testonly", + "visibility", + ]) + + product_type = "com.apple.product-type.framework" + bundle_extension = ".framework" + + output_name = _output_name + bundle_binary_target = ":$_lipo_shared_library_target" + bundle_binary_output = _output_name + + has_public_headers = _has_public_headers + + # Framework do not have entitlements nor mobileprovision because they use + # the one from the bundle using them (.app or .appex) as they are just + # dynamic library with shared code. + disable_entitlements = true + disable_embedded_mobileprovision = true + + if (!defined(deps)) { + deps = [] + } + deps += [ ":$_info_plist_bundle" ] + } + + group(_target_name) { + forward_variables_from(invoker, + [ + "public_configs", + "public_deps", + "testonly", + "visibility", + ]) + if (!defined(public_deps)) { + public_deps = [] + } + public_deps += [ ":${_target_name}_signed_bundle" ] + + if (_has_public_headers) { + if (!defined(public_configs)) { + public_configs = [] + } + public_configs += [ ":$_framework_headers_config" ] + } + } + + group(_link_target_name) { + forward_variables_from(invoker, + [ + "public_configs", + "public_deps", + "testonly", + "visibility", + ]) + if (!defined(public_deps)) { + public_deps = [] + } + public_deps += [ ":$_target_name" ] + + if (!defined(all_dependent_configs)) { + all_dependent_configs = [] + } + all_dependent_configs += [ ":$_framework_public_config" ] + } + + bundle_data(_target_name + "+bundle") { + forward_variables_from(invoker, + [ + "testonly", + "visibility", + ]) + public_deps = [ ":$_target_name" ] + sources = [ "$root_out_dir/$_output_name.framework" ] + outputs = [ "{{bundle_contents_dir}}/Frameworks/$_output_name.framework" ] + } + } +} + +set_defaults("ios_framework_bundle") { + configs = default_shared_library_configs +} + +# Template to build a xctest bundle that contains a loadable module for iOS. +# +# Arguments +# +# deps: +# list of labels to depends on, these values are used to create the +# loadable module. +# +# product_type +# string, product type for the generated Xcode project, use +# "com.apple.product-type.bundle.unit-test" for unit test and +# "com.apple.product-type.bundle.ui-testing" for UI testing. +# +# host_target: +# string, name of the target that depends on the generated bundle, this +# value is used to restrict visibilities. +# +# xcode_test_application_name: +# string, name of the test application for Xcode unit or ui test target. +# +# output_name +# (optional) string, name of the generated application, if omitted, +# defaults to the target_name. +# +# This template defines two targets, one named "${target_name}" is the xctest +# bundle, and the other named "${target_name}_bundle" is a bundle_data that +# wraps the xctest bundle and that only the "${host_target}" can depend on. +# +template("ios_xctest_bundle") { + assert(defined(invoker.deps), "deps must be defined for $target_name") + assert(defined(invoker.product_type), + "product_type must be defined for $target_name") + assert(invoker.product_type == _ios_xcode_xctest_bundle_id || + invoker.product_type == _ios_xcode_xcuitest_bundle_id, + "product_type defined for $target_name is invalid.") + assert(defined(invoker.host_target), + "host_target must be defined for $target_name") + assert(defined(invoker.xcode_test_application_name), + "xcode_test_application_name must be defined for $target_name") + + # Silence "assignment had no effect" error for non-default toolchains as + # following variables are only used in the expansion of the template for the + # default toolchain. + if (is_fat_secondary_toolchain) { + not_needed(invoker, "*") + } + + _target_name = target_name + _output_name = target_name + + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + _arch_loadable_module_source = _target_name + "_arch_loadable_module_source" + _arch_loadable_module_target = _target_name + "_arch_loadable_module" + _lipo_loadable_module_target = _target_name + "_loadable_module" + + _primary_toolchain = current_toolchain + if (is_fat_secondary_toolchain) { + _primary_toolchain = primary_fat_toolchain_name + } + + source_set(_arch_loadable_module_source) { + forward_variables_from(invoker, [ "deps" ]) + + testonly = true + visibility = [ ":$_arch_loadable_module_target" ] + } + + loadable_module(_arch_loadable_module_target) { + testonly = true + visibility = [ ":$_lipo_loadable_module_target($_primary_toolchain)" ] + if (is_fat_secondary_toolchain) { + visibility += [ ":$_target_name" ] + } + + deps = [ ":$_arch_loadable_module_source" ] + configs += [ "//build/config/ios:xctest_config" ] + + output_dir = "$target_out_dir/$target_cpu" + output_name = _output_name + output_prefix_override = true + output_extension = "" + } + + if (is_fat_secondary_toolchain) { + # For fat builds, only the default toolchain will generate a test bundle. + # For the other toolchains, the template is only used for building the + # arch-specific binary, thus the default target is just a group(). + group(_target_name) { + forward_variables_from(invoker, [ "visibility" ]) + testonly = true + + public_deps = [ ":$_arch_loadable_module_target" ] + } + + not_needed(invoker, "*") + } else { + _info_plist_target = _target_name + "_info_plist" + _info_plist_bundle = _target_name + "_info_plist_bundle" + + ios_info_plist(_info_plist_target) { + testonly = true + visibility = [ ":$_info_plist_bundle" ] + + info_plist = "//build/config/ios/Module-Info.plist" + executable_name = _output_name + + if (defined(invoker.xctest_bundle_principal_class)) { + _principal_class = invoker.xctest_bundle_principal_class + } else { + # Fall back to a reasonable default value. + _principal_class = "NSObject" + } + extra_substitutions = [ + "XCTEST_BUNDLE_PRINCIPAL_CLASS=${_principal_class}", + "MODULE_BUNDLE_ID=gtest.$_output_name", + ] + } + + bundle_data(_info_plist_bundle) { + testonly = true + visibility = [ ":$_target_name" ] + + public_deps = [ ":$_info_plist_target" ] + + sources = get_target_outputs(":$_info_plist_target") + outputs = [ "{{bundle_contents_dir}}/Info.plist" ] + } + + lipo_binary(_lipo_loadable_module_target) { + forward_variables_from(invoker, [ "configs" ]) + + testonly = true + visibility = [ ":$_target_name" ] + + output_name = _output_name + arch_binary_target = ":$_arch_loadable_module_target" + arch_binary_output = _output_name + } + + _xctest_bundle = _target_name + "_bundle" + create_signed_bundle(_target_name) { + forward_variables_from(invoker, + [ + "bundle_id", + "data_deps", + "enable_code_signing", + "product_type", + "xcode_test_application_name", + ]) + + testonly = true + visibility = [ ":$_xctest_bundle" ] + + bundle_extension = ".xctest" + + output_name = _output_name + bundle_binary_target = ":$_lipo_loadable_module_target" + bundle_binary_output = _output_name + + if (ios_set_attributes_for_xcode_project_generation) { + _xcode_product_bundle_id = + "$ios_app_bundle_id_prefix.gtest.$_output_name" + + _ios_provisioning_profile_info = + exec_script("//build/config/ios/codesign.py", + [ + "find-provisioning-profile", + "-b=" + _xcode_product_bundle_id, + ], + "json") + + xcode_extra_attributes = { + IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target + CODE_SIGN_IDENTITY = "iPhone Developer" + DEVELOPMENT_TEAM = _ios_provisioning_profile_info.team_identifier + PRODUCT_BUNDLE_IDENTIFIER = _xcode_product_bundle_id + PROVISIONING_PROFILE_SPECIFIER = _ios_provisioning_profile_info.name + + # For XCUITest, Xcode requires specifying the host application name + # via the TEST_TARGET_NAME attribute. + if (invoker.product_type == _ios_xcode_xcuitest_bundle_id) { + TEST_TARGET_NAME = invoker.xcode_test_application_name + } + + # For XCTest, Xcode requires specifying the host application path via + # both BUNDLE_LOADER and TEST_HOST attributes. + if (invoker.product_type == _ios_xcode_xctest_bundle_id) { + _xcode_app_name = invoker.xcode_test_application_name + if (defined(invoker.xcode_test_application_output_name)) { + _xcode_app_name = invoker.xcode_test_application_output_name + } + + BUNDLE_LOADER = "\$(TEST_HOST)" + TEST_HOST = "\$(BUILT_PRODUCTS_DIR)/" + + "${_xcode_app_name}.app/${_xcode_app_name}" + } + } + } else { + not_needed(invoker, + [ + "xcode_test_application_name", + "xcode_test_application_output_name", + ]) + } + + deps = [ ":$_info_plist_bundle" ] + } + + bundle_data(_xctest_bundle) { + forward_variables_from(invoker, [ "host_target" ]) + + testonly = true + visibility = [ ":$host_target" ] + + public_deps = [ ":$_target_name" ] + sources = [ "$root_out_dir/$_output_name.xctest" ] + outputs = [ "{{bundle_contents_dir}}/PlugIns/$_output_name.xctest" ] + } + } +} + +set_defaults("ios_xctest_bundle") { + configs = default_shared_library_configs +} + +# For Chrome on iOS we want to run XCTests for all our build configurations +# (Debug, Release, ...). In addition, the symbols visibility is configured to +# private by default. To simplify testing with those constraints, our tests are +# compiled in the TEST_HOST target instead of the .xctest bundle. +template("ios_xctest_test") { + _target_name = target_name + _output_name = target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + _xctest_target = _target_name + "_module" + _xctest_output = _output_name + "_module" + + _host_target = _target_name + _host_output = _output_name + + # Allow invokers to specify their own target for the xctest module, but + # fall back to a default (empty) module otherwise. + if (defined(invoker.xctest_module_target)) { + _xctest_module_target = invoker.xctest_module_target + } else { + _xctest_module_target_name = _xctest_target + "shell_source" + _xctest_module_target = ":$_xctest_module_target_name" + source_set(_xctest_module_target_name) { + sources = [ "//build/config/ios/xctest_shell.mm" ] + + configs += [ "//build/config/ios:xctest_config" ] + } + } + + ios_xctest_bundle(_xctest_target) { + forward_variables_from(invoker, [ "data_deps" ]) + output_name = _xctest_output + product_type = _ios_xcode_xctest_bundle_id + host_target = _host_target + + # TODO(crbug.com/1056328) The change in output name results in a mismatch + # between this value and the ios_app_bundle target name. To mitigate, this + # has been modified to _host_target. output_name is set to _host_output + # to mitigate the naming. + xcode_test_application_name = _host_target + xcode_test_application_output_name = _host_output + + deps = [ _xctest_module_target ] + } + + ios_app_bundle(_host_target) { + forward_variables_from(invoker, "*", [ "testonly" ]) + + testonly = true + output_name = _host_output + configs += [ "//build/config/ios:xctest_config" ] + + if (!defined(invoker.info_plist) && !defined(invoker.info_plist_target)) { + info_plist = "//build/config/ios/Host-Info.plist" + } + + # Xcode needs the following frameworks installed in the application (and + # signed) for the XCTest to run, so install them using + # extra_system_frameworks. + extra_system_frameworks = [ + "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework", + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework", + "$ios_sdk_platform_path/Developer/usr/lib/libXCTestBundleInject.dylib", + ] + + # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over + # everything that Xcode copies. + if (xcode_version_int >= 1300) { + extra_system_frameworks += [ + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework", + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework", + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework", + "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib", + ] + } + + _xctest_bundle = _xctest_target + "_bundle" + if (!is_fat_secondary_toolchain) { + if (!defined(bundle_deps)) { + bundle_deps = [] + } + bundle_deps += [ ":$_xctest_bundle" ] + } + } +} + +set_defaults("ios_xctest_test") { + configs = default_executable_configs +} + +# Template to build a xcuitest test runner bundle. +# +# Xcode requires a test runner application with a copy of the XCTest dynamic +# library bundle in it for the XCUITest to run. The test runner bundle is created +# by copying the system bundle XCTRunner.app from Xcode SDK with the plist file +# being properly tweaked, and a xctest and it needs to be code signed in order +# to run on devices. +# +# Arguments +# +# xctest_bundle +# string, name of the dependent xctest bundle target. +# +# output_name +# (optional) string, name of the generated application, if omitted, +# defaults to the target_name. +# +template("ios_xcuitest_test_runner_bundle") { + assert(defined(invoker.xctest_bundle), + "xctest_bundle must be defined for $target_name") + + _target_name = target_name + _output_name = target_name + if (defined(invoker.output_name)) { + _output_name = invoker.output_name + } + + _xctrunner_path = + "$ios_sdk_platform_path/Developer/Library/Xcode/Agents/XCTRunner.app" + + _info_plist_merge_plist = _target_name + "_info_plist_merge_plist" + _info_plist_target = _target_name + "_info_plist" + _info_plist_bundle = _target_name + "_info_plist_bundle" + + action(_info_plist_merge_plist) { + testonly = true + script = "//build/apple/plist_util.py" + + sources = [ + "$_xctrunner_path/Info.plist", + + # NOTE: The XCTRunnerAddition+Info.plist must come after the Info.plist + # because it overrides the values under "CFBundleIdentifier" and + # "CFBundleName". + "//build/config/ios/resources/XCTRunnerAddition+Info.plist", + ] + + _output_name = "$target_gen_dir/${_target_name}_merged.plist" + outputs = [ _output_name ] + args = [ + "merge", + "-f=xml1", + "-x=$xcode_version", + "-o=" + rebase_path(_output_name, root_build_dir), + ] + rebase_path(sources, root_build_dir) + + if (use_system_xcode && use_goma) { + deps = [ "//build/config/ios:copy_xctrunner_app" ] + } + } + + ios_info_plist(_info_plist_target) { + testonly = true + visibility = [ ":$_info_plist_bundle" ] + + executable_name = _output_name + info_plist_target = ":$_info_plist_merge_plist" + } + + bundle_data(_info_plist_bundle) { + testonly = true + visibility = [ ":$_target_name" ] + + public_deps = [ ":$_info_plist_target" ] + + sources = get_target_outputs(":$_info_plist_target") + outputs = [ "{{bundle_contents_dir}}/Info.plist" ] + } + + _pkginfo_bundle = _target_name + "_pkginfo_bundle" + bundle_data(_pkginfo_bundle) { + testonly = true + visibility = [ ":$_target_name" ] + + sources = [ "$_xctrunner_path/PkgInfo" ] + + outputs = [ "{{bundle_contents_dir}}/PkgInfo" ] + + if (use_system_xcode && use_goma) { + public_deps = [ "//build/config/ios:copy_xctrunner_app" ] + } + } + + _xctest_bundle = invoker.xctest_bundle + create_signed_bundle(_target_name) { + testonly = true + + bundle_binary_target = "//build/config/ios:xctest_runner_without_arm64e" + bundle_binary_output = "XCTRunner" + bundle_extension = ".app" + product_type = _ios_xcode_app_bundle_id + + output_name = _output_name + + # Xcode needs the following frameworks installed in the application + # (and signed) for the XCUITest to run, so install them using + # extra_system_frameworks. + extra_system_frameworks = [ + "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework", + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework", + ] + + # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over + # everything that Xcode copies. + if (xcode_version_int >= 1300) { + extra_system_frameworks += [ + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework", + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework", + "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework", + "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib", + ] + } + + bundle_deps = [] + if (defined(invoker.bundle_deps)) { + bundle_deps += invoker.bundle_deps + } + bundle_deps += [ + ":$_info_plist_bundle", + ":$_pkginfo_bundle", + ":$_xctest_bundle", + ] + } +} + +# Template to build a XCUITest that consists of two parts: the test runner +# application bundle and the xctest dynamic library. +# +# Arguments +# +# deps: +# list of labels to depends on, these values are used to create the +# xctest dynamic library. +# +# xcode_test_application_name: +# string, name of the test application for the ui test target. +# +# This template defines two targets, one named "${target_name}_module" is the +# xctest dynamic library, and the other named "${target_name}_runner" is the +# test runner application bundle. +# +template("ios_xcuitest_test") { + assert(defined(invoker.deps), "deps must be defined for $target_name") + assert(defined(invoker.xcode_test_application_name), + "xcode_test_application_name must be defined for $target_name") + + _xcuitest_target = target_name + if (defined(invoker.output_name)) { + _xcuitest_target = invoker.output_name + } + + _xcuitest_runner_target = _xcuitest_target + "_runner" + _xcuitest_module_target = _xcuitest_target + "_module" + + group(target_name) { + testonly = true + + deps = [ ":$_xcuitest_runner_target" ] + } + + _xcuitest_module_output = _xcuitest_target + ios_xctest_bundle(_xcuitest_module_target) { + forward_variables_from(invoker, + [ + "xcode_test_application_name", + "xctest_bundle_principal_class", + "data_deps", + ]) + + product_type = _ios_xcode_xcuitest_bundle_id + host_target = _xcuitest_runner_target + output_name = _xcuitest_module_output + + deps = invoker.deps + } + + _xcuitest_runner_output = _xcuitest_target + "-Runner" + ios_xcuitest_test_runner_bundle(_xcuitest_runner_target) { + output_name = _xcuitest_runner_output + xctest_bundle = _xcuitest_module_target + "_bundle" + forward_variables_from(invoker, [ "bundle_deps" ]) + } +} + +set_defaults("ios_xcuitest_test") { + configs = default_executable_configs +} |