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