tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

rules.gni (54226B)


      1 # Copyright 2015 The Chromium Authors
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import("//chromium/build/apple/apple_info_plist.gni")
      6 import("//chromium/build/config/apple/create_signed_bundle.gni")
      7 import("//chromium/build/config/apple/mobile_bundle_data.gni")
      8 import("//chromium/build/config/apple/symbols.gni")
      9 import("//chromium/build/config/compiler/compiler.gni")
     10 import("//chromium/build/config/ios/ios_sdk.gni")
     11 import("//chromium/build/toolchain/rbe.gni")
     12 import("//chromium/build/toolchain/siso.gni")
     13 import("//chromium/build/toolchain/toolchain.gni")
     14 import("//build_overrides/build.gni")
     15 
     16 # iOS-specific wrapper around apple_mobile_create_signed_bundle.
     17 #
     18 # See //build/config/apple/mobile_rules.gni for a description of arguments.
     19 template("ios_create_signed_bundle") {
     20   apple_mobile_create_signed_bundle(target_name) {
     21     forward_variables_from(invoker,
     22                            "*",
     23                            [
     24                              "platform_sdk_name",
     25                              "xcode_extra_attributes",
     26                            ])
     27     platform_sdk_name = ios_sdk_name
     28     xcode_extra_attributes = {
     29       IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target
     30 
     31       # If invoker has defined extra attributes, they override the defaults.
     32       if (defined(invoker.xcode_extra_attributes)) {
     33         forward_variables_from(invoker.xcode_extra_attributes, "*")
     34       }
     35     }
     36   }
     37 }
     38 
     39 # Expose the template under its original name, to avoid breaking dependencies.
     40 template("create_signed_bundle") {
     41   ios_create_signed_bundle(target_name) {
     42     forward_variables_from(invoker, "*", TESTONLY_AND_VISIBILITY)
     43     forward_variables_from(invoker, TESTONLY_AND_VISIBILITY)
     44   }
     45 }
     46 
     47 # Generates Info.plist files for iOS apps and frameworks.
     48 #
     49 # Arguments
     50 #
     51 #     info_plist:
     52 #         (optional) string, path to the Info.plist file that will be used for
     53 #         the bundle.
     54 #
     55 #     info_plist_target:
     56 #         (optional) string, if the info_plist is generated from an action,
     57 #         rather than a regular source file, specify the target name in lieu
     58 #         of info_plist. The two arguments are mutually exclusive.
     59 #
     60 #     executable_name:
     61 #         string, name of the generated target used for the product
     62 #         and executable name as specified in the output Info.plist.
     63 #
     64 #     extra_substitutions:
     65 #         (optional) string array, 'key=value' pairs for extra fields which are
     66 #         specified in a source Info.plist template.
     67 template("ios_info_plist") {
     68   assert(defined(invoker.info_plist) != defined(invoker.info_plist_target),
     69          "Only one of info_plist or info_plist_target may be specified in " +
     70              target_name)
     71 
     72   if (defined(invoker.info_plist)) {
     73     _info_plist = invoker.info_plist
     74   } else {
     75     _info_plist_target_output = get_target_outputs(invoker.info_plist_target)
     76     _info_plist = _info_plist_target_output[0]
     77   }
     78 
     79   apple_info_plist(target_name) {
     80     format = "binary1"
     81     extra_substitutions = [
     82       "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix",
     83       "IOS_PLATFORM_BUILD=$ios_platform_build",
     84       "IOS_PLATFORM_NAME=$ios_sdk_name",
     85       "IOS_PLATFORM_VERSION=$ios_sdk_version",
     86       "IOS_SDK_BUILD=$ios_sdk_build",
     87       "IOS_SDK_NAME=$ios_sdk_name$ios_sdk_version",
     88       "IOS_SUPPORTED_PLATFORM=$ios_sdk_platform",
     89       "BUILD_MACHINE_OS_BUILD=$machine_os_build",
     90       "IOS_DEPLOYMENT_TARGET=$ios_deployment_target",
     91       "XCODE_BUILD=$xcode_build",
     92       "XCODE_VERSION=$xcode_version",
     93     ]
     94     if (defined(invoker.extra_substitutions)) {
     95       extra_substitutions += invoker.extra_substitutions
     96     }
     97     plist_templates = [
     98       "//chromium/build/config/ios/BuildInfo.plist",
     99       _info_plist,
    100     ]
    101     if (defined(invoker.info_plist_target)) {
    102       deps = [ invoker.info_plist_target ]
    103     }
    104     forward_variables_from(invoker,
    105                            [
    106                              "executable_name",
    107                              "output_name",
    108                              "visibility",
    109                              "testonly",
    110                            ])
    111   }
    112 }
    113 
    114 # Template to build an application bundle for iOS.
    115 #
    116 # This should be used instead of "executable" built-in target type on iOS.
    117 # As the template forward the generation of the application executable to
    118 # an "executable" target, all arguments supported by "executable" targets
    119 # are also supported by this template.
    120 #
    121 # Arguments
    122 #
    123 #   output_name:
    124 #       (optional) string, name of the generated application, if omitted,
    125 #       defaults to the target_name.
    126 #
    127 #   extra_substitutions:
    128 #       (optional) list of string in "key=value" format, each value will
    129 #       be used as an additional variable substitution rule when generating
    130 #       the application Info.plist
    131 #
    132 #   info_plist:
    133 #       (optional) string, path to the Info.plist file that will be used for
    134 #       the bundle.
    135 #
    136 #   info_plist_target:
    137 #       (optional) string, if the info_plist is generated from an action,
    138 #       rather than a regular source file, specify the target name in lieu
    139 #       of info_plist. The two arguments are mutually exclusive.
    140 #
    141 #   entitlements_path:
    142 #       (optional) path to the template to use to generate the application
    143 #       entitlements by performing variable substitutions, defaults to
    144 #       //build/config/ios/entitlements.plist.
    145 #
    146 #   entitlements_target:
    147 #       (optional) label of the target generating the application
    148 #       entitlements (must generate a single file as output); cannot be
    149 #       defined if entitlements_path is set.
    150 #
    151 #   product_type
    152 #       (optional) string, product type for the generated Xcode project,
    153 #       default to "com.apple.product-type.application". Should only be
    154 #       overriden when building application extension.
    155 #
    156 #   enable_code_signing
    157 #       (optional) boolean, control whether code signing is enabled or not,
    158 #       default to ios_enable_code_signing if not defined.
    159 #
    160 #   variants
    161 #       (optional) list of scopes, each scope needs to define the attributes
    162 #       "name" and "bundle_deps"; if defined and non-empty, then one bundle
    163 #       named $target_out_dir/$variant/$output_name will be created for each
    164 #       variant with the same binary but the correct bundle_deps, the bundle
    165 #       at $target_out_dir/$output_name will be a copy of the first variant.
    166 #
    167 #   bundle_identifier:
    168 #       (optional) string, value of CFBundleIdentifier in the application
    169 #       Info.plist, defaults to "$ios_app_bundle_id_prefix.$output_name"
    170 #       if omitted. Will be used to set BUNDLE_IDENTIFIER when generating
    171 #       the application Info.plist
    172 #
    173 #   orderfile_path:
    174 #       (optional) string, path to an orderfile passed to the linker in order
    175 #       to improve application launch performance.
    176 #
    177 #   intents_target:
    178 #       (optional) string, label of the target defining the intents for the
    179 #       application. If defined, it must corresponds to a `swift_source_set`
    180 #       target configured with `generate_intents = true`.
    181 #
    182 #   transparent
    183 #       (optional) boolean, whether the bundle is "transparent"; defaults to
    184 #       "false" if omitted; a bundle is considered "transparent" if it does
    185 #       not package the "bundle_data" deps but forward them to all targets
    186 #       the depend on it (unless the "bundle_data" target sets "product_type"
    187 #       to the same value as the "ios_create_signed_bundle" target).
    188 #
    189 # For more information, see "gn help executable".
    190 template("ios_app_bundle") {
    191   _output_name = target_name
    192   _target_name = target_name
    193   if (defined(invoker.output_name)) {
    194     _output_name = invoker.output_name
    195   }
    196 
    197   assert(
    198       !defined(invoker.bundle_extension),
    199       "bundle_extension must not be set for ios_app_bundle template for $target_name")
    200 
    201   # Whether the intents metadata should be extracted (note that they are
    202   # disabled when building for the catalyst environment)
    203   _extract_intents_metadata = false
    204   if (defined(invoker.intents_target)) {
    205     _extract_intents_metadata =
    206         invoker.intents_target != "" && target_environment != "catalyst"
    207   }
    208 
    209   if (defined(invoker.bundle_identifier)) {
    210     _bundle_identifier = invoker.bundle_identifier
    211     assert(_bundle_identifier == string_replace(_bundle_identifier, "_", "-"),
    212            "$target_name: bundle_identifier does not respect rfc1034: " +
    213                _bundle_identifier)
    214   } else {
    215     # Bundle identifier should respect rfc1034, so replace "_" with "-".
    216     _bundle_identifier =
    217         "$ios_app_bundle_id_prefix." + string_replace(_output_name, "_", "-")
    218   }
    219 
    220   if (defined(invoker.variants) && invoker.variants != []) {
    221     _variants = []
    222 
    223     foreach(_variant, invoker.variants) {
    224       assert(defined(_variant.name) && _variant.name != "",
    225              "name must be defined for all $target_name variants")
    226 
    227       assert(defined(_variant.bundle_deps),
    228              "bundle_deps must be defined for all $target_name variants")
    229 
    230       _variants += [
    231         {
    232           name = _variant.name
    233           bundle_deps = _variant.bundle_deps
    234           target_name = "${_target_name}_variants_${_variant.name}"
    235           bundle_gen_dir = "$root_out_dir/variants/${_variant.name}"
    236         },
    237       ]
    238     }
    239   } else {
    240     # If no variants are passed to the template, use a fake variant with
    241     # no name to avoid duplicating code. As no variant can have an empty
    242     # name except this fake variant, it is possible to know if a variant
    243     # is fake or not.
    244     _variants = [
    245       {
    246         name = ""
    247         bundle_deps = []
    248         target_name = _target_name
    249         bundle_gen_dir = root_out_dir
    250       },
    251     ]
    252   }
    253 
    254   _default_variant = _variants[0]
    255 
    256   _executable_target = _target_name + "_executable"
    257   _generate_entitlements_target = _target_name + "_gen_entitlements"
    258   _generate_entitlements_output =
    259       get_label_info(":$_generate_entitlements_target", "target_out_dir") +
    260       "/$_output_name.xcent"
    261 
    262   _product_type = apple_mobile_xcode_app_bundle_id
    263   if (defined(invoker.product_type)) {
    264     _product_type = invoker.product_type
    265   }
    266 
    267   if (_product_type == apple_mobile_xcode_app_bundle_id) {
    268     _bundle_extension = ".app"
    269   } else if (_product_type == apple_mobile_xcode_appex_bundle_id) {
    270     _bundle_extension = ".appex"
    271   } else {
    272     assert(false, "unknown product_type \"$product_type\" for $_target_name")
    273   }
    274 
    275   _is_app_bundle = _product_type == apple_mobile_xcode_app_bundle_id
    276 
    277   if (_extract_intents_metadata) {
    278     _metadata_extraction = _target_name + "_metadata_extraction"
    279     _metadata_bundledata = _target_name + "_metadata_bundledata"
    280   }
    281 
    282   executable(_executable_target) {
    283     forward_variables_from(invoker,
    284                            "*",
    285                            [
    286                              "bundle_deps",
    287                              "bundle_deps_filter",
    288                              "bundle_extension",
    289                              "enable_code_signing",
    290                              "entitlements_path",
    291                              "entitlements_target",
    292                              "extra_substitutions",
    293                              "extra_system_frameworks",
    294                              "info_plist",
    295                              "info_plist_target",
    296                              "output_name",
    297                              "product_type",
    298                              "transparent",
    299                              "visibility",
    300                              "xcode_extra_attributes",
    301                            ])
    302 
    303     if (!defined(deps)) {
    304       deps = []
    305     }
    306 
    307     visibility = []
    308     foreach(_variant, _variants) {
    309       visibility += [ ":${_variant.target_name}" ]
    310     }
    311     if (_extract_intents_metadata) {
    312       visibility += [ ":$_metadata_extraction" ]
    313       deps += [ invoker.intents_target ]
    314     }
    315 
    316     if (defined(invoker.orderfile_path)) {
    317       orderfile_path = invoker.orderfile_path
    318       if (!defined(ldflags)) {
    319         ldflags = []
    320       }
    321       ldflags += [
    322         "-Wl,-order_file",
    323         "-Wl," + rebase_path(orderfile_path, root_build_dir),
    324       ]
    325 
    326       if (!defined(inputs)) {
    327         inputs = []
    328       }
    329       inputs += [ orderfile_path ]
    330     }
    331 
    332     if (target_environment == "simulator") {
    333       deps += [ ":$_generate_entitlements_target" ]
    334 
    335       if (!defined(inputs)) {
    336         inputs = []
    337       }
    338       inputs += [ _generate_entitlements_output ]
    339 
    340       if (!defined(ldflags)) {
    341         ldflags = []
    342       }
    343       ldflags += [ "-Wl,-sectcreate,__TEXT,__entitlements," +
    344                    rebase_path(_generate_entitlements_output, root_build_dir) ]
    345     }
    346 
    347     output_name = _output_name
    348     output_prefix_override = true
    349     output_dir = target_out_dir
    350   }
    351 
    352   if (_extract_intents_metadata) {
    353     _module_info_path =
    354         get_label_info(invoker.intents_target, "target_out_dir") + "/" +
    355         get_label_info(invoker.intents_target, "name") + ".module_info.json"
    356 
    357     action(_metadata_extraction) {
    358       _output_dir = "$target_out_dir/$target_name"
    359       _binary_path = "$target_out_dir/$_output_name"
    360 
    361       visibility = [ ":$_metadata_bundledata" ]
    362       script = "//chromium/build/config/ios/extract_metadata.py"
    363       sources = [
    364         _binary_path,
    365         _module_info_path,
    366       ]
    367       outputs = [
    368         "$_output_dir/Metadata.appintents/extract.actionsdata",
    369         "$_output_dir/Metadata.appintents/version.json",
    370       ]
    371       deps = [
    372         ":$_executable_target",
    373         invoker.intents_target,
    374       ]
    375       depfile = "$target_out_dir/$target_name.d"
    376       args = [
    377         "--toolchain-dir",
    378         rebase_path(ios_toolchains_path, root_build_dir),
    379         "--sdk-root",
    380         rebase_path(ios_sdk_path, root_build_dir),
    381         "--deployment-target",
    382         ios_deployment_target,
    383         "--target-cpu",
    384         target_cpu,
    385         "--target-environment",
    386         target_environment,
    387         "--depfile",
    388         rebase_path(depfile, root_build_dir),
    389         "--output",
    390         rebase_path(_output_dir, root_build_dir),
    391         "--binary-file",
    392         rebase_path(_binary_path, root_build_dir),
    393         "--module-info-path",
    394         rebase_path(_module_info_path, root_build_dir),
    395       ]
    396 
    397       # Starting with Xcode 15.3, appintentsmetadataprocessor requires to be
    398       # passed --xcode-version as parameter (with ${xcode_build} as value),
    399       # while previous versions did not recognize the parameter. So check
    400       # the version before deciding whether to set the parameter or not.
    401       if (xcode_version_int >= 1530) {
    402         args += [
    403           "--xcode-version",
    404           xcode_build,
    405         ]
    406       }
    407     }
    408 
    409     bundle_data(_metadata_bundledata) {
    410       public_deps = [ ":$_metadata_extraction" ]
    411       sources = get_target_outputs(":$_metadata_extraction")
    412       outputs = [ "{{bundle_resources_dir}}/" +
    413                   "Metadata.appintents/{{source_file_part}}" ]
    414     }
    415   }
    416 
    417   _generate_info_plist = target_name + "_generate_info_plist"
    418   ios_info_plist(_generate_info_plist) {
    419     forward_variables_from(invoker,
    420                            [
    421                              "info_plist",
    422                              "info_plist_target",
    423                            ])
    424 
    425     executable_name = _output_name
    426 
    427     extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ]
    428     if (defined(invoker.extra_substitutions)) {
    429       extra_substitutions += invoker.extra_substitutions
    430     }
    431   }
    432 
    433   if (!defined(invoker.entitlements_target)) {
    434     _entitlements_path = "//chromium/build/config/ios/entitlements.plist"
    435     if (defined(invoker.entitlements_path)) {
    436       _entitlements_path = invoker.entitlements_path
    437     }
    438   } else {
    439     assert(!defined(invoker.entitlements_path),
    440            "Cannot define both entitlements_path and entitlements_target" +
    441                "for $_target_name")
    442 
    443     _entitlements_target_outputs =
    444         get_target_outputs(invoker.entitlements_target)
    445     _entitlements_path = _entitlements_target_outputs[0]
    446   }
    447 
    448   action(_generate_entitlements_target) {
    449     _gen_info_plist_outputs = get_target_outputs(":$_generate_info_plist")
    450     _info_plist_path = _gen_info_plist_outputs[0]
    451 
    452     script = "//chromium/build/config/apple/codesign.py"
    453     deps = [ ":$_generate_info_plist" ]
    454     if (defined(invoker.entitlements_target)) {
    455       deps += [ invoker.entitlements_target ]
    456     }
    457     sources = [
    458       _entitlements_path,
    459       _info_plist_path,
    460     ]
    461     sources += ios_mobileprovision_files
    462 
    463     outputs = [ _generate_entitlements_output ]
    464 
    465     args = [
    466       "generate-entitlements",
    467       "-e=" + rebase_path(_entitlements_path, root_build_dir),
    468       "-p=" + rebase_path(_info_plist_path, root_build_dir),
    469     ]
    470     foreach(mobileprovision, ios_mobileprovision_files) {
    471       args += [ "-m=" + rebase_path(mobileprovision, root_build_dir) ]
    472     }
    473     args += rebase_path(outputs, root_build_dir)
    474   }
    475 
    476   # Only write PkgInfo for real application, not application extension.
    477   if (_is_app_bundle) {
    478     _create_pkg_info = target_name + "_pkg_info"
    479     action(_create_pkg_info) {
    480       forward_variables_from(invoker, [ "testonly" ])
    481       script = "//chromium/build/apple/write_pkg_info.py"
    482       inputs = [ "//chromium/build/apple/plist_util.py" ]
    483       sources = get_target_outputs(":$_generate_info_plist")
    484       outputs = [
    485         # Cannot name the output PkgInfo as the name will not be unique if
    486         # multiple ios_app_bundle are defined in the same BUILD.gn file. The
    487         # file is renamed in the bundle_data outputs to the correct name.
    488         "$target_gen_dir/$target_name",
    489       ]
    490       args = [ "--plist" ] + rebase_path(sources, root_build_dir) +
    491              [ "--output" ] + rebase_path(outputs, root_build_dir)
    492       deps = [ ":$_generate_info_plist" ]
    493     }
    494 
    495     _bundle_data_pkg_info = target_name + "_bundle_data_pkg_info"
    496     bundle_data(_bundle_data_pkg_info) {
    497       forward_variables_from(invoker, [ "testonly" ])
    498       sources = get_target_outputs(":$_create_pkg_info")
    499       outputs = [ "{{bundle_resources_dir}}/PkgInfo" ]
    500       public_deps = [ ":$_create_pkg_info" ]
    501     }
    502   }
    503 
    504   foreach(_variant, _variants) {
    505     ios_create_signed_bundle(_variant.target_name) {
    506       forward_variables_from(invoker,
    507                              [
    508                                "bundle_deps",
    509                                "bundle_deps_filter",
    510                                "data_deps",
    511                                "deps",
    512                                "enable_code_signing",
    513                                "entitlements_path",
    514                                "entitlements_target",
    515                                "extra_system_frameworks",
    516                                "public_configs",
    517                                "public_deps",
    518                                "testonly",
    519                                "transparent",
    520                                "visibility",
    521                                "xcasset_compiler_flags",
    522                                "xcode_extra_attributes",
    523                              ])
    524 
    525       output_name = _output_name
    526       bundle_gen_dir = _variant.bundle_gen_dir
    527       bundle_binary_target = ":$_executable_target"
    528       bundle_binary_output = _output_name
    529       bundle_extension = _bundle_extension
    530       product_type = _product_type
    531       xcode_product_bundle_id = _bundle_identifier
    532 
    533       _generate_info_plist_outputs =
    534           get_target_outputs(":$_generate_info_plist")
    535       primary_info_plist = _generate_info_plist_outputs[0]
    536       partial_info_plist =
    537           "$target_gen_dir/${_variant.target_name}_partial_info.plist"
    538 
    539       if (!defined(deps)) {
    540         deps = []
    541       }
    542       deps += [ ":$_generate_info_plist" ]
    543 
    544       if (!defined(bundle_deps)) {
    545         bundle_deps = []
    546       }
    547       if (_is_app_bundle) {
    548         bundle_deps += [ ":$_bundle_data_pkg_info" ]
    549       }
    550       bundle_deps += _variant.bundle_deps
    551       if (_extract_intents_metadata) {
    552         bundle_deps += [ ":$_metadata_bundledata" ]
    553       }
    554 
    555       if (target_environment == "simulator") {
    556         if (!defined(data_deps)) {
    557           data_deps = []
    558         }
    559         if (build_with_chromium) {
    560           data_deps += [ "//testing/iossim" ]
    561         }
    562       }
    563     }
    564   }
    565 
    566   if (_default_variant.name != "") {
    567     _bundle_short_name = "$_output_name$_bundle_extension"
    568     action(_target_name) {
    569       forward_variables_from(invoker, [ "testonly" ])
    570 
    571       script = "//chromium/build/config/ios/hardlink.py"
    572       public_deps = []
    573       foreach(_variant, _variants) {
    574         public_deps += [ ":${_variant.target_name}" ]
    575       }
    576 
    577       sources = [ "${_default_variant.bundle_gen_dir}/$_bundle_short_name" ]
    578       outputs = [ "$root_out_dir/$_bundle_short_name" ]
    579 
    580       args = [
    581                "--output-dir",
    582                rebase_path(root_out_dir, root_build_dir),
    583                "--relative-to",
    584                rebase_path(_default_variant.bundle_gen_dir, root_build_dir),
    585              ] + rebase_path(sources, root_build_dir)
    586     }
    587   }
    588 }
    589 
    590 set_defaults("ios_app_bundle") {
    591   configs = default_executable_configs
    592 }
    593 
    594 # Template to build an application extension bundle for iOS.
    595 #
    596 # This should be used instead of "executable" built-in target type on iOS.
    597 # As the template forward the generation of the application executable to
    598 # an "executable" target, all arguments supported by "executable" targets
    599 # are also supported by this template.
    600 #
    601 # Arguments
    602 #
    603 #   output_name:
    604 #       (optional) string, name of the generated application, if omitted,
    605 #       defaults to the target_name.
    606 #
    607 #   extra_substitutions:
    608 #       (optional) list of string in "key=value" format, each value will
    609 #       be used as an additional variable substitution rule when generating
    610 #       the application Info.plist
    611 #
    612 #   info_plist:
    613 #       (optional) string, path to the Info.plist file that will be used for
    614 #       the bundle.
    615 #
    616 #   info_plist_target:
    617 #       (optional) string, if the info_plist is generated from an action,
    618 #       rather than a regular source file, specify the target name in lieu
    619 #       of info_plist. The two arguments are mutually exclusive.
    620 #
    621 # For more information, see "gn help executable".
    622 template("ios_appex_bundle") {
    623   assert(ios_is_app_extension,
    624          "$target_name needs to be defined in app extension toolchain context")
    625   ios_app_bundle(target_name) {
    626     forward_variables_from(invoker,
    627                            "*",
    628                            [
    629                              "bundle_extension",
    630                              "product_type",
    631                            ])
    632     product_type = apple_mobile_xcode_appex_bundle_id
    633   }
    634 }
    635 
    636 set_defaults("ios_appex_bundle") {
    637   configs = [ "//chromium/build/config/ios:ios_extension_executable_flags" ]
    638 }
    639 
    640 # Template to package a shared library into an iOS framework bundle.
    641 #
    642 # By default, the bundle target this template generates does not link the
    643 # resulting framework into anything that depends on it. If a dependency wants
    644 # a link-time (as well as build-time) dependency on the framework bundle,
    645 # depend against "$target_name+link". If only the build-time dependency is
    646 # required (e.g., for copying into another bundle), then use "$target_name".
    647 #
    648 # Arguments
    649 #
    650 #     output_name:
    651 #         (optional) string, name of the generated framework without the
    652 #         .framework suffix. If omitted, defaults to target_name.
    653 #
    654 #     public_headers:
    655 #         (optional) list of paths to header file that needs to be copied
    656 #         into the framework bundle Headers subdirectory. If omitted or
    657 #         empty then the Headers subdirectory is not created.
    658 #
    659 #     sources
    660 #         (optional) list of files. Needs to be defined and non-empty if
    661 #         public_headers is defined and non-empty.
    662 #
    663 #   enable_code_signing
    664 #       (optional) boolean, control whether code signing is enabled or not,
    665 #       default to ios_enable_code_signing if not defined.
    666 #
    667 #   transparent
    668 #       (optional) boolean, whether the bundle is "transparent"; defaults to
    669 #       "false" if omitted; a bundle is considered "transparent" if it does
    670 #       not package the "bundle_data" deps but forward them to all targets
    671 #       the depend on it (unless the "bundle_data" target sets "product_type"
    672 #       to "com.apple.product-type.framework").
    673 #
    674 # This template provides two targets for the resulting framework bundle. The
    675 # link-time behavior varies depending on which of the two targets below is
    676 # added as a dependency:
    677 #   - $target_name only adds a build-time dependency. Targets that depend on
    678 #     it will not link against the framework.
    679 #   - $target_name+link adds a build-time and link-time dependency. Targets
    680 #     that depend on it will link against the framework.
    681 #
    682 # The build-time-only dependency is used for when a target needs to use the
    683 # framework either only for resources, or because the target loads it at run-
    684 # time, via dlopen() or NSBundle. The link-time dependency will cause the
    685 # dependee to have the framework loaded by dyld at launch.
    686 #
    687 # Example of build-time only dependency:
    688 #
    689 #     framework_bundle("CoreTeleportation") {
    690 #       sources = [ ... ]
    691 #     }
    692 #
    693 #     bundle_data("core_teleportation_bundle_data") {
    694 #       deps = [ ":CoreTeleportation" ]
    695 #       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
    696 #       outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
    697 #     }
    698 #
    699 #     app_bundle("GoatTeleporter") {
    700 #       sources = [ ... ]
    701 #       deps = [
    702 #         ":core_teleportation_bundle_data",
    703 #       ]
    704 #     }
    705 #
    706 # The GoatTeleporter.app will not directly link against
    707 # CoreTeleportation.framework, but it will be included in the bundle's
    708 # Frameworks directory.
    709 #
    710 # Example of link-time dependency:
    711 #
    712 #     framework_bundle("CoreTeleportation") {
    713 #       sources = [ ... ]
    714 #       ldflags = [
    715 #         "-install_name",
    716 #         "@executable_path/../Frameworks/$target_name.framework"
    717 #       ]
    718 #     }
    719 #
    720 #     bundle_data("core_teleportation_bundle_data") {
    721 #       deps = [ ":CoreTeleportation+link" ]
    722 #       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
    723 #       outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
    724 #     }
    725 #
    726 #     app_bundle("GoatTeleporter") {
    727 #       sources = [ ... ]
    728 #       deps = [
    729 #         ":core_teleportation_bundle_data",
    730 #       ]
    731 #     }
    732 #
    733 # Note that the framework is still copied to the app's bundle, but dyld will
    734 # load this library when the app is launched because it uses the "+link"
    735 # target as a dependency. This also requires that the framework set its
    736 # install_name so that dyld can locate it.
    737 #
    738 # See "gn help shared_library" for more information on arguments supported
    739 # by shared library target.
    740 template("ios_framework_bundle") {
    741   _target_name = target_name
    742   _output_name = target_name
    743   if (defined(invoker.output_name)) {
    744     _output_name = invoker.output_name
    745   }
    746 
    747   _product_type = "com.apple.product-type.framework"
    748   _has_public_headers =
    749       defined(invoker.public_headers) && invoker.public_headers != []
    750 
    751   _shared_library_target = _target_name + "_shared_library"
    752   _link_target_name = _target_name + "+link"
    753 
    754   if (_has_public_headers) {
    755     _default_toolchain_target_gen_dir =
    756         get_label_info("$_target_name", "target_gen_dir")
    757 
    758     _framework_headers_target = _target_name + "_framework_headers"
    759 
    760     _headers_map_config = _target_name + "_headers_map"
    761     _header_map_filename =
    762         "$_default_toolchain_target_gen_dir/$_output_name.headers.hmap"
    763     config(_headers_map_config) {
    764       visibility = [
    765         ":${_shared_library_target}",
    766         ":${_target_name}_signed_bundle",
    767       ]
    768       include_dirs = [ _header_map_filename ]
    769     }
    770   }
    771 
    772   _framework_headers_config = _target_name + "_framework_headers_config"
    773   config(_framework_headers_config) {
    774     framework_dirs = [ root_out_dir ]
    775   }
    776 
    777   _framework_public_config = _target_name + "_public_config"
    778   config(_framework_public_config) {
    779     configs = [ ":$_framework_headers_config" ]
    780     frameworks = [ "$_output_name.framework" ]
    781   }
    782 
    783   shared_library(_shared_library_target) {
    784     forward_variables_from(invoker,
    785                            "*",
    786                            [
    787                              "bundle_deps",
    788                              "bundle_deps_filter",
    789                              "data_deps",
    790                              "enable_code_signing",
    791                              "extra_substitutions",
    792                              "info_plist",
    793                              "info_plist_target",
    794                              "output_name",
    795                              "public_configs",
    796                              "transparent",
    797                              "visibility",
    798                            ])
    799 
    800     visibility = [ ":${_target_name}_signed_bundle" ]
    801 
    802     if (!defined(ldflags)) {
    803       ldflags = []
    804     }
    805     ldflags +=
    806         [ "-Wl,-install_name,@rpath/$_output_name.framework/$_output_name" ]
    807 
    808     if (_has_public_headers) {
    809       configs += [ ":$_headers_map_config" ]
    810 
    811       if (!defined(deps)) {
    812         deps = []
    813       }
    814       deps += [ ":$_framework_headers_target" ]
    815     }
    816 
    817     output_extension = ""
    818     output_name = _output_name
    819     output_prefix_override = true
    820     output_dir = target_out_dir
    821   }
    822 
    823   if (_has_public_headers) {
    824     _public_headers = invoker.public_headers
    825 
    826     _framework_root_dir = "$root_out_dir/$_output_name.framework"
    827     if (target_environment == "simulator" || target_environment == "device") {
    828       _framework_contents_dir = _framework_root_dir
    829     } else if (target_environment == "catalyst") {
    830       _framework_contents_dir = "$_framework_root_dir/Versions/A"
    831     }
    832 
    833     _compile_headers_map_target = _target_name + "_compile_headers_map"
    834     action(_compile_headers_map_target) {
    835       visibility = [ ":$_framework_headers_target" ]
    836       forward_variables_from(invoker,
    837                              [
    838                                "deps",
    839                                "public_deps",
    840                                "testonly",
    841                              ])
    842       script = "//chromium/build/config/apple/write_framework_hmap.py"
    843       outputs = [ _header_map_filename ]
    844 
    845       # The header map generation only wants the list of headers, not all of
    846       # sources, so filter any non-header source files from "sources". It is
    847       # less error prone that having the developer duplicate the list of all
    848       # headers in addition to "sources".
    849       sources = []
    850       if (defined(invoker.sources)) {
    851         foreach(_source, invoker.sources) {
    852           if (get_path_info(_source, "extension") == "h") {
    853             sources += [ _source ]
    854           }
    855         }
    856       }
    857 
    858       args = [
    859                rebase_path(_header_map_filename, root_build_dir),
    860                rebase_path(_framework_root_dir, root_build_dir),
    861              ] + rebase_path(sources, root_build_dir)
    862     }
    863 
    864     _create_module_map_target = _target_name + "_module_map"
    865     action(_create_module_map_target) {
    866       visibility = [ ":$_framework_headers_target" ]
    867       script = "//chromium/build/config/apple/write_framework_modulemap.py"
    868       outputs = [ "$_framework_contents_dir/Modules/module.modulemap" ]
    869       args = [
    870         _output_name,
    871         rebase_path("$_framework_contents_dir/Modules", root_build_dir),
    872       ]
    873     }
    874 
    875     _copy_public_headers_target = _target_name + "_copy_public_headers"
    876     copy(_copy_public_headers_target) {
    877       forward_variables_from(invoker,
    878                              [
    879                                "testonly",
    880                                "deps",
    881                              ])
    882       visibility = [ ":$_framework_headers_target" ]
    883       sources = _public_headers
    884       outputs = [ "$_framework_contents_dir/Headers/{{source_file_part}}" ]
    885 
    886       # Do not use forward_variables_from for "public_deps" as
    887       # we do not want to forward those dependencies.
    888       if (defined(invoker.public_deps)) {
    889         if (!defined(deps)) {
    890           deps = []
    891         }
    892         deps += invoker.public_deps
    893       }
    894     }
    895 
    896     group(_framework_headers_target) {
    897       forward_variables_from(invoker, [ "testonly" ])
    898       deps = [
    899         ":$_compile_headers_map_target",
    900         ":$_create_module_map_target",
    901       ]
    902       public_deps = [ ":$_copy_public_headers_target" ]
    903     }
    904   }
    905 
    906   # Bundle identifier should respect rfc1034, so replace "_" with "-".
    907   _bundle_identifier =
    908       "$ios_app_bundle_id_prefix." + string_replace(_output_name, "_", "-")
    909 
    910   _info_plist_target = _target_name + "_info_plist"
    911   _info_plist_bundle = _target_name + "_info_plist_bundle"
    912   ios_info_plist(_info_plist_target) {
    913     visibility = [ ":$_info_plist_bundle" ]
    914     executable_name = _output_name
    915     forward_variables_from(invoker,
    916                            [
    917                              "info_plist",
    918                              "info_plist_target",
    919                            ])
    920 
    921     extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ]
    922     if (defined(invoker.extra_substitutions)) {
    923       extra_substitutions += invoker.extra_substitutions
    924     }
    925   }
    926 
    927   bundle_data(_info_plist_bundle) {
    928     visibility = [ ":${_target_name}_signed_bundle" ]
    929     forward_variables_from(invoker, [ "testonly" ])
    930     sources = get_target_outputs(":$_info_plist_target")
    931     public_deps = [ ":$_info_plist_target" ]
    932     product_type = _product_type
    933 
    934     if (target_environment != "catalyst") {
    935       outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
    936     } else {
    937       outputs = [ "{{bundle_resources_dir}}/Info.plist" ]
    938     }
    939   }
    940 
    941   ios_create_signed_bundle(_target_name + "_signed_bundle") {
    942     forward_variables_from(invoker,
    943                            [
    944                              "bundle_deps",
    945                              "bundle_deps_filter",
    946                              "data_deps",
    947                              "deps",
    948                              "enable_code_signing",
    949                              "public_configs",
    950                              "public_deps",
    951                              "testonly",
    952                              "transparent",
    953                              "visibility",
    954                            ])
    955 
    956     product_type = _product_type
    957     bundle_extension = ".framework"
    958 
    959     output_name = _output_name
    960     bundle_binary_target = ":$_shared_library_target"
    961     bundle_binary_output = _output_name
    962 
    963     has_public_headers = _has_public_headers
    964 
    965     # Framework do not have entitlements nor mobileprovision because they use
    966     # the one from the bundle using them (.app or .appex) as they are just
    967     # dynamic library with shared code.
    968     disable_entitlements = true
    969     disable_embedded_mobileprovision = true
    970 
    971     if (!defined(deps)) {
    972       deps = []
    973     }
    974     deps += [ ":$_info_plist_bundle" ]
    975   }
    976 
    977   group(_target_name) {
    978     forward_variables_from(invoker,
    979                            [
    980                              "public_configs",
    981                              "public_deps",
    982                              "testonly",
    983                              "visibility",
    984                            ])
    985     if (!defined(public_deps)) {
    986       public_deps = []
    987     }
    988     public_deps += [ ":${_target_name}_signed_bundle" ]
    989 
    990     if (_has_public_headers) {
    991       if (!defined(public_configs)) {
    992         public_configs = []
    993       }
    994       public_configs += [ ":$_framework_headers_config" ]
    995     }
    996   }
    997 
    998   group(_link_target_name) {
    999     forward_variables_from(invoker,
   1000                            [
   1001                              "public_configs",
   1002                              "public_deps",
   1003                              "testonly",
   1004                              "visibility",
   1005                            ])
   1006     if (!defined(public_deps)) {
   1007       public_deps = []
   1008     }
   1009     public_deps += [ ":$_target_name" ]
   1010 
   1011     if (!defined(all_dependent_configs)) {
   1012       all_dependent_configs = []
   1013     }
   1014     all_dependent_configs += [ ":$_framework_public_config" ]
   1015   }
   1016 
   1017   bundle_data(_target_name + "+bundle") {
   1018     forward_variables_from(invoker,
   1019                            [
   1020                              "testonly",
   1021                              "visibility",
   1022                            ])
   1023     public_deps = [ ":$_target_name" ]
   1024     sources = [ "$root_out_dir/$_output_name.framework" ]
   1025     outputs = [ "{{bundle_contents_dir}}/Frameworks/$_output_name.framework" ]
   1026   }
   1027 }
   1028 
   1029 set_defaults("ios_framework_bundle") {
   1030   configs = default_shared_library_configs
   1031 }
   1032 
   1033 # Template to build a xctest bundle that contains a loadable module for iOS.
   1034 #
   1035 # Arguments
   1036 #
   1037 #   deps:
   1038 #       list of labels to depends on, these values are used to create the
   1039 #       loadable module.
   1040 #
   1041 #   product_type
   1042 #       string, product type for the generated Xcode project, use
   1043 #       "com.apple.product-type.bundle.unit-test" for unit test and
   1044 #       "com.apple.product-type.bundle.ui-testing" for UI testing.
   1045 #
   1046 #   host_target:
   1047 #       string, name of the target that depends on the generated bundle, this
   1048 #       value is used to restrict visibilities.
   1049 #
   1050 #   xcode_test_application_name:
   1051 #       string, name of the test application for Xcode unit or ui test target.
   1052 #
   1053 #   output_name
   1054 #       (optional) string, name of the generated application, if omitted,
   1055 #       defaults to the target_name.
   1056 #
   1057 # This template defines two targets, one named "${target_name}" is the xctest
   1058 # bundle, and the other named "${target_name}_bundle" is a bundle_data that
   1059 # wraps the xctest bundle and that only the "${host_target}" can depend on.
   1060 #
   1061 template("ios_xctest_bundle") {
   1062   assert(defined(invoker.deps), "deps must be defined for $target_name")
   1063   assert(defined(invoker.product_type),
   1064          "product_type must be defined for $target_name")
   1065   assert(invoker.product_type == apple_mobile_xcode_xctest_bundle_id ||
   1066              invoker.product_type == apple_mobile_xcode_xcuitest_bundle_id,
   1067          "product_type defined for $target_name is invalid.")
   1068   assert(defined(invoker.host_target),
   1069          "host_target must be defined for $target_name")
   1070   assert(defined(invoker.xcode_test_application_name),
   1071          "xcode_test_application_name must be defined for $target_name")
   1072 
   1073   _target_name = target_name
   1074   _output_name = target_name
   1075 
   1076   if (defined(invoker.output_name)) {
   1077     _output_name = invoker.output_name
   1078   }
   1079 
   1080   _loadable_module_target = _target_name + "_loadable_module"
   1081 
   1082   loadable_module(_loadable_module_target) {
   1083     forward_variables_from(invoker,
   1084                            "*",
   1085                            [
   1086                              "bundle_deps",
   1087                              "bundle_deps_filter",
   1088                              "host_target",
   1089                              "output_dir",
   1090                              "output_extension",
   1091                              "output_name",
   1092                              "output_prefix_override",
   1093                              "product_type",
   1094                              "testonly",
   1095                              "visibility",
   1096                              "xcode_test_application_name",
   1097                              "xcode_test_application_output_name",
   1098                              "xctest_bundle_principal_class",
   1099                            ])
   1100 
   1101     testonly = true
   1102     visibility = [ ":$_target_name" ]
   1103 
   1104     configs += [ "//chromium/build/config/ios:xctest_config" ]
   1105 
   1106     output_dir = target_out_dir
   1107     output_name = _output_name
   1108     output_prefix_override = true
   1109     output_extension = ""
   1110   }
   1111 
   1112   _info_plist_target = _target_name + "_info_plist"
   1113   _info_plist_bundle = _target_name + "_info_plist_bundle"
   1114 
   1115   # Bundle identifier should respect rfc1034, so replace "_" with "-".
   1116   _bundle_identifier = "$ios_app_bundle_id_prefix.chrome." +
   1117                        string_replace(_output_name, "_", "-")
   1118 
   1119   ios_info_plist(_info_plist_target) {
   1120     testonly = true
   1121     visibility = [ ":$_info_plist_bundle" ]
   1122 
   1123     info_plist = "//chromium/build/config/ios/Module-Info.plist"
   1124     executable_name = _output_name
   1125 
   1126     if (defined(invoker.xctest_bundle_principal_class)) {
   1127       _principal_class = invoker.xctest_bundle_principal_class
   1128     } else {
   1129       # Fall back to a reasonable default value.
   1130       _principal_class = "NSObject"
   1131     }
   1132     extra_substitutions = [
   1133       "XCTEST_BUNDLE_PRINCIPAL_CLASS=${_principal_class}",
   1134       "BUNDLE_IDENTIFIER=$_bundle_identifier",
   1135     ]
   1136   }
   1137 
   1138   bundle_data(_info_plist_bundle) {
   1139     testonly = true
   1140     visibility = [ ":$_target_name" ]
   1141 
   1142     public_deps = [ ":$_info_plist_target" ]
   1143 
   1144     sources = get_target_outputs(":$_info_plist_target")
   1145     outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
   1146   }
   1147 
   1148   _xctest_bundle = _target_name + "_bundle"
   1149   ios_create_signed_bundle(_target_name) {
   1150     forward_variables_from(invoker,
   1151                            [
   1152                              "bundle_deps",
   1153                              "bundle_deps_filter",
   1154                              "bundle_id",
   1155                              "data_deps",
   1156                              "enable_code_signing",
   1157                              "product_type",
   1158                              "transparent",
   1159                              "xcode_test_application_name",
   1160                            ])
   1161 
   1162     testonly = true
   1163     visibility = [ ":$_xctest_bundle" ]
   1164 
   1165     bundle_extension = ".xctest"
   1166 
   1167     output_name = _output_name
   1168     bundle_binary_target = ":$_loadable_module_target"
   1169     bundle_binary_output = _output_name
   1170 
   1171     xcode_extra_attributes = {
   1172       IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target
   1173       PRODUCT_BUNDLE_IDENTIFIER = _bundle_identifier
   1174       CODE_SIGNING_REQUIRED = "NO"
   1175       CODE_SIGNING_ALLOWED = "NO"
   1176       CODE_SIGN_IDENTITY = ""
   1177       DONT_GENERATE_INFOPLIST_FILE = "YES"
   1178 
   1179       # For XCUITest, Xcode requires specifying the host application name
   1180       # via the TEST_TARGET_NAME attribute.
   1181       if (invoker.product_type == apple_mobile_xcode_xcuitest_bundle_id) {
   1182         TEST_TARGET_NAME = invoker.xcode_test_application_name
   1183       }
   1184 
   1185       # For XCTest, Xcode requires specifying the host application path via
   1186       # both BUNDLE_LOADER and TEST_HOST attributes.
   1187       if (invoker.product_type == apple_mobile_xcode_xctest_bundle_id) {
   1188         _xcode_app_name = invoker.xcode_test_application_name
   1189         if (defined(invoker.xcode_test_application_output_name)) {
   1190           _xcode_app_name = invoker.xcode_test_application_output_name
   1191         }
   1192 
   1193         BUNDLE_LOADER = "\$(TEST_HOST)"
   1194         TEST_HOST = "\$(BUILT_PRODUCTS_DIR)/" +
   1195                     "${_xcode_app_name}.app/${_xcode_app_name}"
   1196       }
   1197     }
   1198 
   1199     deps = [ ":$_info_plist_bundle" ]
   1200   }
   1201 
   1202   bundle_data(_xctest_bundle) {
   1203     forward_variables_from(invoker, [ "host_target" ])
   1204 
   1205     testonly = true
   1206     visibility = [ ":$host_target" ]
   1207 
   1208     public_deps = [ ":$_target_name" ]
   1209     sources = [ "$root_out_dir/$_output_name.xctest" ]
   1210     outputs = [ "{{bundle_contents_dir}}/PlugIns/$_output_name.xctest" ]
   1211   }
   1212 }
   1213 
   1214 set_defaults("ios_xctest_bundle") {
   1215   configs = default_shared_library_configs
   1216 }
   1217 
   1218 # For Chrome on iOS we want to run XCTests for all our build configurations
   1219 # (Debug, Release, ...). In addition, the symbols visibility is configured to
   1220 # private by default. To simplify testing with those constraints, our tests are
   1221 # compiled in the TEST_HOST target instead of the .xctest bundle.
   1222 template("ios_xctest_test") {
   1223   _target_name = target_name
   1224   _output_name = target_name
   1225   if (defined(invoker.output_name)) {
   1226     _output_name = invoker.output_name
   1227   }
   1228 
   1229   _xctest_target = _target_name + "_module"
   1230   _xctest_output = _output_name + "_module"
   1231 
   1232   _host_target = _target_name
   1233   _host_output = _output_name
   1234 
   1235   # Allow invokers to specify their own target for the xctest module, but
   1236   # fall back to a default (empty) module otherwise.
   1237   if (defined(invoker.xctest_module_target)) {
   1238     _xctest_module_target = invoker.xctest_module_target
   1239   } else {
   1240     _xctest_module_target_name = _xctest_target + "shell_source"
   1241     _xctest_module_target = ":$_xctest_module_target_name"
   1242     source_set(_xctest_module_target_name) {
   1243       sources = [ "//chromium/build/config/ios/xctest_shell.mm" ]
   1244 
   1245       configs += [ "//chromium/build/config/ios:xctest_config" ]
   1246     }
   1247   }
   1248 
   1249   ios_xctest_bundle(_xctest_target) {
   1250     forward_variables_from(invoker, [ "data_deps" ])
   1251     output_name = _xctest_output
   1252     product_type = apple_mobile_xcode_xctest_bundle_id
   1253     host_target = _host_target
   1254 
   1255     # TODO(crbug.com/40120290) The change in output name results in a mismatch
   1256     # between this value and the ios_app_bundle target name. To mitigate, this
   1257     # has been modified to _host_target. output_name is set to _host_output
   1258     # to mitigate the naming.
   1259     xcode_test_application_name = _host_target
   1260     xcode_test_application_output_name = _host_output
   1261 
   1262     deps = [ _xctest_module_target ]
   1263   }
   1264 
   1265   ios_app_bundle(_host_target) {
   1266     forward_variables_from(invoker, "*", [ "testonly" ])
   1267 
   1268     testonly = true
   1269     output_name = _host_output
   1270     configs += [ "//chromium/build/config/ios:xctest_config" ]
   1271 
   1272     if (!defined(invoker.info_plist) && !defined(invoker.info_plist_target)) {
   1273       info_plist = "//chromium/build/config/ios/Host-Info.plist"
   1274     }
   1275 
   1276     # Xcode needs the following frameworks installed in the application (and
   1277     # signed) for the XCTest to run, so install them using
   1278     # extra_system_frameworks.
   1279     extra_system_frameworks = [
   1280       "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework",
   1281       "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
   1282       "$ios_sdk_platform_path/Developer/usr/lib/libXCTestBundleInject.dylib",
   1283     ]
   1284 
   1285     # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over
   1286     # everything that Xcode copies.
   1287     if (xcode_version_int >= 1300) {
   1288       extra_system_frameworks += [
   1289         "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework",
   1290         "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework",
   1291         "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib",
   1292       ]
   1293 
   1294       # Xcode 16.3 moved XCUIAutomation.framework
   1295       if (xcode_version_int < 1630) {
   1296         extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework" ]
   1297       } else {
   1298         extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/Frameworks/XCUIAutomation.framework" ]
   1299       }
   1300     }
   1301 
   1302     # XCTestSupport framework is required as of Xcode 14.3 or later.
   1303     if (xcode_version_int >= 1430) {
   1304       extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ]
   1305     }
   1306 
   1307     _xctest_bundle = _xctest_target + "_bundle"
   1308     if (!defined(bundle_deps)) {
   1309       bundle_deps = []
   1310     }
   1311     bundle_deps += [ ":$_xctest_bundle" ]
   1312   }
   1313 }
   1314 
   1315 set_defaults("ios_xctest_test") {
   1316   configs = default_executable_configs
   1317 }
   1318 
   1319 # Template to build a xcuitest test runner bundle.
   1320 #
   1321 # Xcode requires a test runner application with a copy of the XCTest dynamic
   1322 # library bundle in it for the XCUITest to run. The test runner bundle is created
   1323 # by copying the system bundle XCTRunner.app from Xcode SDK with the plist file
   1324 # being properly tweaked, and a xctest and it needs to be code signed in order
   1325 # to run on devices.
   1326 #
   1327 # Arguments
   1328 #
   1329 #   xctest_bundle
   1330 #       string, name of the dependent xctest bundle target.
   1331 #
   1332 #   output_name
   1333 #       (optional) string, name of the generated application, if omitted,
   1334 #       defaults to the target_name.
   1335 #
   1336 template("ios_xcuitest_test_runner_bundle") {
   1337   assert(defined(invoker.xctest_bundle),
   1338          "xctest_bundle must be defined for $target_name")
   1339 
   1340   _target_name = target_name
   1341   _output_name = target_name
   1342   if (defined(invoker.output_name)) {
   1343     _output_name = invoker.output_name
   1344   }
   1345 
   1346   # Bundle identifier should respect rfc1034, so replace "_" with "-".
   1347   _bundle_identifier = "$ios_app_bundle_id_prefix.chrome." +
   1348                        string_replace(_output_name, "_", "-")
   1349 
   1350   _xctrunner_path =
   1351       "$ios_sdk_platform_path/Developer/Library/Xcode/Agents/XCTRunner.app"
   1352 
   1353   _info_plist_merge_plist = _target_name + "_info_plist_merge_plist"
   1354   _info_plist_target = _target_name + "_info_plist"
   1355   _info_plist_bundle = _target_name + "_info_plist_bundle"
   1356 
   1357   action(_info_plist_merge_plist) {
   1358     testonly = true
   1359     script = "//chromium/build/apple/plist_util.py"
   1360 
   1361     sources = [
   1362       "$_xctrunner_path/Info.plist",
   1363 
   1364       # NOTE: The XCTRunnerAddition+Info.plist must come after the Info.plist
   1365       # because it overrides the values under "CFBundleIdentifier" and
   1366       # "CFBundleName".
   1367       "//chromium/build/config/ios/resources/XCTRunnerAddition+Info.plist",
   1368     ]
   1369 
   1370     _output_name = "$target_gen_dir/${_target_name}_merged.plist"
   1371     outputs = [ _output_name ]
   1372     args = [
   1373              "merge",
   1374              "-f=xml1",
   1375              "-x=$xcode_version",
   1376              "-o=" + rebase_path(_output_name, root_build_dir),
   1377            ] + rebase_path(sources, root_build_dir)
   1378 
   1379     if (ios_use_xcode_symlinks) {
   1380       deps = [ "//chromium/build/config/ios:copy_xctrunner_app" ]
   1381     }
   1382   }
   1383 
   1384   ios_info_plist(_info_plist_target) {
   1385     testonly = true
   1386     visibility = [ ":$_info_plist_bundle" ]
   1387 
   1388     executable_name = _output_name
   1389     info_plist_target = ":$_info_plist_merge_plist"
   1390     extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ]
   1391   }
   1392 
   1393   bundle_data(_info_plist_bundle) {
   1394     testonly = true
   1395     visibility = [ ":$_target_name" ]
   1396 
   1397     public_deps = [ ":$_info_plist_target" ]
   1398 
   1399     sources = get_target_outputs(":$_info_plist_target")
   1400     outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
   1401   }
   1402 
   1403   _pkginfo_bundle = _target_name + "_pkginfo_bundle"
   1404   bundle_data(_pkginfo_bundle) {
   1405     testonly = true
   1406     visibility = [ ":$_target_name" ]
   1407 
   1408     sources = [ "$_xctrunner_path/PkgInfo" ]
   1409 
   1410     outputs = [ "{{bundle_contents_dir}}/PkgInfo" ]
   1411 
   1412     if (ios_use_xcode_symlinks) {
   1413       public_deps = [ "//chromium/build/config/ios:copy_xctrunner_app" ]
   1414     }
   1415   }
   1416 
   1417   _xctest_bundle = invoker.xctest_bundle
   1418   ios_create_signed_bundle(_target_name) {
   1419     testonly = true
   1420 
   1421     bundle_binary_target = "//chromium/build/config/ios:xctest_runner_without_arm64e"
   1422     bundle_binary_output = "XCTRunner"
   1423     bundle_extension = ".app"
   1424     product_type = apple_mobile_xcode_app_bundle_id
   1425 
   1426     output_name = _output_name
   1427 
   1428     # Xcode needs the following frameworks installed in the application
   1429     # (and signed) for the XCUITest to run, so install them using
   1430     # extra_system_frameworks.
   1431     extra_system_frameworks = [
   1432       "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework",
   1433       "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
   1434     ]
   1435 
   1436     # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over
   1437     # everything that Xcode copies.
   1438     if (xcode_version_int >= 1300) {
   1439       extra_system_frameworks += [
   1440         "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework",
   1441         "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework",
   1442         "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib",
   1443       ]
   1444 
   1445       # Xcode 16.3 moved XCUIAutomation.framework
   1446       if (xcode_version_int < 1630) {
   1447         extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework" ]
   1448       } else {
   1449         extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/Frameworks/XCUIAutomation.framework" ]
   1450       }
   1451     }
   1452 
   1453     # XCTestSupport framework is required as of Xcode 14.3 or later.
   1454     if (xcode_version_int >= 1430) {
   1455       extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ]
   1456     }
   1457 
   1458     bundle_deps = []
   1459     if (defined(invoker.bundle_deps)) {
   1460       bundle_deps += invoker.bundle_deps
   1461     }
   1462     bundle_deps += [
   1463       ":$_info_plist_bundle",
   1464       ":$_pkginfo_bundle",
   1465       ":$_xctest_bundle",
   1466     ]
   1467   }
   1468 }
   1469 
   1470 # Template to build a XCUITest that consists of two parts: the test runner
   1471 # application bundle and the xctest dynamic library.
   1472 #
   1473 # Arguments
   1474 #
   1475 #   deps:
   1476 #       list of labels to depends on, these values are used to create the
   1477 #       xctest dynamic library.
   1478 #
   1479 #   xcode_test_application_name:
   1480 #       string, name of the test application for the ui test target.
   1481 #
   1482 #   runner_only_bundle_deps:
   1483 #       list of labels of bundle target to include in the runner and
   1484 #       exclude from the test module (the use case is a framework bundle
   1485 #       that is used by the test module and thus needs to be packaged in
   1486 #       the runner application bundle)
   1487 #
   1488 # This template defines two targets, one named "${target_name}_module" is the
   1489 # xctest dynamic library, and the other named "${target_name}_runner" is the
   1490 # test runner application bundle.
   1491 #
   1492 template("ios_xcuitest_test") {
   1493   assert(defined(invoker.deps), "deps must be defined for $target_name")
   1494   assert(defined(invoker.xcode_test_application_name),
   1495          "xcode_test_application_name must be defined for $target_name")
   1496 
   1497   _xcuitest_target = target_name
   1498   if (defined(invoker.output_name)) {
   1499     _xcuitest_target = invoker.output_name
   1500   }
   1501 
   1502   _xcuitest_runner_target = _xcuitest_target + "_runner"
   1503   _xcuitest_module_target = _xcuitest_target + "_module"
   1504 
   1505   group(target_name) {
   1506     testonly = true
   1507 
   1508     deps = [ ":$_xcuitest_runner_target" ]
   1509   }
   1510 
   1511   _xcuitest_module_output = _xcuitest_target
   1512   ios_xctest_bundle(_xcuitest_module_target) {
   1513     forward_variables_from(invoker,
   1514                            [
   1515                              "bundle_deps",
   1516                              "data_deps",
   1517                              "deps",
   1518                              "xcode_test_application_name",
   1519                              "xctest_bundle_principal_class",
   1520                            ])
   1521 
   1522     product_type = apple_mobile_xcode_xcuitest_bundle_id
   1523     host_target = _xcuitest_runner_target
   1524     output_name = _xcuitest_module_output
   1525 
   1526     if (defined(invoker.runner_only_bundle_deps)) {
   1527       bundle_deps_filter = invoker.runner_only_bundle_deps
   1528     }
   1529   }
   1530 
   1531   _xcuitest_runner_output = _xcuitest_target + "-Runner"
   1532   ios_xcuitest_test_runner_bundle(_xcuitest_runner_target) {
   1533     output_name = _xcuitest_runner_output
   1534     xctest_bundle = _xcuitest_module_target + "_bundle"
   1535 
   1536     if (defined(invoker.runner_only_bundle_deps)) {
   1537       if (!defined(bundle_deps)) {
   1538         bundle_deps = []
   1539       }
   1540       bundle_deps += invoker.runner_only_bundle_deps
   1541     }
   1542   }
   1543 }
   1544 
   1545 set_defaults("ios_xcuitest_test") {
   1546   configs = default_executable_configs
   1547 }