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