|  | # 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/config/ios/ios_sdk.gni") | 
|  | import("//build/config/mac/base_rules.gni") | 
|  | import("//build/config/mac/symbols.gni") | 
|  | import("//build/toolchain/toolchain.gni") | 
|  |  | 
|  | # 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") | 
|  |  | 
|  | _target_name = target_name | 
|  | _output_name = target_name | 
|  | if (defined(invoker.output_name)) { | 
|  | _output_name = invoker.output_name | 
|  | } | 
|  |  | 
|  | _all_target_cpu = [ current_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/mac/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 = [] | 
|  | if (!use_system_xcode) { | 
|  | args += [ | 
|  | "--developer_dir", | 
|  | hermetic_xcode_path, | 
|  | ] | 
|  | } | 
|  | 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 (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. | 
|  | # | 
|  | #   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. | 
|  | # | 
|  | #   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 == "com.apple.product-type.bundle.unit-test" || | 
|  | invoker.product_type == "com.apple.product-type.bundle.ui-testing", | 
|  | "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 | 
|  | } | 
|  |  | 
|  | _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 | 
|  | } | 
|  |  | 
|  | 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_extra_attributes", | 
|  | "xcode_test_application_name", | 
|  | ]) | 
|  |  | 
|  | bundle_root_dir = "$_bundle_gen_dir/$_output_name$_bundle_extension" | 
|  | bundle_contents_dir = bundle_root_dir | 
|  | bundle_resources_dir = bundle_contents_dir | 
|  | bundle_executable_dir = bundle_contents_dir | 
|  | bundle_plugins_dir = "$bundle_contents_dir/PlugIns" | 
|  |  | 
|  | if (!defined(public_deps)) { | 
|  | public_deps = [] | 
|  | } | 
|  |  | 
|  | 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_contents_dir/$_output_name" ] | 
|  | if (_enable_code_signing) { | 
|  | code_signing_outputs += | 
|  | [ "$bundle_contents_dir/_CodeSignature/CodeResources" ] | 
|  | } | 
|  | if (ios_code_signing_identity != "" && !use_ios_simulator && | 
|  | _enable_embedded_mobileprovision) { | 
|  | code_signing_outputs += | 
|  | [ "$bundle_contents_dir/embedded.mobileprovision" ] | 
|  | } | 
|  |  | 
|  | 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 = [] | 
|  | if (!use_system_xcode) { | 
|  | code_signing_args += [ | 
|  | "--developer_dir", | 
|  | hermetic_xcode_path, | 
|  | ] | 
|  | } | 
|  | 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. | 
|  | foreach(_framework, invoker.extra_system_frameworks) { | 
|  | code_signing_args += [ "-F=" + _framework ] | 
|  | } | 
|  | } | 
|  | if (defined(invoker.partial_info_plist)) { | 
|  | _partial_info_plists = [ | 
|  | invoker.primary_info_plist, | 
|  | invoker.partial_info_plist, | 
|  | ] | 
|  |  | 
|  | _plist_compiler_path = "//build/config/mac/plist_util.py" | 
|  |  | 
|  | code_signing_sources += _partial_info_plists | 
|  | code_signing_sources += [ _plist_compiler_path ] | 
|  | code_signing_outputs += [ "$bundle_contents_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] | 
|  | } | 
|  |  | 
|  | 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", | 
|  | ] | 
|  | 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. | 
|  | # | 
|  | #   bundle_extension: | 
|  | #       (optional) bundle extension including the dot, default to ".app". | 
|  | # | 
|  | #   product_type | 
|  | #       (optional) string, product type for the generated Xcode project, | 
|  | #       default to "com.apple.product-type.application". Should generally | 
|  | #       not be overridden. | 
|  | # | 
|  | #   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. | 
|  | # | 
|  | # 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 | 
|  | } | 
|  |  | 
|  | _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] | 
|  |  | 
|  | if (current_toolchain != default_toolchain) { | 
|  | # For use of _variants and _default_variant for secondary toolchain to | 
|  | # avoid the "Assignment had no effect" error from gn. | 
|  | assert(_variants != []) | 
|  | assert(_default_variant.target_name != "") | 
|  | } | 
|  |  | 
|  | 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", | 
|  | ]) | 
|  |  | 
|  | visibility = [ ":$_arch_executable_target" ] | 
|  | } | 
|  |  | 
|  | if (current_toolchain == default_toolchain || use_ios_simulator) { | 
|  | _generate_entitlements_target = _target_name + "_gen_entitlements" | 
|  | _generate_entitlements_output = | 
|  | get_label_info(":$_generate_entitlements_target($default_toolchain)", | 
|  | "target_out_dir") + "/$_output_name.xcent" | 
|  | } | 
|  |  | 
|  | 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", | 
|  | ]) | 
|  |  | 
|  | visibility = [ ":$_lipo_executable_target($default_toolchain)" ] | 
|  | if (current_toolchain != default_toolchain) { | 
|  | visibility += [ ":$_target_name" ] | 
|  | } | 
|  |  | 
|  | if (!defined(deps)) { | 
|  | deps = [] | 
|  | } | 
|  | deps += [ ":$_arch_executable_source" ] | 
|  |  | 
|  | if (!defined(libs)) { | 
|  | libs = [] | 
|  | } | 
|  | libs += [ "UIKit.framework" ] | 
|  |  | 
|  | if (!defined(ldflags)) { | 
|  | ldflags = [] | 
|  | } | 
|  | ldflags += [ | 
|  | "-Xlinker", | 
|  | "-rpath", | 
|  | "-Xlinker", | 
|  | "@executable_path/Frameworks", | 
|  | "-Xlinker", | 
|  | "-objc_abi_version", | 
|  | "-Xlinker", | 
|  | "2", | 
|  | ] | 
|  |  | 
|  | if (use_ios_simulator) { | 
|  | deps += [ ":$_generate_entitlements_target($default_toolchain)" ] | 
|  |  | 
|  | if (!defined(inputs)) { | 
|  | inputs = [] | 
|  | } | 
|  | inputs += [ _generate_entitlements_output ] | 
|  |  | 
|  | if (!defined(ldflags)) { | 
|  | ldflags = [] | 
|  | } | 
|  | ldflags += [ | 
|  | "-Xlinker", | 
|  | "-sectcreate", | 
|  | "-Xlinker", | 
|  | "__TEXT", | 
|  | "-Xlinker", | 
|  | "__entitlements", | 
|  | "-Xlinker", | 
|  | rebase_path(_generate_entitlements_output, root_build_dir), | 
|  | ] | 
|  | } | 
|  |  | 
|  | output_name = _output_name | 
|  | output_prefix_override = true | 
|  | output_dir = "$target_out_dir/$current_cpu" | 
|  | } | 
|  |  | 
|  | if (current_toolchain != default_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 (current_toolchain == default_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 = [] | 
|  | if (!use_system_xcode) { | 
|  | args += [ | 
|  | "--developer_dir", | 
|  | hermetic_xcode_path, | 
|  | ] | 
|  | } | 
|  | 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) | 
|  | } | 
|  | } | 
|  |  | 
|  | _app_product_type = "com.apple.product-type.application" | 
|  | _product_type = _app_product_type | 
|  | if (defined(invoker.product_type)) { | 
|  | _product_type = invoker.product_type | 
|  | } | 
|  |  | 
|  | _app_bundle_extension = ".app" | 
|  | _bundle_extension = _app_bundle_extension | 
|  | if (defined(invoker.bundle_extension)) { | 
|  | _bundle_extension = invoker.bundle_extension | 
|  | } | 
|  |  | 
|  | # Only write PkgInfo for real application, not application extension (they | 
|  | # have the same product type but a different extension). | 
|  | _write_pkg_info = _product_type == _app_product_type && | 
|  | _bundle_extension == _app_bundle_extension | 
|  |  | 
|  | if (_write_pkg_info) { | 
|  | _create_pkg_info = target_name + "_pkg_info" | 
|  | action(_create_pkg_info) { | 
|  | forward_variables_from(invoker, [ "testonly" ]) | 
|  | script = "//build/config/mac/write_pkg_info.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", | 
|  | ]) | 
|  |  | 
|  | 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 | 
|  |  | 
|  | _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 (_write_pkg_info) { | 
|  | bundle_deps += [ ":$_bundle_data_pkg_info" ] | 
|  | } | 
|  | bundle_deps += _variant.bundle_deps | 
|  |  | 
|  | if (use_ios_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_out_dir) + | 
|  | rebase_path(outputs, root_out_dir) | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | 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", | 
|  | ]) | 
|  | bundle_extension = ".appex" | 
|  | product_type = "com.apple.product-type.app-extension" | 
|  |  | 
|  | # Add linker flags required for an application extension (determined by | 
|  | # inspecting the link command-line when using Xcode 9.0+). | 
|  | if (!defined(ldflags)) { | 
|  | ldflags = [] | 
|  | } | 
|  | ldflags += [ | 
|  | "-e", | 
|  | "_NSExtensionMain", | 
|  | "-fapplication-extension", | 
|  | ] | 
|  | } | 
|  | } | 
|  |  | 
|  | set_defaults("ios_appex_bundle") { | 
|  | configs = default_executable_configs | 
|  | } | 
|  |  | 
|  | # 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 != [] | 
|  |  | 
|  | # 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($default_toolchain)", "root_out_dir") | 
|  | _default_toolchain_target_gen_dir = | 
|  | get_label_info("$_target_name($default_toolchain)", "target_gen_dir") | 
|  |  | 
|  | if (_has_public_headers) { | 
|  | _framework_headers_target = _target_name + "_framework_headers" | 
|  | _framework_headers_config = _target_name + "_framework_headers_config" | 
|  | config(_framework_headers_config) { | 
|  | # The link settings are inherited from the framework_bundle config. | 
|  | cflags = [ | 
|  | "-F", | 
|  | rebase_path("$_default_toolchain_root_out_dir/.", root_build_dir), | 
|  | ] | 
|  | } | 
|  |  | 
|  | _headers_map_config = _target_name + "_headers_map" | 
|  | _header_map_filename = | 
|  | "$_default_toolchain_target_gen_dir/$_output_name.headers.hmap" | 
|  | config(_headers_map_config) { | 
|  | visibility = [ ":$_target_name" ] | 
|  | include_dirs = [ _header_map_filename ] | 
|  | } | 
|  | } | 
|  |  | 
|  | _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" | 
|  |  | 
|  | _framework_public_config = _target_name + "_public_config" | 
|  | config(_framework_public_config) { | 
|  | # TODO(sdefresne): should we have a framework_dirs similar to lib_dirs | 
|  | # and include_dirs to avoid duplicate values on the command-line. | 
|  | visibility = [ ":$_target_name" ] | 
|  | ldflags = [ | 
|  | "-F", | 
|  | rebase_path("$_default_toolchain_root_out_dir/.", root_build_dir), | 
|  | ] | 
|  | lib_dirs = [ root_out_dir ] | 
|  | libs = [ "$_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", | 
|  | "visibility", | 
|  | ]) | 
|  |  | 
|  | visibility = [ ":$_arch_shared_library_target" ] | 
|  |  | 
|  | if (_has_public_headers) { | 
|  | configs += [ | 
|  | ":$_framework_headers_config", | 
|  | ":$_headers_map_config", | 
|  | ] | 
|  |  | 
|  | if (!defined(deps)) { | 
|  | deps = [] | 
|  | } | 
|  | deps += [ ":$_framework_headers_target($default_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", | 
|  | "visibility", | 
|  | ]) | 
|  |  | 
|  | visibility = [ ":$_lipo_shared_library_target($default_toolchain)" ] | 
|  | if (current_toolchain != default_toolchain) { | 
|  | visibility += [ ":$_target_name" ] | 
|  | } | 
|  |  | 
|  | if (!defined(deps)) { | 
|  | deps = [] | 
|  | } | 
|  | deps += [ ":$_arch_shared_library_source" ] | 
|  | if (_has_public_headers) { | 
|  | deps += [ ":$_framework_headers_target($default_toolchain)" ] | 
|  | } | 
|  | if (!defined(ldflags)) { | 
|  | ldflags = [] | 
|  | } | 
|  | ldflags += [ | 
|  | "-Xlinker", | 
|  | "-install_name", | 
|  | "-Xlinker", | 
|  | "@rpath/$_output_name.framework/$_output_name", | 
|  | "-Xlinker", | 
|  | "-objc_abi_version", | 
|  | "-Xlinker", | 
|  | "2", | 
|  | ] | 
|  |  | 
|  | output_extension = "" | 
|  | output_name = _output_name | 
|  | output_prefix_override = true | 
|  | output_dir = "$target_out_dir/$current_cpu" | 
|  | } | 
|  |  | 
|  | if (current_toolchain != default_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($default_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" ] | 
|  | } | 
|  |  | 
|  | if (defined(invoker.bundle_deps)) { | 
|  | assert(invoker.bundle_deps != [], "mark bundle_deps as used") | 
|  | } | 
|  | } else { | 
|  | if (_has_public_headers) { | 
|  | _public_headers = invoker.public_headers | 
|  | _framework_root = "$root_out_dir/$_output_name.framework" | 
|  |  | 
|  | _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". | 
|  | set_sources_assignment_filter([ | 
|  | "*.c", | 
|  | "*.cc", | 
|  | "*.cpp", | 
|  | "*.m", | 
|  | "*.mm", | 
|  | ]) | 
|  | sources = invoker.sources | 
|  | set_sources_assignment_filter([]) | 
|  |  | 
|  | args = [ | 
|  | rebase_path(_header_map_filename), | 
|  | rebase_path(_framework_root, 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_root/Modules/module.modulemap", | 
|  | ] | 
|  | args = [ rebase_path("$_framework_root", 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_root/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" ] | 
|  | 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" ] | 
|  | forward_variables_from(invoker, [ "testonly" ]) | 
|  | sources = get_target_outputs(":$_info_plist_target") | 
|  | outputs = [ | 
|  | "{{bundle_contents_dir}}/Info.plist", | 
|  | ] | 
|  | public_deps = [ | 
|  | ":$_info_plist_target", | 
|  | ] | 
|  | } | 
|  |  | 
|  | create_signed_bundle(_target_name) { | 
|  | 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 | 
|  |  | 
|  | # 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(_link_target_name) { | 
|  | forward_variables_from(invoker, | 
|  | [ | 
|  | "public_configs", | 
|  | "public_deps", | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  | if (!defined(public_deps)) { | 
|  | public_deps = [] | 
|  | } | 
|  | public_deps += [ ":$_target_name" ] | 
|  |  | 
|  | 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" ] | 
|  | } | 
|  |  | 
|  | bundle_data(_target_name + "+bundle") { | 
|  | forward_variables_from(invoker, | 
|  | [ | 
|  | "testonly", | 
|  | "visibility", | 
|  | ]) | 
|  | public_deps = [ | 
|  | ":$_target_name", | 
|  | ] | 
|  | sources = [ | 
|  | "$root_out_dir/$_output_name.framework", | 
|  | ] | 
|  | outputs = [ | 
|  | "{{bundle_resources_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 == "com.apple.product-type.bundle.unit-test" || | 
|  | invoker.product_type == "com.apple.product-type.bundle.ui-testing", | 
|  | "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. | 
|  | assert(invoker.configs != []) | 
|  | assert(invoker.host_target != target_name) | 
|  | assert(invoker.xcode_test_application_name != target_name) | 
|  |  | 
|  | _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" | 
|  |  | 
|  | 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($default_toolchain)" ] | 
|  | if (current_toolchain != default_toolchain) { | 
|  | visibility += [ ":$_target_name" ] | 
|  | } | 
|  |  | 
|  | deps = [ | 
|  | ":$_arch_loadable_module_source", | 
|  | ] | 
|  | configs += [ "//build/config/ios:xctest_config" ] | 
|  |  | 
|  | output_dir = "$target_out_dir/$current_cpu" | 
|  | output_name = _output_name | 
|  | output_prefix_override = true | 
|  | output_extension = "" | 
|  | } | 
|  |  | 
|  | if (current_toolchain != default_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", | 
|  | ] | 
|  | } | 
|  | } 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 (ios_automatically_manage_certs) { | 
|  | # Use a fixed bundle identifier for EarlGrey tests when using Xcode to | 
|  | # manage the certificates as the number of free certs is limited. | 
|  | extra_substitutions = [ | 
|  | "MODULE_BUNDLE_ID=gtest.${ios_generic_test_bundle_id_suffix}-module", | 
|  | ] | 
|  | } else { | 
|  | extra_substitutions = [ "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, | 
|  | [ | 
|  | "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 | 
|  |  | 
|  | # Test files need to be known to Xcode for proper indexing and discovery | 
|  | # of tests function for XCTest, but the compilation is done via ninja and | 
|  | # thus must prevent Xcode from linking object files via this hack. | 
|  | xcode_extra_attributes = { | 
|  | OTHER_LDFLAGS = "-help" | 
|  | ONLY_ACTIVE_ARCH = "YES" | 
|  | DEBUG_INFORMATION_FORMAT = "dwarf" | 
|  |  | 
|  | # For XCUITest, Xcode requires specifying the host application name via | 
|  | # the TEST_TARGET_NAME attribute. | 
|  | if (invoker.product_type == "com.apple.product-type.bundle.ui-testing") { | 
|  | TEST_TARGET_NAME = invoker.xcode_test_application_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_plugins_dir}}/$_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 | 
|  |  | 
|  | _xctest_shell_source_target = _xctest_target + "shell_source" | 
|  | source_set(_xctest_shell_source_target) { | 
|  | sources = [ | 
|  | "//build/config/ios/xctest_shell.mm", | 
|  | ] | 
|  |  | 
|  | configs += [ "//build/config/ios:xctest_config" ] | 
|  | } | 
|  |  | 
|  | ios_xctest_bundle(_xctest_target) { | 
|  | output_name = _xctest_output | 
|  | product_type = "com.apple.product-type.bundle.unit-test" | 
|  | host_target = _host_target | 
|  | xcode_test_application_name = _host_output | 
|  |  | 
|  | deps = [ | 
|  | ":$_xctest_shell_source_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" | 
|  | if (ios_automatically_manage_certs) { | 
|  | # Use the same bundle identifier for EarlGrey tests as for unit tests | 
|  | # when managing certificates as the number of free certs is limited. | 
|  | if (!defined(extra_substitutions)) { | 
|  | extra_substitutions = [] | 
|  | } | 
|  | extra_substitutions += | 
|  | [ "EXECUTABLE_NAME=gtest.${ios_generic_test_bundle_id_suffix}" ] | 
|  | } | 
|  | } | 
|  |  | 
|  | # Xcode needs those two framework installed in the application (and signed) | 
|  | # for the XCTest to run, so install them using extra_system_frameworks. | 
|  | _ios_platform_library = "$ios_sdk_platform_path/Developer/Library" | 
|  | extra_system_frameworks = [ | 
|  | "$_ios_platform_library/Frameworks/XCTest.framework", | 
|  | "$_ios_platform_library/PrivateFrameworks/IDEBundleInjection.framework", | 
|  | ] | 
|  |  | 
|  | _xctest_bundle = _xctest_target + "_bundle" | 
|  | if (current_toolchain == default_toolchain) { | 
|  | if (!defined(bundle_deps)) { | 
|  | bundle_deps = [] | 
|  | } | 
|  | bundle_deps += [ ":$_xctest_bundle" ] | 
|  | } | 
|  |  | 
|  | if (!defined(ldflags)) { | 
|  | ldflags = [] | 
|  | } | 
|  | ldflags += [ | 
|  | "-Xlinker", | 
|  | "-rpath", | 
|  | "-Xlinker", | 
|  | "@executable_path/Frameworks", | 
|  | "-Xlinker", | 
|  | "-rpath", | 
|  | "-Xlinker", | 
|  | "@loader_path/Frameworks", | 
|  | ] | 
|  | } | 
|  | } | 
|  |  | 
|  | 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/config/mac/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". | 
|  | "//ios/chrome/app/resources/XCTRunnerAddition+Info.plist", | 
|  | ] | 
|  |  | 
|  | _output_name = "$target_gen_dir/${_target_name}_merged.plist" | 
|  | outputs = [ | 
|  | _output_name, | 
|  | ] | 
|  | args = [ | 
|  | "merge", | 
|  | "-f=xml1", | 
|  | "-o=" + rebase_path(_output_name, root_build_dir), | 
|  | ] + rebase_path(sources, root_build_dir) | 
|  | } | 
|  |  | 
|  | ios_info_plist(_info_plist_target) { | 
|  | testonly = true | 
|  | visibility = [ ":$_info_plist_bundle" ] | 
|  |  | 
|  | executable_name = _output_name | 
|  | info_plist_target = ":$_info_plist_merge_plist" | 
|  |  | 
|  | if (ios_automatically_manage_certs) { | 
|  | # Use the same bundle identifier for XCUITest tests as for unit tests | 
|  | # when managing certificates as the number of free certs is limited. | 
|  | extra_substitutions = | 
|  | [ "EXECUTABLE_NAME=gtest.${ios_generic_test_bundle_id_suffix}" ] | 
|  | } | 
|  | } | 
|  |  | 
|  | 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", | 
|  | ] | 
|  | } | 
|  |  | 
|  | _xctest_bundle = invoker.xctest_bundle | 
|  | create_signed_bundle(_target_name) { | 
|  | testonly = true | 
|  |  | 
|  | bundle_binary_path = "$_xctrunner_path/XCTRunner" | 
|  | bundle_extension = ".app" | 
|  | product_type = "com.apple.product-type.application" | 
|  |  | 
|  | 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", | 
|  | ] | 
|  |  | 
|  | 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 | 
|  | _xcuitest_runner_target = _xcuitest_target + "_runner" | 
|  | _xcuitest_module_target = _xcuitest_target + "_module" | 
|  |  | 
|  | group(_xcuitest_target) { | 
|  | 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" ]) | 
|  |  | 
|  | product_type = "com.apple.product-type.bundle.ui-testing" | 
|  | 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" | 
|  | } | 
|  | } | 
|  |  | 
|  | set_defaults("ios_xcuitest_test") { | 
|  | configs = default_executable_configs | 
|  | } |