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