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 "xcode_extra_attributes", 522 ]) 523 524 output_name = _output_name 525 bundle_gen_dir = _variant.bundle_gen_dir 526 bundle_binary_target = ":$_executable_target" 527 bundle_binary_output = _output_name 528 bundle_extension = _bundle_extension 529 product_type = _product_type 530 xcode_product_bundle_id = _bundle_identifier 531 532 _generate_info_plist_outputs = 533 get_target_outputs(":$_generate_info_plist") 534 primary_info_plist = _generate_info_plist_outputs[0] 535 partial_info_plist = 536 "$target_gen_dir/${_variant.target_name}_partial_info.plist" 537 538 if (!defined(deps)) { 539 deps = [] 540 } 541 deps += [ ":$_generate_info_plist" ] 542 543 if (!defined(bundle_deps)) { 544 bundle_deps = [] 545 } 546 if (_is_app_bundle) { 547 bundle_deps += [ ":$_bundle_data_pkg_info" ] 548 } 549 bundle_deps += _variant.bundle_deps 550 if (_extract_intents_metadata) { 551 bundle_deps += [ ":$_metadata_bundledata" ] 552 } 553 554 if (target_environment == "simulator") { 555 if (!defined(data_deps)) { 556 data_deps = [] 557 } 558 if (build_with_chromium) { 559 data_deps += [ "//testing/iossim" ] 560 } 561 } 562 } 563 } 564 565 if (_default_variant.name != "") { 566 _bundle_short_name = "$_output_name$_bundle_extension" 567 action(_target_name) { 568 forward_variables_from(invoker, [ "testonly" ]) 569 570 script = "//build/config/ios/hardlink.py" 571 public_deps = [] 572 foreach(_variant, _variants) { 573 public_deps += [ ":${_variant.target_name}" ] 574 } 575 576 sources = [ "${_default_variant.bundle_gen_dir}/$_bundle_short_name" ] 577 outputs = [ "$root_out_dir/$_bundle_short_name" ] 578 579 args = [ 580 "--output-dir", 581 rebase_path(root_out_dir, root_build_dir), 582 "--relative-to", 583 rebase_path(_default_variant.bundle_gen_dir, root_build_dir), 584 ] + rebase_path(sources, root_build_dir) 585 } 586 } 587} 588 589set_defaults("ios_app_bundle") { 590 configs = default_executable_configs 591} 592 593# Template to build an application extension bundle for iOS. 594# 595# This should be used instead of "executable" built-in target type on iOS. 596# As the template forward the generation of the application executable to 597# an "executable" target, all arguments supported by "executable" targets 598# are also supported by this template. 599# 600# Arguments 601# 602# output_name: 603# (optional) string, name of the generated application, if omitted, 604# defaults to the target_name. 605# 606# extra_substitutions: 607# (optional) list of string in "key=value" format, each value will 608# be used as an additional variable substitution rule when generating 609# the application Info.plist 610# 611# info_plist: 612# (optional) string, path to the Info.plist file that will be used for 613# the bundle. 614# 615# info_plist_target: 616# (optional) string, if the info_plist is generated from an action, 617# rather than a regular source file, specify the target name in lieu 618# of info_plist. The two arguments are mutually exclusive. 619# 620# For more information, see "gn help executable". 621template("ios_appex_bundle") { 622 assert(ios_is_app_extension, 623 "$target_name needs to be defined in app extension toolchain context") 624 ios_app_bundle(target_name) { 625 forward_variables_from(invoker, 626 "*", 627 [ 628 "bundle_extension", 629 "product_type", 630 ]) 631 product_type = apple_mobile_xcode_appex_bundle_id 632 } 633} 634 635set_defaults("ios_appex_bundle") { 636 configs = [ "//build/config/ios:ios_extension_executable_flags" ] 637} 638 639# Template to package a shared library into an iOS framework bundle. 640# 641# By default, the bundle target this template generates does not link the 642# resulting framework into anything that depends on it. If a dependency wants 643# a link-time (as well as build-time) dependency on the framework bundle, 644# depend against "$target_name+link". If only the build-time dependency is 645# required (e.g., for copying into another bundle), then use "$target_name". 646# 647# Arguments 648# 649# output_name: 650# (optional) string, name of the generated framework without the 651# .framework suffix. If omitted, defaults to target_name. 652# 653# public_headers: 654# (optional) list of paths to header file that needs to be copied 655# into the framework bundle Headers subdirectory. If omitted or 656# empty then the Headers subdirectory is not created. 657# 658# sources 659# (optional) list of files. Needs to be defined and non-empty if 660# public_headers is defined and non-empty. 661# 662# enable_code_signing 663# (optional) boolean, control whether code signing is enabled or not, 664# default to ios_enable_code_signing if not defined. 665# 666# transparent 667# (optional) boolean, whether the bundle is "transparent"; defaults to 668# "false" if omitted; a bundle is considered "transparent" if it does 669# not package the "bundle_data" deps but forward them to all targets 670# the depend on it (unless the "bundle_data" target sets "product_type" 671# to "com.apple.product-type.framework"). 672# 673# This template provides two targets for the resulting framework bundle. The 674# link-time behavior varies depending on which of the two targets below is 675# added as a dependency: 676# - $target_name only adds a build-time dependency. Targets that depend on 677# it will not link against the framework. 678# - $target_name+link adds a build-time and link-time dependency. Targets 679# that depend on it will link against the framework. 680# 681# The build-time-only dependency is used for when a target needs to use the 682# framework either only for resources, or because the target loads it at run- 683# time, via dlopen() or NSBundle. The link-time dependency will cause the 684# dependee to have the framework loaded by dyld at launch. 685# 686# Example of build-time only dependency: 687# 688# framework_bundle("CoreTeleportation") { 689# sources = [ ... ] 690# } 691# 692# bundle_data("core_teleportation_bundle_data") { 693# deps = [ ":CoreTeleportation" ] 694# sources = [ "$root_out_dir/CoreTeleportation.framework" ] 695# outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] 696# } 697# 698# app_bundle("GoatTeleporter") { 699# sources = [ ... ] 700# deps = [ 701# ":core_teleportation_bundle_data", 702# ] 703# } 704# 705# The GoatTeleporter.app will not directly link against 706# CoreTeleportation.framework, but it will be included in the bundle's 707# Frameworks directory. 708# 709# Example of link-time dependency: 710# 711# framework_bundle("CoreTeleportation") { 712# sources = [ ... ] 713# ldflags = [ 714# "-install_name", 715# "@executable_path/../Frameworks/$target_name.framework" 716# ] 717# } 718# 719# bundle_data("core_teleportation_bundle_data") { 720# deps = [ ":CoreTeleportation+link" ] 721# sources = [ "$root_out_dir/CoreTeleportation.framework" ] 722# outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] 723# } 724# 725# app_bundle("GoatTeleporter") { 726# sources = [ ... ] 727# deps = [ 728# ":core_teleportation_bundle_data", 729# ] 730# } 731# 732# Note that the framework is still copied to the app's bundle, but dyld will 733# load this library when the app is launched because it uses the "+link" 734# target as a dependency. This also requires that the framework set its 735# install_name so that dyld can locate it. 736# 737# See "gn help shared_library" for more information on arguments supported 738# by shared library target. 739template("ios_framework_bundle") { 740 _target_name = target_name 741 _output_name = target_name 742 if (defined(invoker.output_name)) { 743 _output_name = invoker.output_name 744 } 745 746 _product_type = "com.apple.product-type.framework" 747 _has_public_headers = 748 defined(invoker.public_headers) && invoker.public_headers != [] 749 750 _shared_library_target = _target_name + "_shared_library" 751 _link_target_name = _target_name + "+link" 752 753 if (_has_public_headers) { 754 _default_toolchain_target_gen_dir = 755 get_label_info("$_target_name", "target_gen_dir") 756 757 _framework_headers_target = _target_name + "_framework_headers" 758 759 _headers_map_config = _target_name + "_headers_map" 760 _header_map_filename = 761 "$_default_toolchain_target_gen_dir/$_output_name.headers.hmap" 762 config(_headers_map_config) { 763 visibility = [ 764 ":${_shared_library_target}", 765 ":${_target_name}_signed_bundle", 766 ] 767 include_dirs = [ _header_map_filename ] 768 } 769 } 770 771 _framework_headers_config = _target_name + "_framework_headers_config" 772 config(_framework_headers_config) { 773 framework_dirs = [ root_out_dir ] 774 } 775 776 _framework_public_config = _target_name + "_public_config" 777 config(_framework_public_config) { 778 configs = [ ":$_framework_headers_config" ] 779 frameworks = [ "$_output_name.framework" ] 780 } 781 782 shared_library(_shared_library_target) { 783 forward_variables_from(invoker, 784 "*", 785 [ 786 "bundle_deps", 787 "bundle_deps_filter", 788 "data_deps", 789 "enable_code_signing", 790 "extra_substitutions", 791 "info_plist", 792 "info_plist_target", 793 "output_name", 794 "public_configs", 795 "transparent", 796 "visibility", 797 ]) 798 799 visibility = [ ":${_target_name}_signed_bundle" ] 800 801 if (!defined(ldflags)) { 802 ldflags = [] 803 } 804 ldflags += 805 [ "-Wl,-install_name,@rpath/$_output_name.framework/$_output_name" ] 806 807 if (_has_public_headers) { 808 configs += [ ":$_headers_map_config" ] 809 810 if (!defined(deps)) { 811 deps = [] 812 } 813 deps += [ ":$_framework_headers_target" ] 814 } 815 816 output_extension = "" 817 output_name = _output_name 818 output_prefix_override = true 819 output_dir = target_out_dir 820 } 821 822 if (_has_public_headers) { 823 _public_headers = invoker.public_headers 824 825 _framework_root_dir = "$root_out_dir/$_output_name.framework" 826 if (target_environment == "simulator" || target_environment == "device") { 827 _framework_contents_dir = _framework_root_dir 828 } else if (target_environment == "catalyst") { 829 _framework_contents_dir = "$_framework_root_dir/Versions/A" 830 } 831 832 _compile_headers_map_target = _target_name + "_compile_headers_map" 833 action(_compile_headers_map_target) { 834 visibility = [ ":$_framework_headers_target" ] 835 forward_variables_from(invoker, 836 [ 837 "deps", 838 "public_deps", 839 "testonly", 840 ]) 841 script = "//build/config/apple/write_framework_hmap.py" 842 outputs = [ _header_map_filename ] 843 844 # The header map generation only wants the list of headers, not all of 845 # sources, so filter any non-header source files from "sources". It is 846 # less error prone that having the developer duplicate the list of all 847 # headers in addition to "sources". 848 sources = [] 849 if (defined(invoker.sources)) { 850 foreach(_source, invoker.sources) { 851 if (get_path_info(_source, "extension") == "h") { 852 sources += [ _source ] 853 } 854 } 855 } 856 857 args = [ 858 rebase_path(_header_map_filename, root_build_dir), 859 rebase_path(_framework_root_dir, root_build_dir), 860 ] + rebase_path(sources, root_build_dir) 861 } 862 863 _create_module_map_target = _target_name + "_module_map" 864 action(_create_module_map_target) { 865 visibility = [ ":$_framework_headers_target" ] 866 script = "//build/config/apple/write_framework_modulemap.py" 867 outputs = [ "$_framework_contents_dir/Modules/module.modulemap" ] 868 args = [ 869 _output_name, 870 rebase_path("$_framework_contents_dir/Modules", root_build_dir), 871 ] 872 } 873 874 _copy_public_headers_target = _target_name + "_copy_public_headers" 875 copy(_copy_public_headers_target) { 876 forward_variables_from(invoker, 877 [ 878 "testonly", 879 "deps", 880 ]) 881 visibility = [ ":$_framework_headers_target" ] 882 sources = _public_headers 883 outputs = [ "$_framework_contents_dir/Headers/{{source_file_part}}" ] 884 885 # Do not use forward_variables_from for "public_deps" as 886 # we do not want to forward those dependencies. 887 if (defined(invoker.public_deps)) { 888 if (!defined(deps)) { 889 deps = [] 890 } 891 deps += invoker.public_deps 892 } 893 } 894 895 group(_framework_headers_target) { 896 forward_variables_from(invoker, [ "testonly" ]) 897 deps = [ 898 ":$_compile_headers_map_target", 899 ":$_create_module_map_target", 900 ] 901 public_deps = [ ":$_copy_public_headers_target" ] 902 } 903 } 904 905 # Bundle identifier should respect rfc1034, so replace "_" with "-". 906 _bundle_identifier = 907 "$ios_app_bundle_id_prefix." + string_replace(_output_name, "_", "-") 908 909 _info_plist_target = _target_name + "_info_plist" 910 _info_plist_bundle = _target_name + "_info_plist_bundle" 911 ios_info_plist(_info_plist_target) { 912 visibility = [ ":$_info_plist_bundle" ] 913 executable_name = _output_name 914 forward_variables_from(invoker, 915 [ 916 "info_plist", 917 "info_plist_target", 918 ]) 919 920 extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ] 921 if (defined(invoker.extra_substitutions)) { 922 extra_substitutions += invoker.extra_substitutions 923 } 924 } 925 926 bundle_data(_info_plist_bundle) { 927 visibility = [ ":${_target_name}_signed_bundle" ] 928 forward_variables_from(invoker, [ "testonly" ]) 929 sources = get_target_outputs(":$_info_plist_target") 930 public_deps = [ ":$_info_plist_target" ] 931 product_type = _product_type 932 933 if (target_environment != "catalyst") { 934 outputs = [ "{{bundle_contents_dir}}/Info.plist" ] 935 } else { 936 outputs = [ "{{bundle_resources_dir}}/Info.plist" ] 937 } 938 } 939 940 ios_create_signed_bundle(_target_name + "_signed_bundle") { 941 forward_variables_from(invoker, 942 [ 943 "bundle_deps", 944 "bundle_deps_filter", 945 "data_deps", 946 "deps", 947 "enable_code_signing", 948 "public_configs", 949 "public_deps", 950 "testonly", 951 "transparent", 952 "visibility", 953 ]) 954 955 product_type = _product_type 956 bundle_extension = ".framework" 957 958 output_name = _output_name 959 bundle_binary_target = ":$_shared_library_target" 960 bundle_binary_output = _output_name 961 962 has_public_headers = _has_public_headers 963 964 # Framework do not have entitlements nor mobileprovision because they use 965 # the one from the bundle using them (.app or .appex) as they are just 966 # dynamic library with shared code. 967 disable_entitlements = true 968 disable_embedded_mobileprovision = true 969 970 if (!defined(deps)) { 971 deps = [] 972 } 973 deps += [ ":$_info_plist_bundle" ] 974 } 975 976 group(_target_name) { 977 forward_variables_from(invoker, 978 [ 979 "public_configs", 980 "public_deps", 981 "testonly", 982 "visibility", 983 ]) 984 if (!defined(public_deps)) { 985 public_deps = [] 986 } 987 public_deps += [ ":${_target_name}_signed_bundle" ] 988 989 if (_has_public_headers) { 990 if (!defined(public_configs)) { 991 public_configs = [] 992 } 993 public_configs += [ ":$_framework_headers_config" ] 994 } 995 } 996 997 group(_link_target_name) { 998 forward_variables_from(invoker, 999 [ 1000 "public_configs", 1001 "public_deps", 1002 "testonly", 1003 "visibility", 1004 ]) 1005 if (!defined(public_deps)) { 1006 public_deps = [] 1007 } 1008 public_deps += [ ":$_target_name" ] 1009 1010 if (!defined(all_dependent_configs)) { 1011 all_dependent_configs = [] 1012 } 1013 all_dependent_configs += [ ":$_framework_public_config" ] 1014 } 1015 1016 bundle_data(_target_name + "+bundle") { 1017 forward_variables_from(invoker, 1018 [ 1019 "testonly", 1020 "visibility", 1021 ]) 1022 public_deps = [ ":$_target_name" ] 1023 sources = [ "$root_out_dir/$_output_name.framework" ] 1024 outputs = [ "{{bundle_contents_dir}}/Frameworks/$_output_name.framework" ] 1025 } 1026} 1027 1028set_defaults("ios_framework_bundle") { 1029 configs = default_shared_library_configs 1030} 1031 1032# Template to build a xctest bundle that contains a loadable module for iOS. 1033# 1034# Arguments 1035# 1036# deps: 1037# list of labels to depends on, these values are used to create the 1038# loadable module. 1039# 1040# product_type 1041# string, product type for the generated Xcode project, use 1042# "com.apple.product-type.bundle.unit-test" for unit test and 1043# "com.apple.product-type.bundle.ui-testing" for UI testing. 1044# 1045# host_target: 1046# string, name of the target that depends on the generated bundle, this 1047# value is used to restrict visibilities. 1048# 1049# xcode_test_application_name: 1050# string, name of the test application for Xcode unit or ui test target. 1051# 1052# output_name 1053# (optional) string, name of the generated application, if omitted, 1054# defaults to the target_name. 1055# 1056# This template defines two targets, one named "${target_name}" is the xctest 1057# bundle, and the other named "${target_name}_bundle" is a bundle_data that 1058# wraps the xctest bundle and that only the "${host_target}" can depend on. 1059# 1060template("ios_xctest_bundle") { 1061 assert(defined(invoker.deps), "deps must be defined for $target_name") 1062 assert(defined(invoker.product_type), 1063 "product_type must be defined for $target_name") 1064 assert(invoker.product_type == apple_mobile_xcode_xctest_bundle_id || 1065 invoker.product_type == apple_mobile_xcode_xcuitest_bundle_id, 1066 "product_type defined for $target_name is invalid.") 1067 assert(defined(invoker.host_target), 1068 "host_target must be defined for $target_name") 1069 assert(defined(invoker.xcode_test_application_name), 1070 "xcode_test_application_name must be defined for $target_name") 1071 1072 _target_name = target_name 1073 _output_name = target_name 1074 1075 if (defined(invoker.output_name)) { 1076 _output_name = invoker.output_name 1077 } 1078 1079 _loadable_module_target = _target_name + "_loadable_module" 1080 1081 loadable_module(_loadable_module_target) { 1082 forward_variables_from(invoker, 1083 "*", 1084 [ 1085 "bundle_deps", 1086 "bundle_deps_filter", 1087 "host_target", 1088 "output_dir", 1089 "output_extension", 1090 "output_name", 1091 "output_prefix_override", 1092 "product_type", 1093 "testonly", 1094 "visibility", 1095 "xcode_test_application_name", 1096 "xcode_test_application_output_name", 1097 "xctest_bundle_principal_class", 1098 ]) 1099 1100 testonly = true 1101 visibility = [ ":$_target_name" ] 1102 1103 configs += [ "//build/config/ios:xctest_config" ] 1104 1105 output_dir = target_out_dir 1106 output_name = _output_name 1107 output_prefix_override = true 1108 output_extension = "" 1109 } 1110 1111 _info_plist_target = _target_name + "_info_plist" 1112 _info_plist_bundle = _target_name + "_info_plist_bundle" 1113 1114 # Bundle identifier should respect rfc1034, so replace "_" with "-". 1115 _bundle_identifier = "$ios_app_bundle_id_prefix.chrome." + 1116 string_replace(_output_name, "_", "-") 1117 1118 ios_info_plist(_info_plist_target) { 1119 testonly = true 1120 visibility = [ ":$_info_plist_bundle" ] 1121 1122 info_plist = "//build/config/ios/Module-Info.plist" 1123 executable_name = _output_name 1124 1125 if (defined(invoker.xctest_bundle_principal_class)) { 1126 _principal_class = invoker.xctest_bundle_principal_class 1127 } else { 1128 # Fall back to a reasonable default value. 1129 _principal_class = "NSObject" 1130 } 1131 extra_substitutions = [ 1132 "XCTEST_BUNDLE_PRINCIPAL_CLASS=${_principal_class}", 1133 "BUNDLE_IDENTIFIER=$_bundle_identifier", 1134 ] 1135 } 1136 1137 bundle_data(_info_plist_bundle) { 1138 testonly = true 1139 visibility = [ ":$_target_name" ] 1140 1141 public_deps = [ ":$_info_plist_target" ] 1142 1143 sources = get_target_outputs(":$_info_plist_target") 1144 outputs = [ "{{bundle_contents_dir}}/Info.plist" ] 1145 } 1146 1147 _xctest_bundle = _target_name + "_bundle" 1148 ios_create_signed_bundle(_target_name) { 1149 forward_variables_from(invoker, 1150 [ 1151 "bundle_deps", 1152 "bundle_deps_filter", 1153 "bundle_id", 1154 "data_deps", 1155 "enable_code_signing", 1156 "product_type", 1157 "transparent", 1158 "xcode_test_application_name", 1159 ]) 1160 1161 testonly = true 1162 visibility = [ ":$_xctest_bundle" ] 1163 1164 bundle_extension = ".xctest" 1165 1166 output_name = _output_name 1167 bundle_binary_target = ":$_loadable_module_target" 1168 bundle_binary_output = _output_name 1169 1170 xcode_extra_attributes = { 1171 IPHONEOS_DEPLOYMENT_TARGET = ios_deployment_target 1172 PRODUCT_BUNDLE_IDENTIFIER = _bundle_identifier 1173 CODE_SIGNING_REQUIRED = "NO" 1174 CODE_SIGNING_ALLOWED = "NO" 1175 CODE_SIGN_IDENTITY = "" 1176 DONT_GENERATE_INFOPLIST_FILE = "YES" 1177 1178 # For XCUITest, Xcode requires specifying the host application name 1179 # via the TEST_TARGET_NAME attribute. 1180 if (invoker.product_type == apple_mobile_xcode_xcuitest_bundle_id) { 1181 TEST_TARGET_NAME = invoker.xcode_test_application_name 1182 } 1183 1184 # For XCTest, Xcode requires specifying the host application path via 1185 # both BUNDLE_LOADER and TEST_HOST attributes. 1186 if (invoker.product_type == apple_mobile_xcode_xctest_bundle_id) { 1187 _xcode_app_name = invoker.xcode_test_application_name 1188 if (defined(invoker.xcode_test_application_output_name)) { 1189 _xcode_app_name = invoker.xcode_test_application_output_name 1190 } 1191 1192 BUNDLE_LOADER = "\$(TEST_HOST)" 1193 TEST_HOST = "\$(BUILT_PRODUCTS_DIR)/" + 1194 "${_xcode_app_name}.app/${_xcode_app_name}" 1195 } 1196 } 1197 1198 deps = [ ":$_info_plist_bundle" ] 1199 } 1200 1201 bundle_data(_xctest_bundle) { 1202 forward_variables_from(invoker, [ "host_target" ]) 1203 1204 testonly = true 1205 visibility = [ ":$host_target" ] 1206 1207 public_deps = [ ":$_target_name" ] 1208 sources = [ "$root_out_dir/$_output_name.xctest" ] 1209 outputs = [ "{{bundle_contents_dir}}/PlugIns/$_output_name.xctest" ] 1210 } 1211} 1212 1213set_defaults("ios_xctest_bundle") { 1214 configs = default_shared_library_configs 1215} 1216 1217# For Chrome on iOS we want to run XCTests for all our build configurations 1218# (Debug, Release, ...). In addition, the symbols visibility is configured to 1219# private by default. To simplify testing with those constraints, our tests are 1220# compiled in the TEST_HOST target instead of the .xctest bundle. 1221template("ios_xctest_test") { 1222 _target_name = target_name 1223 _output_name = target_name 1224 if (defined(invoker.output_name)) { 1225 _output_name = invoker.output_name 1226 } 1227 1228 _xctest_target = _target_name + "_module" 1229 _xctest_output = _output_name + "_module" 1230 1231 _host_target = _target_name 1232 _host_output = _output_name 1233 1234 # Allow invokers to specify their own target for the xctest module, but 1235 # fall back to a default (empty) module otherwise. 1236 if (defined(invoker.xctest_module_target)) { 1237 _xctest_module_target = invoker.xctest_module_target 1238 } else { 1239 _xctest_module_target_name = _xctest_target + "shell_source" 1240 _xctest_module_target = ":$_xctest_module_target_name" 1241 source_set(_xctest_module_target_name) { 1242 sources = [ "//build/config/ios/xctest_shell.mm" ] 1243 1244 configs += [ "//build/config/ios:xctest_config" ] 1245 } 1246 } 1247 1248 ios_xctest_bundle(_xctest_target) { 1249 forward_variables_from(invoker, [ "data_deps" ]) 1250 output_name = _xctest_output 1251 product_type = apple_mobile_xcode_xctest_bundle_id 1252 host_target = _host_target 1253 1254 # TODO(crbug.com/40120290) The change in output name results in a mismatch 1255 # between this value and the ios_app_bundle target name. To mitigate, this 1256 # has been modified to _host_target. output_name is set to _host_output 1257 # to mitigate the naming. 1258 xcode_test_application_name = _host_target 1259 xcode_test_application_output_name = _host_output 1260 1261 deps = [ _xctest_module_target ] 1262 } 1263 1264 ios_app_bundle(_host_target) { 1265 forward_variables_from(invoker, "*", [ "testonly" ]) 1266 1267 testonly = true 1268 output_name = _host_output 1269 configs += [ "//build/config/ios:xctest_config" ] 1270 1271 if (!defined(invoker.info_plist) && !defined(invoker.info_plist_target)) { 1272 info_plist = "//build/config/ios/Host-Info.plist" 1273 } 1274 1275 # Xcode needs the following frameworks installed in the application (and 1276 # signed) for the XCTest to run, so install them using 1277 # extra_system_frameworks. 1278 extra_system_frameworks = [ 1279 "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework", 1280 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework", 1281 "$ios_sdk_platform_path/Developer/usr/lib/libXCTestBundleInject.dylib", 1282 ] 1283 1284 # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over 1285 # everything that Xcode copies. 1286 if (xcode_version_int >= 1300) { 1287 extra_system_frameworks += [ 1288 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework", 1289 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework", 1290 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework", 1291 "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib", 1292 ] 1293 } 1294 1295 # XCTestSupport framework is required as of Xcode 14.3 or later. 1296 if (xcode_version_int >= 1430) { 1297 extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ] 1298 } 1299 1300 _xctest_bundle = _xctest_target + "_bundle" 1301 if (!defined(bundle_deps)) { 1302 bundle_deps = [] 1303 } 1304 bundle_deps += [ ":$_xctest_bundle" ] 1305 } 1306} 1307 1308set_defaults("ios_xctest_test") { 1309 configs = default_executable_configs 1310} 1311 1312# Template to build a xcuitest test runner bundle. 1313# 1314# Xcode requires a test runner application with a copy of the XCTest dynamic 1315# library bundle in it for the XCUITest to run. The test runner bundle is created 1316# by copying the system bundle XCTRunner.app from Xcode SDK with the plist file 1317# being properly tweaked, and a xctest and it needs to be code signed in order 1318# to run on devices. 1319# 1320# Arguments 1321# 1322# xctest_bundle 1323# string, name of the dependent xctest bundle target. 1324# 1325# output_name 1326# (optional) string, name of the generated application, if omitted, 1327# defaults to the target_name. 1328# 1329template("ios_xcuitest_test_runner_bundle") { 1330 assert(defined(invoker.xctest_bundle), 1331 "xctest_bundle must be defined for $target_name") 1332 1333 _target_name = target_name 1334 _output_name = target_name 1335 if (defined(invoker.output_name)) { 1336 _output_name = invoker.output_name 1337 } 1338 1339 # Bundle identifier should respect rfc1034, so replace "_" with "-". 1340 _bundle_identifier = "$ios_app_bundle_id_prefix.chrome." + 1341 string_replace(_output_name, "_", "-") 1342 1343 _xctrunner_path = 1344 "$ios_sdk_platform_path/Developer/Library/Xcode/Agents/XCTRunner.app" 1345 1346 _info_plist_merge_plist = _target_name + "_info_plist_merge_plist" 1347 _info_plist_target = _target_name + "_info_plist" 1348 _info_plist_bundle = _target_name + "_info_plist_bundle" 1349 1350 action(_info_plist_merge_plist) { 1351 testonly = true 1352 script = "//build/apple/plist_util.py" 1353 1354 sources = [ 1355 "$_xctrunner_path/Info.plist", 1356 1357 # NOTE: The XCTRunnerAddition+Info.plist must come after the Info.plist 1358 # because it overrides the values under "CFBundleIdentifier" and 1359 # "CFBundleName". 1360 "//build/config/ios/resources/XCTRunnerAddition+Info.plist", 1361 ] 1362 1363 _output_name = "$target_gen_dir/${_target_name}_merged.plist" 1364 outputs = [ _output_name ] 1365 args = [ 1366 "merge", 1367 "-f=xml1", 1368 "-x=$xcode_version", 1369 "-o=" + rebase_path(_output_name, root_build_dir), 1370 ] + rebase_path(sources, root_build_dir) 1371 1372 if (ios_use_xcode_symlinks) { 1373 deps = [ "//build/config/ios:copy_xctrunner_app" ] 1374 } 1375 } 1376 1377 ios_info_plist(_info_plist_target) { 1378 testonly = true 1379 visibility = [ ":$_info_plist_bundle" ] 1380 1381 executable_name = _output_name 1382 info_plist_target = ":$_info_plist_merge_plist" 1383 extra_substitutions = [ "BUNDLE_IDENTIFIER=$_bundle_identifier" ] 1384 } 1385 1386 bundle_data(_info_plist_bundle) { 1387 testonly = true 1388 visibility = [ ":$_target_name" ] 1389 1390 public_deps = [ ":$_info_plist_target" ] 1391 1392 sources = get_target_outputs(":$_info_plist_target") 1393 outputs = [ "{{bundle_contents_dir}}/Info.plist" ] 1394 } 1395 1396 _pkginfo_bundle = _target_name + "_pkginfo_bundle" 1397 bundle_data(_pkginfo_bundle) { 1398 testonly = true 1399 visibility = [ ":$_target_name" ] 1400 1401 sources = [ "$_xctrunner_path/PkgInfo" ] 1402 1403 outputs = [ "{{bundle_contents_dir}}/PkgInfo" ] 1404 1405 if (ios_use_xcode_symlinks) { 1406 public_deps = [ "//build/config/ios:copy_xctrunner_app" ] 1407 } 1408 } 1409 1410 _xctest_bundle = invoker.xctest_bundle 1411 ios_create_signed_bundle(_target_name) { 1412 testonly = true 1413 1414 bundle_binary_target = "//build/config/ios:xctest_runner_without_arm64e" 1415 bundle_binary_output = "XCTRunner" 1416 bundle_extension = ".app" 1417 product_type = apple_mobile_xcode_app_bundle_id 1418 1419 output_name = _output_name 1420 1421 # Xcode needs the following frameworks installed in the application 1422 # (and signed) for the XCUITest to run, so install them using 1423 # extra_system_frameworks. 1424 extra_system_frameworks = [ 1425 "$ios_sdk_platform_path/Developer/Library/Frameworks/XCTest.framework", 1426 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTAutomationSupport.framework", 1427 ] 1428 1429 # Xcode 13 now depends on XCTestCore. To keep things future proof, copy over 1430 # everything that Xcode copies. 1431 if (xcode_version_int >= 1300) { 1432 extra_system_frameworks += [ 1433 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestCore.framework", 1434 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUIAutomation.framework", 1435 "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCUnit.framework", 1436 "$ios_sdk_platform_path/Developer/usr/lib/libXCTestSwiftSupport.dylib", 1437 ] 1438 } 1439 1440 # XCTestSupport framework is required as of Xcode 14.3 or later. 1441 if (xcode_version_int >= 1430) { 1442 extra_system_frameworks += [ "$ios_sdk_platform_path/Developer/Library/PrivateFrameworks/XCTestSupport.framework" ] 1443 } 1444 1445 bundle_deps = [] 1446 if (defined(invoker.bundle_deps)) { 1447 bundle_deps += invoker.bundle_deps 1448 } 1449 bundle_deps += [ 1450 ":$_info_plist_bundle", 1451 ":$_pkginfo_bundle", 1452 ":$_xctest_bundle", 1453 ] 1454 } 1455} 1456 1457# Template to build a XCUITest that consists of two parts: the test runner 1458# application bundle and the xctest dynamic library. 1459# 1460# Arguments 1461# 1462# deps: 1463# list of labels to depends on, these values are used to create the 1464# xctest dynamic library. 1465# 1466# xcode_test_application_name: 1467# string, name of the test application for the ui test target. 1468# 1469# runner_only_bundle_deps: 1470# list of labels of bundle target to include in the runner and 1471# exclude from the test module (the use case is a framework bundle 1472# that is used by the test module and thus needs to be packaged in 1473# the runner application bundle) 1474# 1475# This template defines two targets, one named "${target_name}_module" is the 1476# xctest dynamic library, and the other named "${target_name}_runner" is the 1477# test runner application bundle. 1478# 1479template("ios_xcuitest_test") { 1480 assert(defined(invoker.deps), "deps must be defined for $target_name") 1481 assert(defined(invoker.xcode_test_application_name), 1482 "xcode_test_application_name must be defined for $target_name") 1483 1484 _xcuitest_target = target_name 1485 if (defined(invoker.output_name)) { 1486 _xcuitest_target = invoker.output_name 1487 } 1488 1489 _xcuitest_runner_target = _xcuitest_target + "_runner" 1490 _xcuitest_module_target = _xcuitest_target + "_module" 1491 1492 group(target_name) { 1493 testonly = true 1494 1495 deps = [ ":$_xcuitest_runner_target" ] 1496 } 1497 1498 _xcuitest_module_output = _xcuitest_target 1499 ios_xctest_bundle(_xcuitest_module_target) { 1500 forward_variables_from(invoker, 1501 [ 1502 "bundle_deps", 1503 "data_deps", 1504 "deps", 1505 "xcode_test_application_name", 1506 "xctest_bundle_principal_class", 1507 ]) 1508 1509 product_type = apple_mobile_xcode_xcuitest_bundle_id 1510 host_target = _xcuitest_runner_target 1511 output_name = _xcuitest_module_output 1512 1513 if (defined(invoker.runner_only_bundle_deps)) { 1514 bundle_deps_filter = invoker.runner_only_bundle_deps 1515 } 1516 } 1517 1518 _xcuitest_runner_output = _xcuitest_target + "-Runner" 1519 ios_xcuitest_test_runner_bundle(_xcuitest_runner_target) { 1520 output_name = _xcuitest_runner_output 1521 xctest_bundle = _xcuitest_module_target + "_bundle" 1522 1523 if (defined(invoker.runner_only_bundle_deps)) { 1524 if (!defined(bundle_deps)) { 1525 bundle_deps = [] 1526 } 1527 bundle_deps += invoker.runner_only_bundle_deps 1528 } 1529 } 1530} 1531 1532set_defaults("ios_xcuitest_test") { 1533 configs = default_executable_configs 1534} 1535