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