• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5import("//build/apple/apple_info_plist.gni")
6import("//build/config/apple/symbols.gni")
7import("//build/config/compiler/compiler.gni")
8import("//build/config/ios/ios_sdk.gni")
9import("//build/config/zip.gni")
10import("//build/toolchain/rbe.gni")
11import("//build/toolchain/siso.gni")
12import("//build/toolchain/toolchain.gni")
13import("//build_overrides/build.gni")
14
15# Constants corresponding to the bundle type identifiers use application,
16# application extension, XCTest and XCUITest targets respectively.
17_ios_xcode_app_bundle_id = "com.apple.product-type.application"
18_ios_xcode_appex_bundle_id = "com.apple.product-type.app-extension"
19_ios_xcode_xctest_bundle_id = "com.apple.product-type.bundle.unit-test"
20_ios_xcode_xcuitest_bundle_id = "com.apple.product-type.bundle.ui-testing"
21
22# Wrapper around create_bundle taking care of code signature settings.
23#
24# Arguments
25#
26#   product_type
27#       string, product type for the generated Xcode project.
28#
29#   bundle_gen_dir
30#       (optional) directory where the bundle is generated; must be below
31#       root_out_dir and defaults to root_out_dir if omitted.
32#
33#   bundle_deps
34#       (optional) list of additional dependencies.
35#
36#   bundle_deps_filter
37#       (optional) list of dependencies to filter (for more information
38#       see "gn help bundle_deps_filter").
39#
40#   bundle_extension
41#       string, extension of the bundle, used to generate bundle name.
42#
43#   bundle_binary_target
44#       (optional) string, label of the target generating the bundle main
45#       binary. This target and bundle_binary_path are mutually exclusive.
46#
47#   bundle_binary_output
48#       (optional) string, base name of the binary generated by the
49#       bundle_binary_target target, defaults to the target name.
50#
51#   bundle_binary_path
52#       (optional) string, path to the bundle main binary. This target and
53#       bundle_binary_target are mutually exclusive.
54#
55#   output_name:
56#       (optional) string, name of the generated application, if omitted,
57#       defaults to the target_name.
58#
59#   extra_system_frameworks
60#       (optional) list of system framework to copy to the bundle.
61#
62#   enable_code_signing
63#       (optional) boolean, control whether code signing is enabled or not,
64#       default to ios_enable_code_signing if not defined.
65#
66#   entitlements_path:
67#       (optional) path to the template to use to generate the application
68#       entitlements by performing variable substitutions, defaults to
69#       //build/config/ios/entitlements.plist.
70#
71#   entitlements_target:
72#       (optional) label of the target generating the application
73#       entitlements (must generate a single file as output); cannot be
74#       defined if entitlements_path is set.
75#
76#   has_public_headers:
77#       (optional) boolean, defaults to false; only meaningful if the bundle
78#       is a framework bundle; if true, then the frameworks includes public
79#       headers
80#
81#   disable_entitlements
82#       (optional, defaults to false) boolean, control whether entitlements willi
83#       be embedded in the application during signature. If false and no
84#       entitlements are provided, default empty entitlements will be used.
85#
86#   disable_embedded_mobileprovision
87#       (optional, default to false) boolean, control whether mobile provisions
88#       will be embedded in the bundle. If true, the existing
89#       embedded.mobileprovision will be deleted.
90#
91#   xcode_extra_attributes
92#       (optional) scope, extra attributes for Xcode projects.
93#
94#   xcode_test_application_name:
95#       (optional) string, name of the test application for Xcode unit or ui
96#       test target.
97#
98#   xcode_product_bundle_id:
99#       (optional) string, the bundle ID that will be added in the XCode
100#       attributes to enable some features when debugging (e.g. MetricKit).
101#
102#   primary_info_plist:
103#       (optional) path to Info.plist to merge with the $partial_info_plist
104#       generated by the compilation of the asset catalog.
105#
106#   partial_info_plist:
107#       (optional) path to the partial Info.plist generated by the asset
108#       catalog compiler; if defined $primary_info_plist must also be defined.
109#
110#   transparent
111#       (optional) boolean, whether the bundle is "transparent"; defaults to
112#       "false" if omitted; a bundle is considered "transparent" if it does
113#       not package the "bundle_data" deps but forward them to all targets
114#       the depend on it (unless the "bundle_data" target sets "product_type"
115#       to the same value as the "create_signed_bundle" target).
116#
117template("create_signed_bundle") {
118  assert(defined(invoker.product_type),
119         "product_type must be defined for $target_name")
120  assert(defined(invoker.bundle_extension),
121         "bundle_extension must be defined for $target_name")
122  assert(defined(invoker.bundle_binary_target) !=
123             defined(invoker.bundle_binary_path),
124         "Only one of bundle_binary_target or bundle_binary_path may be " +
125             "specified for $target_name")
126  assert(!defined(invoker.partial_info_plist) ||
127             defined(invoker.primary_info_plist),
128         "primary_info_plist must be defined when partial_info_plist is " +
129             "defined for $target_name")
130
131  if (defined(invoker.xcode_test_application_name)) {
132    assert(
133        invoker.product_type == _ios_xcode_xctest_bundle_id ||
134            invoker.product_type == _ios_xcode_xcuitest_bundle_id,
135        "xcode_test_application_name can be only defined for Xcode unit or ui test target.")
136  }
137
138  _target_name = target_name
139  _output_name = target_name
140  if (defined(invoker.output_name)) {
141    _output_name = invoker.output_name
142  }
143
144  if (defined(invoker.bundle_binary_path)) {
145    _bundle_binary_path = invoker.bundle_binary_path
146  } else {
147    _bundle_binary_target = invoker.bundle_binary_target
148    _bundle_binary_output = get_label_info(_bundle_binary_target, "name")
149    if (defined(invoker.bundle_binary_output)) {
150      _bundle_binary_output = invoker.bundle_binary_output
151    }
152    _bundle_binary_path =
153        get_label_info(_bundle_binary_target, "target_out_dir") +
154        "/$_bundle_binary_output"
155  }
156
157  _bundle_gen_dir = root_out_dir
158  if (defined(invoker.bundle_gen_dir)) {
159    _bundle_gen_dir = invoker.bundle_gen_dir
160  }
161
162  _bundle_extension = invoker.bundle_extension
163
164  _enable_embedded_mobileprovision = true
165  if (defined(invoker.disable_embedded_mobileprovision)) {
166    _enable_embedded_mobileprovision = !invoker.disable_embedded_mobileprovision
167  }
168
169  if (target_environment == "catalyst") {
170    _enable_embedded_mobileprovision = false
171  }
172
173  _enable_entitlements = true
174  if (defined(invoker.disable_entitlements)) {
175    _enable_entitlements = !invoker.disable_entitlements
176  }
177
178  if (_enable_entitlements) {
179    if (!defined(invoker.entitlements_target)) {
180      _entitlements_path = "//build/config/ios/entitlements.plist"
181      if (defined(invoker.entitlements_path)) {
182        _entitlements_path = invoker.entitlements_path
183      }
184    } else {
185      assert(!defined(invoker.entitlements_path),
186             "Cannot define both entitlements_path and entitlements_target " +
187                 "for $target_name")
188
189      _entitlements_target_outputs =
190          get_target_outputs(invoker.entitlements_target)
191      _entitlements_path = _entitlements_target_outputs[0]
192    }
193  }
194
195  _enable_code_signing = ios_enable_code_signing
196  if (defined(invoker.enable_code_signing)) {
197    _enable_code_signing = invoker.enable_code_signing
198  }
199
200  create_bundle(_target_name) {
201    forward_variables_from(invoker,
202                           [
203                             "bundle_deps_filter",
204                             "data_deps",
205                             "deps",
206                             "partial_info_plist",
207                             "product_type",
208                             "public_configs",
209                             "public_deps",
210                             "testonly",
211                             "transparent",
212                             "visibility",
213                             "xcode_test_application_name",
214                           ])
215
216    bundle_root_dir = "$_bundle_gen_dir/$_output_name$_bundle_extension"
217    if (target_environment == "simulator" || target_environment == "device") {
218      bundle_contents_dir = bundle_root_dir
219      bundle_resources_dir = bundle_contents_dir
220      bundle_executable_dir = bundle_contents_dir
221    } else if (target_environment == "catalyst") {
222      if (_bundle_extension != ".framework") {
223        bundle_contents_dir = "$bundle_root_dir/Contents"
224        bundle_resources_dir = "$bundle_contents_dir/Resources"
225        bundle_executable_dir = "$bundle_contents_dir/MacOS"
226      } else {
227        bundle_contents_dir = "$bundle_root_dir/Versions/A"
228        bundle_resources_dir = "$bundle_contents_dir/Resources"
229        bundle_executable_dir = bundle_contents_dir
230      }
231    }
232
233    if (!defined(public_deps)) {
234      public_deps = []
235    }
236
237    _bundle_identifier = ""
238    if (defined(invoker.xcode_product_bundle_id)) {
239      _bundle_identifier = invoker.xcode_product_bundle_id
240      assert(_bundle_identifier == string_replace(_bundle_identifier, "_", "-"),
241             "$target_name: bundle_identifier does not respect rfc1034: " +
242                 _bundle_identifier)
243    }
244
245    xcode_extra_attributes = {
246      IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target
247      PRODUCT_BUNDLE_IDENTIFIER = _bundle_identifier
248      CODE_SIGNING_REQUIRED = "NO"
249      CODE_SIGNING_ALLOWED = "NO"
250      CODE_SIGN_IDENTITY = ""
251      DONT_GENERATE_INFOPLIST_FILE = "YES"
252
253      # If invoker has defined extra attributes, they override the defaults.
254      if (defined(invoker.xcode_extra_attributes)) {
255        forward_variables_from(invoker.xcode_extra_attributes, "*")
256      }
257    }
258
259    if (defined(invoker.bundle_binary_target)) {
260      public_deps += [ invoker.bundle_binary_target ]
261    }
262
263    if (defined(invoker.bundle_deps)) {
264      if (!defined(deps)) {
265        deps = []
266      }
267      deps += invoker.bundle_deps
268    }
269    if (!defined(deps)) {
270      deps = []
271    }
272
273    post_processing_script = "//build/config/ios/codesign.py"
274    post_processing_sources = [ _bundle_binary_path ]
275    if (_enable_entitlements) {
276      if (defined(invoker.entitlements_target)) {
277        deps += [ invoker.entitlements_target ]
278      }
279      post_processing_sources += [ _entitlements_path ]
280    }
281    post_processing_outputs = [ "$bundle_executable_dir/$_output_name" ]
282    if (_enable_code_signing) {
283      post_processing_outputs +=
284          [ "$bundle_contents_dir/_CodeSignature/CodeResources" ]
285    }
286    if (ios_code_signing_identity != "" && target_environment == "device" &&
287        _enable_embedded_mobileprovision) {
288      post_processing_outputs +=
289          [ "$bundle_contents_dir/embedded.mobileprovision" ]
290    }
291    if (_bundle_extension == ".framework") {
292      if (target_environment == "catalyst") {
293        post_processing_outputs += [
294          "$bundle_root_dir/Versions/Current",
295          "$bundle_root_dir/$_output_name",
296        ]
297
298        if (defined(invoker.has_public_headers) && invoker.has_public_headers) {
299          post_processing_outputs += [
300            "$bundle_root_dir/Headers",
301            "$bundle_root_dir/Modules",
302          ]
303        }
304      } else {
305        not_needed(invoker, [ "has_public_headers" ])
306      }
307    }
308
309    if (defined(invoker.extra_system_frameworks)) {
310      foreach(_framework, invoker.extra_system_frameworks) {
311        post_processing_outputs += [ "$bundle_contents_dir/Frameworks/" +
312                                     get_path_info(_framework, "file") ]
313      }
314    }
315
316    post_processing_args = [
317      "code-sign-bundle",
318      "-t=" + ios_sdk_name,
319      "-i=" + ios_code_signing_identity,
320      "-b=" + rebase_path(_bundle_binary_path, root_build_dir),
321    ]
322    foreach(mobileprovision, ios_mobileprovision_files) {
323      post_processing_args +=
324          [ "-m=" + rebase_path(mobileprovision, root_build_dir) ]
325    }
326    post_processing_sources += ios_mobileprovision_files
327    if (_enable_entitlements) {
328      post_processing_args +=
329          [ "-e=" + rebase_path(_entitlements_path, root_build_dir) ]
330    }
331    if (!_enable_embedded_mobileprovision) {
332      post_processing_args += [ "--disable-embedded-mobileprovision" ]
333    }
334    post_processing_args += [ rebase_path(bundle_root_dir, root_build_dir) ]
335    if (!_enable_code_signing) {
336      post_processing_args += [ "--disable-code-signature" ]
337    }
338    if (defined(invoker.extra_system_frameworks)) {
339      # All framework in extra_system_frameworks are expected to be system
340      # framework and the path to be already system absolute so do not use
341      # rebase_path here unless using RBE and system Xcode (as in that
342      # case the system framework are found via a symlink in root_build_dir).
343      foreach(_framework, invoker.extra_system_frameworks) {
344        if (use_system_xcode && use_remoteexec) {
345          _framework_path = rebase_path(_framework, root_build_dir)
346        } else {
347          _framework_path = _framework
348        }
349        post_processing_args += [ "-F=$_framework_path" ]
350      }
351    }
352    if (defined(invoker.partial_info_plist)) {
353      _partial_info_plists = [
354        invoker.primary_info_plist,
355        invoker.partial_info_plist,
356      ]
357
358      _plist_compiler_path = "//build/apple/plist_util.py"
359
360      post_processing_sources += _partial_info_plists
361      post_processing_sources += [ _plist_compiler_path ]
362      if (target_environment != "catalyst" ||
363          _bundle_extension != ".framework") {
364        post_processing_outputs += [ "$bundle_contents_dir/Info.plist" ]
365      } else {
366        post_processing_outputs += [ "$bundle_resources_dir/Info.plist" ]
367      }
368
369      post_processing_args +=
370          [ "-P=" + rebase_path(_plist_compiler_path, root_build_dir) ]
371      foreach(_partial_info_plist, _partial_info_plists) {
372        post_processing_args +=
373            [ "-p=" + rebase_path(_partial_info_plist, root_build_dir) ]
374      }
375    }
376  }
377}
378
379# Generates Info.plist files for iOS apps and frameworks.
380#
381# Arguments
382#
383#     info_plist:
384#         (optional) string, path to the Info.plist file that will be used for
385#         the bundle.
386#
387#     info_plist_target:
388#         (optional) string, if the info_plist is generated from an action,
389#         rather than a regular source file, specify the target name in lieu
390#         of info_plist. The two arguments are mutually exclusive.
391#
392#     executable_name:
393#         string, name of the generated target used for the product
394#         and executable name as specified in the output Info.plist.
395#
396#     extra_substitutions:
397#         (optional) string array, 'key=value' pairs for extra fields which are
398#         specified in a source Info.plist template.
399template("ios_info_plist") {
400  assert(defined(invoker.info_plist) != defined(invoker.info_plist_target),
401         "Only one of info_plist or info_plist_target may be specified in " +
402             target_name)
403
404  if (defined(invoker.info_plist)) {
405    _info_plist = invoker.info_plist
406  } else {
407    _info_plist_target_output = get_target_outputs(invoker.info_plist_target)
408    _info_plist = _info_plist_target_output[0]
409  }
410
411  apple_info_plist(target_name) {
412    format = "binary1"
413    extra_substitutions = [
414      "IOS_BUNDLE_ID_PREFIX=$ios_app_bundle_id_prefix",
415      "IOS_PLATFORM_BUILD=$ios_platform_build",
416      "IOS_PLATFORM_NAME=$ios_sdk_name",
417      "IOS_PLATFORM_VERSION=$ios_sdk_version",
418      "IOS_SDK_BUILD=$ios_sdk_build",
419      "IOS_SDK_NAME=$ios_sdk_name$ios_sdk_version",
420      "IOS_SUPPORTED_PLATFORM=$ios_sdk_platform",
421      "BUILD_MACHINE_OS_BUILD=$machine_os_build",
422      "IOS_DEPLOYMENT_TARGET=$ios_deployment_target",
423      "XCODE_BUILD=$xcode_build",
424      "XCODE_VERSION=$xcode_version",
425    ]
426    if (defined(invoker.extra_substitutions)) {
427      extra_substitutions += invoker.extra_substitutions
428    }
429    plist_templates = [
430      "//build/config/ios/BuildInfo.plist",
431      _info_plist,
432    ]
433    if (defined(invoker.info_plist_target)) {
434      deps = [ invoker.info_plist_target ]
435    }
436    forward_variables_from(invoker,
437                           [
438                             "executable_name",
439                             "output_name",
440                             "visibility",
441                             "testonly",
442                           ])
443  }
444}
445
446# Template to build an application bundle for iOS.
447#
448# This should be used instead of "executable" built-in target type on iOS.
449# As the template forward the generation of the application executable to
450# an "executable" target, all arguments supported by "executable" targets
451# are also supported by this template.
452#
453# Arguments
454#
455#   output_name:
456#       (optional) string, name of the generated application, if omitted,
457#       defaults to the target_name.
458#
459#   extra_substitutions:
460#       (optional) list of string in "key=value" format, each value will
461#       be used as an additional variable substitution rule when generating
462#       the application Info.plist
463#
464#   info_plist:
465#       (optional) string, path to the Info.plist file that will be used for
466#       the bundle.
467#
468#   info_plist_target:
469#       (optional) string, if the info_plist is generated from an action,
470#       rather than a regular source file, specify the target name in lieu
471#       of info_plist. The two arguments are mutually exclusive.
472#
473#   entitlements_path:
474#       (optional) path to the template to use to generate the application
475#       entitlements by performing variable substitutions, defaults to
476#       //build/config/ios/entitlements.plist.
477#
478#   entitlements_target:
479#       (optional) label of the target generating the application
480#       entitlements (must generate a single file as output); cannot be
481#       defined if entitlements_path is set.
482#
483#   product_type
484#       (optional) string, product type for the generated Xcode project,
485#       default to "com.apple.product-type.application". Should only be
486#       overriden when building application extension.
487#
488#   enable_code_signing
489#       (optional) boolean, control whether code signing is enabled or not,
490#       default to ios_enable_code_signing if not defined.
491#
492#   variants
493#       (optional) list of scopes, each scope needs to define the attributes
494#       "name" and "bundle_deps"; if defined and non-empty, then one bundle
495#       named $target_out_dir/$variant/$output_name will be created for each
496#       variant with the same binary but the correct bundle_deps, the bundle
497#       at $target_out_dir/$output_name will be a copy of the first variant.
498#
499#   bundle_identifier:
500#       (optional) string, value of CFBundleIdentifier in the application
501#       Info.plist, defaults to "$ios_app_bundle_id_prefix.$output_name"
502#       if omitted. Will be used to set BUNDLE_IDENTIFIER when generating
503#       the application Info.plist
504#
505#   orderfile_path:
506#       (optional) string, path to an orderfile passed to the linker in order
507#       to improve application launch performance.
508#
509#   intents_target:
510#       (optional) string, label of the target defining the intents for the
511#       application. If defined, it must corresponds to a `swift_source_set`
512#       target configured with `generate_intents = true`.
513#
514#   transparent
515#       (optional) boolean, whether the bundle is "transparent"; defaults to
516#       "false" if omitted; a bundle is considered "transparent" if it does
517#       not package the "bundle_data" deps but forward them to all targets
518#       the depend on it (unless the "bundle_data" target sets "product_type"
519#       to the same value as the "create_signed_bundle" target).
520#
521# For more information, see "gn help executable".
522template("ios_app_bundle") {
523  _output_name = target_name
524  _target_name = target_name
525  if (defined(invoker.output_name)) {
526    _output_name = invoker.output_name
527  }
528
529  assert(
530      !defined(invoker.bundle_extension),
531      "bundle_extension must not be set for ios_app_bundle template for $target_name")
532
533  # Whether the intents metadata should be extracted (note that they are
534  # disabled when building for the catalyst environment)
535  _extract_intents_metadata = false
536  if (defined(invoker.intents_target)) {
537    _extract_intents_metadata =
538        invoker.intents_target != "" && target_environment != "catalyst"
539  }
540
541  if (defined(invoker.bundle_identifier)) {
542    _bundle_identifier = invoker.bundle_identifier
543    assert(_bundle_identifier == string_replace(_bundle_identifier, "_", "-"),
544           "$target_name: bundle_identifier does not respect rfc1034: " +
545               _bundle_identifier)
546  } else {
547    # Bundle identifier should respect rfc1034, so replace "_" with "-".
548    _bundle_identifier =
549        "$ios_app_bundle_id_prefix." + string_replace(_output_name, "_", "-")
550  }
551
552  if (defined(invoker.variants) && invoker.variants != []) {
553    _variants = []
554
555    foreach(_variant, invoker.variants) {
556      assert(defined(_variant.name) && _variant.name != "",
557             "name must be defined for all $target_name variants")
558
559      assert(defined(_variant.bundle_deps),
560             "bundle_deps must be defined for all $target_name variants")
561
562      _variants += [
563        {
564          name = _variant.name
565          bundle_deps = _variant.bundle_deps
566          target_name = "${_target_name}_variants_${_variant.name}"
567          bundle_gen_dir = "$root_out_dir/variants/${_variant.name}"
568        },
569      ]
570    }
571  } else {
572    # If no variants are passed to the template, use a fake variant with
573    # no name to avoid duplicating code. As no variant can have an empty
574    # name except this fake variant, it is possible to know if a variant
575    # is fake or not.
576    _variants = [
577      {
578        name = ""
579        bundle_deps = []
580        target_name = _target_name
581        bundle_gen_dir = root_out_dir
582      },
583    ]
584  }
585
586  _default_variant = _variants[0]
587
588  _executable_target = _target_name + "_executable"
589  _generate_entitlements_target = _target_name + "_gen_entitlements"
590  _generate_entitlements_output =
591      get_label_info(":$_generate_entitlements_target", "target_out_dir") +
592      "/$_output_name.xcent"
593
594  _product_type = _ios_xcode_app_bundle_id
595  if (defined(invoker.product_type)) {
596    _product_type = invoker.product_type
597  }
598
599  if (_product_type == _ios_xcode_app_bundle_id) {
600    _bundle_extension = ".app"
601  } else if (_product_type == _ios_xcode_appex_bundle_id) {
602    _bundle_extension = ".appex"
603  } else {
604    assert(false, "unknown product_type \"$product_type\" for $_target_name")
605  }
606
607  _is_app_bundle = _product_type == _ios_xcode_app_bundle_id
608
609  if (_extract_intents_metadata) {
610    _metadata_extraction = _target_name + "_metadata_extraction"
611    _metadata_bundledata = _target_name + "_metadata_bundledata"
612  }
613
614  executable(_executable_target) {
615    forward_variables_from(invoker,
616                           "*",
617                           [
618                             "bundle_deps",
619                             "bundle_deps_filter",
620                             "bundle_extension",
621                             "enable_code_signing",
622                             "entitlements_path",
623                             "entitlements_target",
624                             "extra_substitutions",
625                             "extra_system_frameworks",
626                             "info_plist",
627                             "info_plist_target",
628                             "output_name",
629                             "product_type",
630                             "transparent",
631                             "visibility",
632                             "xcode_extra_attributes",
633                           ])
634
635    if (!defined(deps)) {
636      deps = []
637    }
638
639    visibility = []
640    foreach(_variant, _variants) {
641      visibility += [ ":${_variant.target_name}" ]
642    }
643    if (_extract_intents_metadata) {
644      visibility += [ ":$_metadata_extraction" ]
645      deps += [ invoker.intents_target ]
646    }
647
648    if (defined(invoker.orderfile_path)) {
649      orderfile_path = invoker.orderfile_path
650      if (!defined(ldflags)) {
651        ldflags = []
652      }
653      ldflags += [
654        "-Wl,-order_file",
655        "-Wl," + rebase_path(orderfile_path, root_build_dir),
656      ]
657
658      if (!defined(inputs)) {
659        inputs = []
660      }
661      inputs += [ orderfile_path ]
662    }
663
664    if (target_environment == "simulator") {
665      deps += [ ":$_generate_entitlements_target" ]
666
667      if (!defined(inputs)) {
668        inputs = []
669      }
670      inputs += [ _generate_entitlements_output ]
671
672      if (!defined(ldflags)) {
673        ldflags = []
674      }
675      ldflags += [ "-Wl,-sectcreate,__TEXT,__entitlements," +
676                   rebase_path(_generate_entitlements_output, root_build_dir) ]
677    }
678
679    output_name = _output_name
680    output_prefix_override = true
681    output_dir = target_out_dir
682  }
683
684  if (_extract_intents_metadata) {
685    _module_info_path =
686        get_label_info(invoker.intents_target, "target_out_dir") + "/" +
687        get_label_info(invoker.intents_target, "name") + ".module_info.json"
688
689    action(_metadata_extraction) {
690      _output_dir = "$target_out_dir/$target_name"
691      _binary_path = "$target_out_dir/$_output_name"
692
693      visibility = [ ":$_metadata_bundledata" ]
694      script = "//build/config/ios/extract_metadata.py"
695      sources = [
696        _binary_path,
697        _module_info_path,
698      ]
699      outputs = [
700        "$_output_dir/Metadata.appintents/extract.actionsdata",
701        "$_output_dir/Metadata.appintents/version.json",
702      ]
703      deps = [
704        ":$_executable_target",
705        invoker.intents_target,
706      ]
707      depfile = "$target_out_dir/$target_name.d"
708      args = [
709        "--toolchain-dir",
710        rebase_path(ios_toolchains_path, root_build_dir),
711        "--sdk-root",
712        rebase_path(ios_sdk_path, root_build_dir),
713        "--deployment-target",
714        ios_deployment_target,
715        "--target-cpu",
716        current_cpu,
717        "--target-environment",
718        target_environment,
719        "--depfile",
720        rebase_path(depfile, root_build_dir),
721        "--output",
722        rebase_path(_output_dir, root_build_dir),
723        "--binary-file",
724        rebase_path(_binary_path, root_build_dir),
725        "--module-info-path",
726        rebase_path(_module_info_path, root_build_dir),
727      ]
728
729      # Starting with Xcode 15.3, appintentsmetadataprocessor requires to be
730      # passed --xcode-version as parameter (with ${xcode_build} as value),
731      # while previous versions did not recognize the parameter. So check
732      # the version before deciding whether to set the parameter or not.
733      if (xcode_version_int >= 1530) {
734        args += [
735          "--xcode-version",
736          xcode_build,
737        ]
738      }
739    }
740
741    bundle_data(_metadata_bundledata) {
742      public_deps = [ ":$_metadata_extraction" ]
743      sources = get_target_outputs(":$_metadata_extraction")
744      outputs = [ "{{bundle_resources_dir}}/" +
745                  "Metadata.appintents/{{source_file_part}}" ]
746    }
747  }
748
749  _generate_info_plist = target_name + "_generate_info_plist"
750  ios_info_plist(_generate_info_plist) {
751    forward_variables_from(invoker,
752                           [
753                             "info_plist",
754                             "info_plist_target",
755                           ])
756
757    executable_name = _output_name
758
759    extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ]
760    if (defined(invoker.extra_substitutions)) {
761      extra_substitutions += invoker.extra_substitutions
762    }
763  }
764
765  if (!defined(invoker.entitlements_target)) {
766    _entitlements_path = "//build/config/ios/entitlements.plist"
767    if (defined(invoker.entitlements_path)) {
768      _entitlements_path = invoker.entitlements_path
769    }
770  } else {
771    assert(!defined(invoker.entitlements_path),
772           "Cannot define both entitlements_path and entitlements_target" +
773               "for $_target_name")
774
775    _entitlements_target_outputs =
776        get_target_outputs(invoker.entitlements_target)
777    _entitlements_path = _entitlements_target_outputs[0]
778  }
779
780  action(_generate_entitlements_target) {
781    _gen_info_plist_outputs = get_target_outputs(":$_generate_info_plist")
782    _info_plist_path = _gen_info_plist_outputs[0]
783
784    script = "//build/config/ios/codesign.py"
785    deps = [ ":$_generate_info_plist" ]
786    if (defined(invoker.entitlements_target)) {
787      deps += [ invoker.entitlements_target ]
788    }
789    sources = [
790      _entitlements_path,
791      _info_plist_path,
792    ]
793    sources += ios_mobileprovision_files
794
795    outputs = [ _generate_entitlements_output ]
796
797    args = [
798      "generate-entitlements",
799      "-e=" + rebase_path(_entitlements_path, root_build_dir),
800      "-p=" + rebase_path(_info_plist_path, root_build_dir),
801    ]
802    foreach(mobileprovision, ios_mobileprovision_files) {
803      args += [ "-m=" + rebase_path(mobileprovision, root_build_dir) ]
804    }
805    args += rebase_path(outputs, root_build_dir)
806  }
807
808  # Only write PkgInfo for real application, not application extension.
809  if (_is_app_bundle) {
810    _create_pkg_info = target_name + "_pkg_info"
811    action(_create_pkg_info) {
812      forward_variables_from(invoker, [ "testonly" ])
813      script = "//build/apple/write_pkg_info.py"
814      inputs = [ "//build/apple/plist_util.py" ]
815      sources = get_target_outputs(":$_generate_info_plist")
816      outputs = [
817        # Cannot name the output PkgInfo as the name will not be unique if
818        # multiple ios_app_bundle are defined in the same BUILD.gn file. The
819        # file is renamed in the bundle_data outputs to the correct name.
820        "$target_gen_dir/$target_name",
821      ]
822      args = [ "--plist" ] + rebase_path(sources, root_build_dir) +
823             [ "--output" ] + rebase_path(outputs, root_build_dir)
824      deps = [ ":$_generate_info_plist" ]
825    }
826
827    _bundle_data_pkg_info = target_name + "_bundle_data_pkg_info"
828    bundle_data(_bundle_data_pkg_info) {
829      forward_variables_from(invoker, [ "testonly" ])
830      sources = get_target_outputs(":$_create_pkg_info")
831      outputs = [ "{{bundle_resources_dir}}/PkgInfo" ]
832      public_deps = [ ":$_create_pkg_info" ]
833    }
834  }
835
836  foreach(_variant, _variants) {
837    create_signed_bundle(_variant.target_name) {
838      forward_variables_from(invoker,
839                             [
840                               "bundle_deps",
841                               "bundle_deps_filter",
842                               "data_deps",
843                               "deps",
844                               "enable_code_signing",
845                               "entitlements_path",
846                               "entitlements_target",
847                               "extra_system_frameworks",
848                               "public_configs",
849                               "public_deps",
850                               "testonly",
851                               "transparent",
852                               "visibility",
853                               "xcode_extra_attributes",
854                             ])
855
856      output_name = _output_name
857      bundle_gen_dir = _variant.bundle_gen_dir
858      bundle_binary_target = ":$_executable_target"
859      bundle_binary_output = _output_name
860      bundle_extension = _bundle_extension
861      product_type = _product_type
862      xcode_product_bundle_id = _bundle_identifier
863
864      _generate_info_plist_outputs =
865          get_target_outputs(":$_generate_info_plist")
866      primary_info_plist = _generate_info_plist_outputs[0]
867      partial_info_plist =
868          "$target_gen_dir/${_variant.target_name}_partial_info.plist"
869
870      if (!defined(deps)) {
871        deps = []
872      }
873      deps += [ ":$_generate_info_plist" ]
874
875      if (!defined(bundle_deps)) {
876        bundle_deps = []
877      }
878      if (_is_app_bundle) {
879        bundle_deps += [ ":$_bundle_data_pkg_info" ]
880      }
881      bundle_deps += _variant.bundle_deps
882      if (_extract_intents_metadata) {
883        bundle_deps += [ ":$_metadata_bundledata" ]
884      }
885
886      if (target_environment == "simulator") {
887        if (!defined(data_deps)) {
888          data_deps = []
889        }
890        if (build_with_chromium) {
891          data_deps += [ "//testing/iossim" ]
892        }
893      }
894    }
895  }
896
897  if (_default_variant.name != "") {
898    _bundle_short_name = "$_output_name$_bundle_extension"
899    action(_target_name) {
900      forward_variables_from(invoker, [ "testonly" ])
901
902      script = "//build/config/ios/hardlink.py"
903      public_deps = []
904      foreach(_variant, _variants) {
905        public_deps += [ ":${_variant.target_name}" ]
906      }
907
908      sources = [ "${_default_variant.bundle_gen_dir}/$_bundle_short_name" ]
909      outputs = [ "$root_out_dir/$_bundle_short_name" ]
910
911      args = [
912               "--output-dir",
913               rebase_path(root_out_dir, root_build_dir),
914               "--relative-to",
915               rebase_path(_default_variant.bundle_gen_dir, root_build_dir),
916             ] + rebase_path(sources, root_build_dir)
917    }
918  }
919}
920
921set_defaults("ios_app_bundle") {
922  configs = default_executable_configs
923}
924
925# Template to build an application extension bundle for iOS.
926#
927# This should be used instead of "executable" built-in target type on iOS.
928# As the template forward the generation of the application executable to
929# an "executable" target, all arguments supported by "executable" targets
930# are also supported by this template.
931#
932# Arguments
933#
934#   output_name:
935#       (optional) string, name of the generated application, if omitted,
936#       defaults to the target_name.
937#
938#   extra_substitutions:
939#       (optional) list of string in "key=value" format, each value will
940#       be used as an additional variable substitution rule when generating
941#       the application Info.plist
942#
943#   info_plist:
944#       (optional) string, path to the Info.plist file that will be used for
945#       the bundle.
946#
947#   info_plist_target:
948#       (optional) string, if the info_plist is generated from an action,
949#       rather than a regular source file, specify the target name in lieu
950#       of info_plist. The two arguments are mutually exclusive.
951#
952# For more information, see "gn help executable".
953template("ios_appex_bundle") {
954  assert(ios_is_app_extension,
955         "$target_name needs to be defined in app extension toolchain context")
956  ios_app_bundle(target_name) {
957    forward_variables_from(invoker,
958                           "*",
959                           [
960                             "bundle_extension",
961                             "product_type",
962                           ])
963    product_type = _ios_xcode_appex_bundle_id
964  }
965}
966
967set_defaults("ios_appex_bundle") {
968  configs = [ "//build/config/ios:ios_extension_executable_flags" ]
969}
970
971# Template to compile .xib and .storyboard files.
972#
973# Arguments
974#
975#     sources:
976#         list of string, sources to compile
977#
978#     ibtool_flags:
979#         (optional) list of string, additional flags to pass to the ibtool
980template("compile_ib_files") {
981  action_foreach(target_name) {
982    forward_variables_from(invoker,
983                           [
984                             "testonly",
985                             "visibility",
986                           ])
987    assert(defined(invoker.sources),
988           "sources must be specified for $target_name")
989    assert(defined(invoker.output_extension),
990           "output_extension must be specified for $target_name")
991
992    ibtool_flags = []
993    if (defined(invoker.ibtool_flags)) {
994      ibtool_flags = invoker.ibtool_flags
995    }
996
997    _output_extension = invoker.output_extension
998
999    script = "//build/config/ios/compile_ib_files.py"
1000    sources = invoker.sources
1001    outputs = [
1002      "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension",
1003    ]
1004    args = [
1005      "--input",
1006      "{{source}}",
1007      "--output",
1008      rebase_path(
1009          "$target_gen_dir/$target_name/{{source_name_part}}.$_output_extension",
1010          root_build_dir),
1011    ]
1012    args += ibtool_flags
1013  }
1014}
1015
1016# Compile a xib or storyboard file and add it to a bundle_data so that it is
1017# available at runtime in the bundle.
1018#
1019# Arguments
1020#
1021#   source:
1022#       string, path of the xib or storyboard to compile.
1023#
1024# Forwards all variables to the bundle_data target.
1025template("bundle_data_ib_file") {
1026  assert(defined(invoker.source), "source needs to be defined for $target_name")
1027
1028  _source_extension = get_path_info(invoker.source, "extension")
1029  assert(_source_extension == "xib" || _source_extension == "storyboard",
1030         "source must be a .xib or .storyboard for $target_name")
1031
1032  _target_name = target_name
1033  if (_source_extension == "xib") {
1034    _compile_ib_file = target_name + "_compile_xib"
1035    _output_extension = "nib"
1036  } else {
1037    _compile_ib_file = target_name + "_compile_storyboard"
1038    _output_extension = "storyboardc"
1039  }
1040
1041  compile_ib_files(_compile_ib_file) {
1042    sources = [ invoker.source ]
1043    output_extension = _output_extension
1044    visibility = [ ":$_target_name" ]
1045    ibtool_flags = [
1046      "--minimum-deployment-target",
1047      ios_deployment_target,
1048      "--auto-activate-custom-fonts",
1049      "--target-device",
1050      "iphone",
1051      "--target-device",
1052      "ipad",
1053    ]
1054  }
1055
1056  bundle_data(_target_name) {
1057    forward_variables_from(invoker, "*", [ "source" ])
1058
1059    if (!defined(public_deps)) {
1060      public_deps = []
1061    }
1062    public_deps += [ ":$_compile_ib_file" ]
1063
1064    sources = get_target_outputs(":$_compile_ib_file")
1065
1066    outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
1067  }
1068}
1069
1070# Compile a strings file and add it to a bundle_data so that it is available
1071# at runtime in the bundle.
1072#
1073# Arguments
1074#
1075#   source:
1076#       string, path of the strings file to compile.
1077#
1078#   output:
1079#       string, path of the compiled file in the final bundle.
1080#
1081# Forwards all variables to the bundle_data target.
1082template("bundle_data_strings") {
1083  assert(defined(invoker.source), "source needs to be defined for $target_name")
1084  assert(defined(invoker.output), "output needs to be defined for $target_name")
1085
1086  _source_extension = get_path_info(invoker.source, "extension")
1087  assert(_source_extension == "strings",
1088         "source must be a .strings for $target_name")
1089
1090  _target_name = target_name
1091  _convert_target = target_name + "_compile_strings"
1092
1093  convert_plist(_convert_target) {
1094    visibility = [ ":$_target_name" ]
1095    source = invoker.source
1096    output =
1097        "$target_gen_dir/$_target_name/" + get_path_info(invoker.source, "file")
1098    format = "binary1"
1099  }
1100
1101  bundle_data(_target_name) {
1102    forward_variables_from(invoker,
1103                           "*",
1104                           [
1105                             "source",
1106                             "output",
1107                           ])
1108
1109    if (!defined(public_deps)) {
1110      public_deps = []
1111    }
1112    public_deps += [ ":$_convert_target" ]
1113
1114    sources = get_target_outputs(":$_convert_target")
1115
1116    outputs = [ invoker.output ]
1117  }
1118}
1119
1120# This template declares a bundle_data target that reference an assets
1121# catalog so that is is compiled to the asset catalog of the generated
1122# bundle.
1123#
1124# The target will ensure that only the files explicitly listed will be
1125# compiled into the final application (i.e. it allow listing some of
1126# the assets catalog content conditionally).
1127#
1128# The target requires that the files are located in a .xcassets bundle
1129# in the repository (or generated via a script). This ensures that the
1130# assets catalog is correctly visible in Xcode (though as usual, using
1131# Xcode to make change to the .xcassets bundle will not be reflected in
1132# the final build unless the target is updated in the gn configuration).
1133#
1134# Arguments
1135#
1136#     sources:
1137#       required, list of strings, path to the files contained in the
1138#       .xcassets bundle; this may contains a sub-set of the files on
1139#       disk if some assets are only compiled conditionally
1140#
1141#     catalog:
1142#       required, string, path to the .xcassets bundle; all path in
1143#       sources must be relative to this path or the compilation will
1144#       fail
1145#
1146# Example
1147#
1148#     bundle_data_xcassets("assets") {
1149#       catalog = "Assets.xcassets"
1150#       sources = [
1151#         "Assets.xcassets/Color.colorset/Contents.json",
1152#         "Assets.xcassets/Contents.json",
1153#       ]
1154#       if (includes_images) {
1155#         sources += [
1156#           "Assets.xcassets/Image.imageset/Contents.json",
1157#           "Assets.xcassets/Image.imageset/Image.svg",
1158#         ]
1159#       }
1160#     }
1161template("bundle_data_xcassets") {
1162  assert(defined(invoker.sources), "sources must be defined for $target_name")
1163  assert(defined(invoker.catalog), "catalog must be defined for $target_name")
1164
1165  _target_name = target_name
1166  _target_zip = target_name + "_zip"
1167
1168  zip(_target_zip) {
1169    _catalog_name = get_path_info(invoker.catalog, "file")
1170    _catalog_path = get_path_info(invoker.catalog, "dir")
1171
1172    inputs = invoker.sources
1173    output = "$target_out_dir/$target_name/$_catalog_name"
1174    base_dir = _catalog_path
1175  }
1176
1177  bundle_data(_target_name) {
1178    forward_variables_from(invoker,
1179                           "*",
1180                           [
1181                             "sources",
1182                             "deps",
1183                             "public_deps",
1184                           ])
1185
1186    public_deps = [ ":$_target_zip" ]
1187    sources = get_target_outputs(":$_target_zip")
1188    outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ]
1189  }
1190}
1191
1192# Template to package a shared library into an iOS framework bundle.
1193#
1194# By default, the bundle target this template generates does not link the
1195# resulting framework into anything that depends on it. If a dependency wants
1196# a link-time (as well as build-time) dependency on the framework bundle,
1197# depend against "$target_name+link". If only the build-time dependency is
1198# required (e.g., for copying into another bundle), then use "$target_name".
1199#
1200# Arguments
1201#
1202#     output_name:
1203#         (optional) string, name of the generated framework without the
1204#         .framework suffix. If omitted, defaults to target_name.
1205#
1206#     public_headers:
1207#         (optional) list of paths to header file that needs to be copied
1208#         into the framework bundle Headers subdirectory. If omitted or
1209#         empty then the Headers subdirectory is not created.
1210#
1211#     sources
1212#         (optional) list of files. Needs to be defined and non-empty if
1213#         public_headers is defined and non-empty.
1214#
1215#   enable_code_signing
1216#       (optional) boolean, control whether code signing is enabled or not,
1217#       default to ios_enable_code_signing if not defined.
1218#
1219#   transparent
1220#       (optional) boolean, whether the bundle is "transparent"; defaults to
1221#       "false" if omitted; a bundle is considered "transparent" if it does
1222#       not package the "bundle_data" deps but forward them to all targets
1223#       the depend on it (unless the "bundle_data" target sets "product_type"
1224#       to "com.apple.product-type.framework").
1225#
1226# This template provides two targets for the resulting framework bundle. The
1227# link-time behavior varies depending on which of the two targets below is
1228# added as a dependency:
1229#   - $target_name only adds a build-time dependency. Targets that depend on
1230#     it will not link against the framework.
1231#   - $target_name+link adds a build-time and link-time dependency. Targets
1232#     that depend on it will link against the framework.
1233#
1234# The build-time-only dependency is used for when a target needs to use the
1235# framework either only for resources, or because the target loads it at run-
1236# time, via dlopen() or NSBundle. The link-time dependency will cause the
1237# dependee to have the framework loaded by dyld at launch.
1238#
1239# Example of build-time only dependency:
1240#
1241#     framework_bundle("CoreTeleportation") {
1242#       sources = [ ... ]
1243#     }
1244#
1245#     bundle_data("core_teleportation_bundle_data") {
1246#       deps = [ ":CoreTeleportation" ]
1247#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
1248#       outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
1249#     }
1250#
1251#     app_bundle("GoatTeleporter") {
1252#       sources = [ ... ]
1253#       deps = [
1254#         ":core_teleportation_bundle_data",
1255#       ]
1256#     }
1257#
1258# The GoatTeleporter.app will not directly link against
1259# CoreTeleportation.framework, but it will be included in the bundle's
1260# Frameworks directory.
1261#
1262# Example of link-time dependency:
1263#
1264#     framework_bundle("CoreTeleportation") {
1265#       sources = [ ... ]
1266#       ldflags = [
1267#         "-install_name",
1268#         "@executable_path/../Frameworks/$target_name.framework"
1269#       ]
1270#     }
1271#
1272#     bundle_data("core_teleportation_bundle_data") {
1273#       deps = [ ":CoreTeleportation+link" ]
1274#       sources = [ "$root_out_dir/CoreTeleportation.framework" ]
1275#       outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ]
1276#     }
1277#
1278#     app_bundle("GoatTeleporter") {
1279#       sources = [ ... ]
1280#       deps = [
1281#         ":core_teleportation_bundle_data",
1282#       ]
1283#     }
1284#
1285# Note that the framework is still copied to the app's bundle, but dyld will
1286# load this library when the app is launched because it uses the "+link"
1287# target as a dependency. This also requires that the framework set its
1288# install_name so that dyld can locate it.
1289#
1290# See "gn help shared_library" for more information on arguments supported
1291# by shared library target.
1292template("ios_framework_bundle") {
1293  _target_name = target_name
1294  _output_name = target_name
1295  if (defined(invoker.output_name)) {
1296    _output_name = invoker.output_name
1297  }
1298
1299  _product_type = "com.apple.product-type.framework"
1300  _has_public_headers =
1301      defined(invoker.public_headers) && invoker.public_headers != []
1302
1303  _shared_library_target = _target_name + "_shared_library"
1304  _link_target_name = _target_name + "+link"
1305
1306  if (_has_public_headers) {
1307    _default_toolchain_target_gen_dir =
1308        get_label_info("$_target_name", "target_gen_dir")
1309
1310    _framework_headers_target = _target_name + "_framework_headers"
1311
1312    _headers_map_config = _target_name + "_headers_map"
1313    _header_map_filename =
1314        "$_default_toolchain_target_gen_dir/$_output_name.headers.hmap"
1315    config(_headers_map_config) {
1316      visibility = [
1317        ":${_shared_library_target}",
1318        ":${_target_name}_signed_bundle",
1319      ]
1320      include_dirs = [ _header_map_filename ]
1321    }
1322  }
1323
1324  _framework_headers_config = _target_name + "_framework_headers_config"
1325  config(_framework_headers_config) {
1326    framework_dirs = [ root_out_dir ]
1327  }
1328
1329  _framework_public_config = _target_name + "_public_config"
1330  config(_framework_public_config) {
1331    configs = [ ":$_framework_headers_config" ]
1332    frameworks = [ "$_output_name.framework" ]
1333  }
1334
1335  shared_library(_shared_library_target) {
1336    forward_variables_from(invoker,
1337                           "*",
1338                           [
1339                             "bundle_deps",
1340                             "bundle_deps_filter",
1341                             "data_deps",
1342                             "enable_code_signing",
1343                             "extra_substitutions",
1344                             "info_plist",
1345                             "info_plist_target",
1346                             "output_name",
1347                             "public_configs",
1348                             "transparent",
1349                             "visibility",
1350                           ])
1351
1352    visibility = [ ":${_target_name}_signed_bundle" ]
1353
1354    if (!defined(ldflags)) {
1355      ldflags = []
1356    }
1357    ldflags +=
1358        [ "-Wl,-install_name,@rpath/$_output_name.framework/$_output_name" ]
1359
1360    if (_has_public_headers) {
1361      configs += [ ":$_headers_map_config" ]
1362
1363      if (!defined(deps)) {
1364        deps = []
1365      }
1366      deps += [ ":$_framework_headers_target" ]
1367    }
1368
1369    output_extension = ""
1370    output_name = _output_name
1371    output_prefix_override = true
1372    output_dir = target_out_dir
1373  }
1374
1375  if (_has_public_headers) {
1376    _public_headers = invoker.public_headers
1377
1378    _framework_root_dir = "$root_out_dir/$_output_name.framework"
1379    if (target_environment == "simulator" || target_environment == "device") {
1380      _framework_contents_dir = _framework_root_dir
1381    } else if (target_environment == "catalyst") {
1382      _framework_contents_dir = "$_framework_root_dir/Versions/A"
1383    }
1384
1385    _compile_headers_map_target = _target_name + "_compile_headers_map"
1386    action(_compile_headers_map_target) {
1387      visibility = [ ":$_framework_headers_target" ]
1388      forward_variables_from(invoker,
1389                             [
1390                               "deps",
1391                               "public_deps",
1392                               "testonly",
1393                             ])
1394      script = "//build/config/ios/write_framework_hmap.py"
1395      outputs = [ _header_map_filename ]
1396
1397      # The header map generation only wants the list of headers, not all of
1398      # sources, so filter any non-header source files from "sources". It is
1399      # less error prone that having the developer duplicate the list of all
1400      # headers in addition to "sources".
1401      sources = []
1402      if (defined(invoker.sources)) {
1403        foreach(_source, invoker.sources) {
1404          if (get_path_info(_source, "extension") == "h") {
1405            sources += [ _source ]
1406          }
1407        }
1408      }
1409
1410      args = [
1411               rebase_path(_header_map_filename, root_build_dir),
1412               rebase_path(_framework_root_dir, root_build_dir),
1413             ] + rebase_path(sources, root_build_dir)
1414    }
1415
1416    _create_module_map_target = _target_name + "_module_map"
1417    action(_create_module_map_target) {
1418      visibility = [ ":$_framework_headers_target" ]
1419      script = "//build/config/ios/write_framework_modulemap.py"
1420      outputs = [ "$_framework_contents_dir/Modules/module.modulemap" ]
1421      args = [
1422        _output_name,
1423        rebase_path("$_framework_contents_dir/Modules", root_build_dir),
1424      ]
1425    }
1426
1427    _copy_public_headers_target = _target_name + "_copy_public_headers"
1428    copy(_copy_public_headers_target) {
1429      forward_variables_from(invoker,
1430                             [
1431                               "testonly",
1432                               "deps",
1433                             ])
1434      visibility = [ ":$_framework_headers_target" ]
1435      sources = _public_headers
1436      outputs = [ "$_framework_contents_dir/Headers/{{source_file_part}}" ]
1437
1438      # Do not use forward_variables_from for "public_deps" as
1439      # we do not want to forward those dependencies.
1440      if (defined(invoker.public_deps)) {
1441        if (!defined(deps)) {
1442          deps = []
1443        }
1444        deps += invoker.public_deps
1445      }
1446    }
1447
1448    group(_framework_headers_target) {
1449      forward_variables_from(invoker, [ "testonly" ])
1450      deps = [
1451        ":$_compile_headers_map_target",
1452        ":$_create_module_map_target",
1453      ]
1454      public_deps = [ ":$_copy_public_headers_target" ]
1455    }
1456  }
1457
1458  # Bundle identifier should respect rfc1034, so replace "_" with "-".
1459  _bundle_identifier =
1460      "$ios_app_bundle_id_prefix." + string_replace(_output_name, "_", "-")
1461
1462  _info_plist_target = _target_name + "_info_plist"
1463  _info_plist_bundle = _target_name + "_info_plist_bundle"
1464  ios_info_plist(_info_plist_target) {
1465    visibility = [ ":$_info_plist_bundle" ]
1466    executable_name = _output_name
1467    forward_variables_from(invoker,
1468                           [
1469                             "info_plist",
1470                             "info_plist_target",
1471                           ])
1472
1473    extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ]
1474    if (defined(invoker.extra_substitutions)) {
1475      extra_substitutions += invoker.extra_substitutions
1476    }
1477  }
1478
1479  bundle_data(_info_plist_bundle) {
1480    visibility = [ ":${_target_name}_signed_bundle" ]
1481    forward_variables_from(invoker, [ "testonly" ])
1482    sources = get_target_outputs(":$_info_plist_target")
1483    public_deps = [ ":$_info_plist_target" ]
1484    product_type = _product_type
1485
1486    if (target_environment != "catalyst") {
1487      outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
1488    } else {
1489      outputs = [ "{{bundle_resources_dir}}/Info.plist" ]
1490    }
1491  }
1492
1493  create_signed_bundle(_target_name + "_signed_bundle") {
1494    forward_variables_from(invoker,
1495                           [
1496                             "bundle_deps",
1497                             "bundle_deps_filter",
1498                             "data_deps",
1499                             "deps",
1500                             "enable_code_signing",
1501                             "public_configs",
1502                             "public_deps",
1503                             "testonly",
1504                             "transparent",
1505                             "visibility",
1506                           ])
1507
1508    product_type = _product_type
1509    bundle_extension = ".framework"
1510
1511    output_name = _output_name
1512    bundle_binary_target = ":$_shared_library_target"
1513    bundle_binary_output = _output_name
1514
1515    has_public_headers = _has_public_headers
1516
1517    # Framework do not have entitlements nor mobileprovision because they use
1518    # the one from the bundle using them (.app or .appex) as they are just
1519    # dynamic library with shared code.
1520    disable_entitlements = true
1521    disable_embedded_mobileprovision = true
1522
1523    if (!defined(deps)) {
1524      deps = []
1525    }
1526    deps += [ ":$_info_plist_bundle" ]
1527  }
1528
1529  group(_target_name) {
1530    forward_variables_from(invoker,
1531                           [
1532                             "public_configs",
1533                             "public_deps",
1534                             "testonly",
1535                             "visibility",
1536                           ])
1537    if (!defined(public_deps)) {
1538      public_deps = []
1539    }
1540    public_deps += [ ":${_target_name}_signed_bundle" ]
1541
1542    if (_has_public_headers) {
1543      if (!defined(public_configs)) {
1544        public_configs = []
1545      }
1546      public_configs += [ ":$_framework_headers_config" ]
1547    }
1548  }
1549
1550  group(_link_target_name) {
1551    forward_variables_from(invoker,
1552                           [
1553                             "public_configs",
1554                             "public_deps",
1555                             "testonly",
1556                             "visibility",
1557                           ])
1558    if (!defined(public_deps)) {
1559      public_deps = []
1560    }
1561    public_deps += [ ":$_target_name" ]
1562
1563    if (!defined(all_dependent_configs)) {
1564      all_dependent_configs = []
1565    }
1566    all_dependent_configs += [ ":$_framework_public_config" ]
1567  }
1568
1569  bundle_data(_target_name + "+bundle") {
1570    forward_variables_from(invoker,
1571                           [
1572                             "testonly",
1573                             "visibility",
1574                           ])
1575    public_deps = [ ":$_target_name" ]
1576    sources = [ "$root_out_dir/$_output_name.framework" ]
1577    outputs = [ "{{bundle_contents_dir}}/Frameworks/$_output_name.framework" ]
1578  }
1579}
1580
1581set_defaults("ios_framework_bundle") {
1582  configs = default_shared_library_configs
1583}
1584
1585# Template to build a xctest bundle that contains a loadable module for iOS.
1586#
1587# Arguments
1588#
1589#   deps:
1590#       list of labels to depends on, these values are used to create the
1591#       loadable module.
1592#
1593#   product_type
1594#       string, product type for the generated Xcode project, use
1595#       "com.apple.product-type.bundle.unit-test" for unit test and
1596#       "com.apple.product-type.bundle.ui-testing" for UI testing.
1597#
1598#   host_target:
1599#       string, name of the target that depends on the generated bundle, this
1600#       value is used to restrict visibilities.
1601#
1602#   xcode_test_application_name:
1603#       string, name of the test application for Xcode unit or ui test target.
1604#
1605#   output_name
1606#       (optional) string, name of the generated application, if omitted,
1607#       defaults to the target_name.
1608#
1609# This template defines two targets, one named "${target_name}" is the xctest
1610# bundle, and the other named "${target_name}_bundle" is a bundle_data that
1611# wraps the xctest bundle and that only the "${host_target}" can depend on.
1612#
1613template("ios_xctest_bundle") {
1614  assert(defined(invoker.deps), "deps must be defined for $target_name")
1615  assert(defined(invoker.product_type),
1616         "product_type must be defined for $target_name")
1617  assert(invoker.product_type == _ios_xcode_xctest_bundle_id ||
1618             invoker.product_type == _ios_xcode_xcuitest_bundle_id,
1619         "product_type defined for $target_name is invalid.")
1620  assert(defined(invoker.host_target),
1621         "host_target must be defined for $target_name")
1622  assert(defined(invoker.xcode_test_application_name),
1623         "xcode_test_application_name must be defined for $target_name")
1624
1625  _target_name = target_name
1626  _output_name = target_name
1627
1628  if (defined(invoker.output_name)) {
1629    _output_name = invoker.output_name
1630  }
1631
1632  _loadable_module_target = _target_name + "_loadable_module"
1633
1634  loadable_module(_loadable_module_target) {
1635    forward_variables_from(invoker,
1636                           "*",
1637                           [
1638                             "bundle_deps",
1639                             "bundle_deps_filter",
1640                             "host_target",
1641                             "output_dir",
1642                             "output_extension",
1643                             "output_name",
1644                             "output_prefix_override",
1645                             "product_type",
1646                             "testonly",
1647                             "visibility",
1648                             "xcode_test_application_name",
1649                             "xcode_test_application_output_name",
1650                             "xctest_bundle_principal_class",
1651                           ])
1652
1653    testonly = true
1654    visibility = [ ":$_target_name" ]
1655
1656    configs += [ "//build/config/ios:xctest_config" ]
1657
1658    output_dir = target_out_dir
1659    output_name = _output_name
1660    output_prefix_override = true
1661    output_extension = ""
1662  }
1663
1664  _info_plist_target = _target_name + "_info_plist"
1665  _info_plist_bundle = _target_name + "_info_plist_bundle"
1666
1667  # Bundle identifier should respect rfc1034, so replace "_" with "-".
1668  _bundle_identifier = "$ios_app_bundle_id_prefix.chrome." +
1669                       string_replace(_output_name, "_", "-")
1670
1671  ios_info_plist(_info_plist_target) {
1672    testonly = true
1673    visibility = [ ":$_info_plist_bundle" ]
1674
1675    info_plist = "//build/config/ios/Module-Info.plist"
1676    executable_name = _output_name
1677
1678    if (defined(invoker.xctest_bundle_principal_class)) {
1679      _principal_class = invoker.xctest_bundle_principal_class
1680    } else {
1681      # Fall back to a reasonable default value.
1682      _principal_class = "NSObject"
1683    }
1684    extra_substitutions = [
1685      "XCTEST_BUNDLE_PRINCIPAL_CLASS=${_principal_class}",
1686      "BUNDLE_IDENTIFIER=$_bundle_identifier",
1687    ]
1688  }
1689
1690  bundle_data(_info_plist_bundle) {
1691    testonly = true
1692    visibility = [ ":$_target_name" ]
1693
1694    public_deps = [ ":$_info_plist_target" ]
1695
1696    sources = get_target_outputs(":$_info_plist_target")
1697    outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
1698  }
1699
1700  _xctest_bundle = _target_name + "_bundle"
1701  create_signed_bundle(_target_name) {
1702    forward_variables_from(invoker,
1703                           [
1704                             "bundle_deps",
1705                             "bundle_deps_filter",
1706                             "bundle_id",
1707                             "data_deps",
1708                             "enable_code_signing",
1709                             "product_type",
1710                             "transparent",
1711                             "xcode_test_application_name",
1712                           ])
1713
1714    testonly = true
1715    visibility = [ ":$_xctest_bundle" ]
1716
1717    bundle_extension = ".xctest"
1718
1719    output_name = _output_name
1720    bundle_binary_target = ":$_loadable_module_target"
1721    bundle_binary_output = _output_name
1722
1723    xcode_extra_attributes = {
1724      IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target
1725      PRODUCT_BUNDLE_IDENTIFIER = _bundle_identifier
1726      CODE_SIGNING_REQUIRED = "NO"
1727      CODE_SIGNING_ALLOWED = "NO"
1728      CODE_SIGN_IDENTITY = ""
1729      DONT_GENERATE_INFOPLIST_FILE = "YES"
1730
1731      # For XCUITest, Xcode requires specifying the host application name
1732      # via the TEST_TARGET_NAME attribute.
1733      if (invoker.product_type == _ios_xcode_xcuitest_bundle_id) {
1734        TEST_TARGET_NAME = invoker.xcode_test_application_name
1735      }
1736
1737      # For XCTest, Xcode requires specifying the host application path via
1738      # both BUNDLE_LOADER and TEST_HOST attributes.
1739      if (invoker.product_type == _ios_xcode_xctest_bundle_id) {
1740        _xcode_app_name = invoker.xcode_test_application_name
1741        if (defined(invoker.xcode_test_application_output_name)) {
1742          _xcode_app_name = invoker.xcode_test_application_output_name
1743        }
1744
1745        BUNDLE_LOADER = "\$(TEST_HOST)"
1746        TEST_HOST = "\$(BUILT_PRODUCTS_DIR)/" +
1747                    "${_xcode_app_name}.app/${_xcode_app_name}"
1748      }
1749    }
1750
1751    deps = [ ":$_info_plist_bundle" ]
1752  }
1753
1754  bundle_data(_xctest_bundle) {
1755    forward_variables_from(invoker, [ "host_target" ])
1756
1757    testonly = true
1758    visibility = [ ":$host_target" ]
1759
1760    public_deps = [ ":$_target_name" ]
1761    sources = [ "$root_out_dir/$_output_name.xctest" ]
1762    outputs = [ "{{bundle_contents_dir}}/PlugIns/$_output_name.xctest" ]
1763  }
1764}
1765
1766set_defaults("ios_xctest_bundle") {
1767  configs = default_shared_library_configs
1768}
1769
1770# For Chrome on iOS we want to run XCTests for all our build configurations
1771# (Debug, Release, ...). In addition, the symbols visibility is configured to
1772# private by default. To simplify testing with those constraints, our tests are
1773# compiled in the TEST_HOST target instead of the .xctest bundle.
1774template("ios_xctest_test") {
1775  _target_name = target_name
1776  _output_name = target_name
1777  if (defined(invoker.output_name)) {
1778    _output_name = invoker.output_name
1779  }
1780
1781  _xctest_target = _target_name + "_module"
1782  _xctest_output = _output_name + "_module"
1783
1784  _host_target = _target_name
1785  _host_output = _output_name
1786
1787  # Allow invokers to specify their own target for the xctest module, but
1788  # fall back to a default (empty) module otherwise.
1789  if (defined(invoker.xctest_module_target)) {
1790    _xctest_module_target = invoker.xctest_module_target
1791  } else {
1792    _xctest_module_target_name = _xctest_target + "shell_source"
1793    _xctest_module_target = ":$_xctest_module_target_name"
1794    source_set(_xctest_module_target_name) {
1795      sources = [ "//build/config/ios/xctest_shell.mm" ]
1796
1797      configs += [ "//build/config/ios:xctest_config" ]
1798    }
1799  }
1800
1801  ios_xctest_bundle(_xctest_target) {
1802    forward_variables_from(invoker, [ "data_deps" ])
1803    output_name = _xctest_output
1804    product_type = _ios_xcode_xctest_bundle_id
1805    host_target = _host_target
1806
1807    # TODO(crbug.com/40120290) The change in output name results in a mismatch
1808    # between this value and the ios_app_bundle target name. To mitigate, this
1809    # has been modified to _host_target. output_name is set to _host_output
1810    # to mitigate the naming.
1811    xcode_test_application_name = _host_target
1812    xcode_test_application_output_name = _host_output
1813
1814    deps = [ _xctest_module_target ]
1815  }
1816
1817  ios_app_bundle(_host_target) {
1818    forward_variables_from(invoker, "*", [ "testonly" ])
1819
1820    testonly = true
1821    output_name = _host_output
1822    configs += [ "//build/config/ios:xctest_config" ]
1823
1824    if (!defined(invoker.info_plist) && !defined(invoker.info_plist_target)) {
1825      info_plist = "//build/config/ios/Host-Info.plist"
1826    }
1827
1828    # Xcode needs the following frameworks installed in the application (and
1829    # signed) for the XCTest to run, so install them using
1830    # extra_system_frameworks.
1831    extra_system_frameworks = [
1832      "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework",
1833      "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
1834      "$ios_sdk_platform_path/Developer/usr/lib/libXCTestBundleInject.dylib",
1835    ]
1836
1837    # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over
1838    # everything that Xcode copies.
1839    if (xcode_version_int >= 1300) {
1840      extra_system_frameworks += [
1841        "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework",
1842        "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework",
1843        "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework",
1844        "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib",
1845      ]
1846    }
1847
1848    # XCTestSupport framework is required as of Xcode 14.3 or later.
1849    if (xcode_version_int >= 1430) {
1850      extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ]
1851    }
1852
1853    _xctest_bundle = _xctest_target + "_bundle"
1854    if (!defined(bundle_deps)) {
1855      bundle_deps = []
1856    }
1857    bundle_deps += [ ":$_xctest_bundle" ]
1858  }
1859}
1860
1861set_defaults("ios_xctest_test") {
1862  configs = default_executable_configs
1863}
1864
1865# Template to build a xcuitest test runner bundle.
1866#
1867# Xcode requires a test runner application with a copy of the XCTest dynamic
1868# library bundle in it for the XCUITest to run. The test runner bundle is created
1869# by copying the system bundle XCTRunner.app from Xcode SDK with the plist file
1870# being properly tweaked, and a xctest and it needs to be code signed in order
1871# to run on devices.
1872#
1873# Arguments
1874#
1875#   xctest_bundle
1876#       string, name of the dependent xctest bundle target.
1877#
1878#   output_name
1879#       (optional) string, name of the generated application, if omitted,
1880#       defaults to the target_name.
1881#
1882template("ios_xcuitest_test_runner_bundle") {
1883  assert(defined(invoker.xctest_bundle),
1884         "xctest_bundle must be defined for $target_name")
1885
1886  _target_name = target_name
1887  _output_name = target_name
1888  if (defined(invoker.output_name)) {
1889    _output_name = invoker.output_name
1890  }
1891
1892  # Bundle identifier should respect rfc1034, so replace "_" with "-".
1893  _bundle_identifier = "$ios_app_bundle_id_prefix.chrome." +
1894                       string_replace(_output_name, "_", "-")
1895
1896  _xctrunner_path =
1897      "$ios_sdk_platform_path/Developer/Library/Xcode/Agents/XCTRunner.app"
1898
1899  _info_plist_merge_plist = _target_name + "_info_plist_merge_plist"
1900  _info_plist_target = _target_name + "_info_plist"
1901  _info_plist_bundle = _target_name + "_info_plist_bundle"
1902
1903  action(_info_plist_merge_plist) {
1904    testonly = true
1905    script = "//build/apple/plist_util.py"
1906
1907    sources = [
1908      "$_xctrunner_path/Info.plist",
1909
1910      # NOTE: The XCTRunnerAddition+Info.plist must come after the Info.plist
1911      # because it overrides the values under "CFBundleIdentifier" and
1912      # "CFBundleName".
1913      "//build/config/ios/resources/XCTRunnerAddition+Info.plist",
1914    ]
1915
1916    _output_name = "$target_gen_dir/${_target_name}_merged.plist"
1917    outputs = [ _output_name ]
1918    args = [
1919             "merge",
1920             "-f=xml1",
1921             "-x=$xcode_version",
1922             "-o=" + rebase_path(_output_name, root_build_dir),
1923           ] + rebase_path(sources, root_build_dir)
1924
1925    if (use_system_xcode && use_remoteexec) {
1926      deps = [ "//build/config/ios:copy_xctrunner_app" ]
1927    }
1928  }
1929
1930  ios_info_plist(_info_plist_target) {
1931    testonly = true
1932    visibility = [ ":$_info_plist_bundle" ]
1933
1934    executable_name = _output_name
1935    info_plist_target = ":$_info_plist_merge_plist"
1936    extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ]
1937  }
1938
1939  bundle_data(_info_plist_bundle) {
1940    testonly = true
1941    visibility = [ ":$_target_name" ]
1942
1943    public_deps = [ ":$_info_plist_target" ]
1944
1945    sources = get_target_outputs(":$_info_plist_target")
1946    outputs = [ "{{bundle_contents_dir}}/Info.plist" ]
1947  }
1948
1949  _pkginfo_bundle = _target_name + "_pkginfo_bundle"
1950  bundle_data(_pkginfo_bundle) {
1951    testonly = true
1952    visibility = [ ":$_target_name" ]
1953
1954    sources = [ "$_xctrunner_path/PkgInfo" ]
1955
1956    outputs = [ "{{bundle_contents_dir}}/PkgInfo" ]
1957
1958    if (use_system_xcode && use_remoteexec) {
1959      public_deps = [ "//build/config/ios:copy_xctrunner_app" ]
1960    }
1961  }
1962
1963  _xctest_bundle = invoker.xctest_bundle
1964  create_signed_bundle(_target_name) {
1965    testonly = true
1966
1967    bundle_binary_target = "//build/config/ios:xctest_runner_without_arm64e"
1968    bundle_binary_output = "XCTRunner"
1969    bundle_extension = ".app"
1970    product_type = _ios_xcode_app_bundle_id
1971
1972    output_name = _output_name
1973
1974    # Xcode needs the following frameworks installed in the application
1975    # (and signed) for the XCUITest to run, so install them using
1976    # extra_system_frameworks.
1977    extra_system_frameworks = [
1978      "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework",
1979      "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework",
1980    ]
1981
1982    # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over
1983    # everything that Xcode copies.
1984    if (xcode_version_int >= 1300) {
1985      extra_system_frameworks += [
1986        "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework",
1987        "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework",
1988        "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework",
1989        "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib",
1990      ]
1991    }
1992
1993    # XCTestSupport framework is required as of Xcode 14.3 or later.
1994    if (xcode_version_int >= 1430) {
1995      extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ]
1996    }
1997
1998    bundle_deps = []
1999    if (defined(invoker.bundle_deps)) {
2000      bundle_deps += invoker.bundle_deps
2001    }
2002    bundle_deps += [
2003      ":$_info_plist_bundle",
2004      ":$_pkginfo_bundle",
2005      ":$_xctest_bundle",
2006    ]
2007  }
2008}
2009
2010# Template to build a XCUITest that consists of two parts: the test runner
2011# application bundle and the xctest dynamic library.
2012#
2013# Arguments
2014#
2015#   deps:
2016#       list of labels to depends on, these values are used to create the
2017#       xctest dynamic library.
2018#
2019#   xcode_test_application_name:
2020#       string, name of the test application for the ui test target.
2021#
2022#   runner_only_bundle_deps:
2023#       list of labels of bundle target to include in the runner and
2024#       exclude from the test module (the use case is a framework bundle
2025#       that is used by the test module and thus needs to be packaged in
2026#       the runner application bundle)
2027#
2028# This template defines two targets, one named "${target_name}_module" is the
2029# xctest dynamic library, and the other named "${target_name}_runner" is the
2030# test runner application bundle.
2031#
2032template("ios_xcuitest_test") {
2033  assert(defined(invoker.deps), "deps must be defined for $target_name")
2034  assert(defined(invoker.xcode_test_application_name),
2035         "xcode_test_application_name must be defined for $target_name")
2036
2037  _xcuitest_target = target_name
2038  if (defined(invoker.output_name)) {
2039    _xcuitest_target = invoker.output_name
2040  }
2041
2042  _xcuitest_runner_target = _xcuitest_target + "_runner"
2043  _xcuitest_module_target = _xcuitest_target + "_module"
2044
2045  group(target_name) {
2046    testonly = true
2047
2048    deps = [ ":$_xcuitest_runner_target" ]
2049  }
2050
2051  _xcuitest_module_output = _xcuitest_target
2052  ios_xctest_bundle(_xcuitest_module_target) {
2053    forward_variables_from(invoker,
2054                           [
2055                             "bundle_deps",
2056                             "data_deps",
2057                             "deps",
2058                             "xcode_test_application_name",
2059                             "xctest_bundle_principal_class",
2060                           ])
2061
2062    product_type = _ios_xcode_xcuitest_bundle_id
2063    host_target = _xcuitest_runner_target
2064    output_name = _xcuitest_module_output
2065
2066    if (defined(invoker.runner_only_bundle_deps)) {
2067      bundle_deps_filter = invoker.runner_only_bundle_deps
2068    }
2069  }
2070
2071  _xcuitest_runner_output = _xcuitest_target + "-Runner"
2072  ios_xcuitest_test_runner_bundle(_xcuitest_runner_target) {
2073    output_name = _xcuitest_runner_output
2074    xctest_bundle = _xcuitest_module_target + "_bundle"
2075
2076    if (defined(invoker.runner_only_bundle_deps)) {
2077      if (!defined(bundle_deps)) {
2078        bundle_deps = []
2079      }
2080      bundle_deps += invoker.runner_only_bundle_deps
2081    }
2082  }
2083}
2084
2085set_defaults("ios_xcuitest_test") {
2086  configs = default_executable_configs
2087}
2088