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/mac/mac_sdk.gni") 8 9# Generates Info.plist files for Mac apps and frameworks. 10# 11# Arguments 12# 13# info_plist: 14# (optional) string, path to the Info.plist file that will be used for 15# the bundle. 16# 17# info_plist_target: 18# (optional) string, if the info_plist is generated from an action, 19# rather than a regular source file, specify the target name in lieu 20# of info_plist. The two arguments are mutually exclusive. 21# 22# executable_name: 23# string, name of the generated target used for the product 24# and executable name as specified in the output Info.plist. 25# 26# extra_substitutions: 27# (optional) string array, 'key=value' pairs for extra fields which are 28# specified in a source Info.plist template. 29template("mac_info_plist") { 30 assert(defined(invoker.info_plist) != defined(invoker.info_plist_target), 31 "Only one of info_plist or info_plist_target may be specified in " + 32 target_name) 33 34 if (defined(invoker.info_plist)) { 35 _info_plist = invoker.info_plist 36 } else { 37 _info_plist_target_output = get_target_outputs(invoker.info_plist_target) 38 _info_plist = _info_plist_target_output[0] 39 } 40 41 apple_info_plist(target_name) { 42 format = "xml1" 43 extra_substitutions = [ 44 "MAC_SDK_BUILD=$mac_sdk_build_version", 45 "MAC_SDK_NAME=$mac_sdk_name$mac_sdk_version", 46 "MACOSX_DEPLOYMENT_TARGET=$mac_deployment_target", 47 "CHROMIUM_MIN_SYSTEM_VERSION=$mac_min_system_version", 48 "XCODE_BUILD=$xcode_build", 49 "XCODE_VERSION=$xcode_version", 50 ] 51 if (defined(invoker.extra_substitutions)) { 52 extra_substitutions += invoker.extra_substitutions 53 } 54 plist_templates = [ 55 "//build/config/mac/BuildInfo.plist", 56 _info_plist, 57 ] 58 if (defined(invoker.info_plist_target)) { 59 deps = [ invoker.info_plist_target ] 60 } 61 forward_variables_from(invoker, 62 [ 63 "testonly", 64 "executable_name", 65 ]) 66 } 67} 68 69# Template to package a shared library into a Mac framework bundle. 70# 71# By default, the bundle target this template generates does not link the 72# resulting framework into anything that depends on it. If a dependency wants 73# a link-time (as well as build-time) dependency on the framework bundle, 74# depend against "$target_name+link". If only the build-time dependency is 75# required (e.g., for copying into another bundle), then use "$target_name". 76# 77# Arguments 78# 79# framework_version: 80# string, version of the framework. Typically this is a 81# single letter, like "A". 82# 83# framework_contents: 84# list of string, top-level items in the framework. This is 85# the list of symlinks to create in the .framework directory that link 86# into Versions/Current/. 87# 88# info_plist: 89# (optional) string, path to the Info.plist file that will be used for 90# the bundle. 91# 92# info_plist_target: 93# (optional) string, if the info_plist is generated from an action, 94# rather than a regular source file, specify the target name in lieu 95# of info_plist. The two arguments are mutually exclusive. 96# 97# output_name: 98# (optional) string, name of the generated framework without the 99# .framework suffix. If omitted, defaults to target_name. 100# 101# extra_substitutions: 102# (optional) string array, 'key=value' pairs for extra fields which are 103# specified in a source Info.plist template. 104# 105# This template provides three targets for the resulting framework bundle. The 106# link-time behavior varies depending on which of the two targets below is 107# added as a dependency: 108# - $target_name only adds a build-time dependency. Targets that depend on 109# it will not link against the framework. 110# - $target_name+link adds a build-time and link-time dependency. Targets 111# that depend on it will link against the framework. 112# - $target_name+link_nested adds a build-time and link-time dependency, but 113# only on the shared library and not the fully-assembled framework bundle. 114# This should only be used for other nested binary components of the 115# framework bundle (e.g. Helpers) that themselves depend on the main shared 116# library of the framework bundle. 117# 118# The build-time-only dependency is used for when a target needs to use the 119# framework either only for resources, or because the target loads it at run- 120# time, via dlopen() or NSBundle. The link-time dependency will cause the 121# dependee to have the framework loaded by dyld at launch. 122# 123# Example of build-time only dependency: 124# 125# mac_framework_bundle("CoreTeleportation") { 126# sources = [ ... ] 127# } 128# 129# bundle_data("core_teleportation_bundle_data") { 130# deps = [ ":CoreTeleportation" ] 131# sources = [ "$root_out_dir/CoreTeleportation.framework" ] 132# outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] 133# } 134# 135# app_bundle("GoatTeleporter") { 136# sources = [ ... ] 137# deps = [ 138# ":core_teleportation_bundle_data", 139# ] 140# } 141# 142# The GoatTeleporter.app will not directly link against 143# CoreTeleportation.framework, but it will be included in the bundle's 144# Frameworks directory. 145# 146# Example of link-time dependency: 147# 148# mac_framework_bundle("CoreTeleportation") { 149# sources = [ ... ] 150# ldflags = [ 151# "-install_name", 152# "@executable_path/../Frameworks/$target_name.framework" 153# ] 154# } 155# 156# bundle_data("core_teleportation_bundle_data") { 157# deps = [ ":CoreTeleportation+link" ] 158# sources = [ "$root_out_dir/CoreTeleportation.framework" ] 159# outputs = [ "{{bundle_contents_dir}}/Frameworks/{{source_file_part}}" ] 160# } 161# 162# app_bundle("GoatTeleporter") { 163# sources = [ ... ] 164# deps = [ 165# ":core_teleportation_bundle_data", 166# ] 167# } 168# 169# Note that the framework is still copied to the app's bundle, but dyld will 170# load this library when the app is launched because it uses the "+link" 171# target as a dependency. This also requires that the framework set its 172# install_name so that dyld can locate it. 173# 174# See "gn help shared_library" for more information on arguments supported 175# by shared library target. 176template("mac_framework_bundle") { 177 assert(defined(invoker.deps) || defined(invoker.public_deps), 178 "Dependencies must be specified for $target_name") 179 assert(invoker.framework_version != "", "framework_version is required") 180 assert(defined(invoker.framework_contents), "framework_contents is required") 181 182 _info_plist_target = target_name + "_info_plist" 183 184 mac_info_plist(_info_plist_target) { 185 executable_name = target_name 186 if (defined(invoker.output_name)) { 187 executable_name = invoker.output_name 188 } 189 forward_variables_from(invoker, 190 [ 191 "extra_substitutions", 192 "info_plist", 193 "info_plist_target", 194 "testonly", 195 ]) 196 } 197 198 _info_plist_bundle_data = _info_plist_target + "_bundle_data" 199 200 bundle_data(_info_plist_bundle_data) { 201 forward_variables_from(invoker, [ "testonly" ]) 202 sources = get_target_outputs(":$_info_plist_target") 203 outputs = [ "{{bundle_resources_dir}}/Info.plist" ] 204 public_deps = [ ":$_info_plist_target" ] 205 } 206 207 _target_name = target_name 208 _output_name = target_name 209 if (defined(invoker.output_name)) { 210 _output_name = invoker.output_name 211 } 212 213 # Create a file to track the build dependency on the framework_version and 214 # framework_contents variables. 215 _framework_toc = [ 216 "Version=" + invoker.framework_version, 217 _output_name, 218 ] + invoker.framework_contents 219 _framework_contents = [ _output_name ] + invoker.framework_contents 220 _framework_toc_file = "$target_out_dir/${target_name}.toc" 221 write_file(_framework_toc_file, _framework_toc) 222 223 # Create local variables for referencing different parts of the bundle. 224 _framework_target = _target_name 225 _framework_name = _output_name + ".framework" 226 _framework_base_dir = "$root_out_dir/$_framework_name" 227 _framework_root_dir = 228 _framework_base_dir + "/Versions/${invoker.framework_version}" 229 230 # Clean the entire framework if the framework_version changes. 231 _version_file = "$target_out_dir/${target_name}_version" 232 exec_script("//build/config/mac/prepare_framework_version.py", 233 [ 234 rebase_path(_version_file), 235 rebase_path(_framework_base_dir), 236 invoker.framework_version, 237 ]) 238 239 # Create the symlinks. 240 _framework_package_target = target_name + "_package" 241 action(_framework_package_target) { 242 script = "//build/config/mac/package_framework.py" 243 244 # The TOC file never needs to be read, since its contents are the values 245 # of GN variables. It is only used to trigger this rule when the values 246 # change. 247 inputs = [ _framework_toc_file ] 248 249 _stamp_file = "$target_out_dir/run_${_framework_package_target}.stamp" 250 outputs = [ _stamp_file ] 251 252 visibility = [ ":$_framework_target" ] 253 254 args = [ 255 "--framework", 256 rebase_path(_framework_base_dir, root_build_dir), 257 "--stamp", 258 rebase_path(_stamp_file, root_build_dir), 259 "--version", 260 invoker.framework_version, 261 "--contents", 262 ] + _framework_contents 263 264 # It is not possible to list _framework_contents as outputs, since 265 # ninja does not properly stat symbolic links. 266 # https://github.com/ninja-build/ninja/issues/1186 267 } 268 269 _link_shared_library_target = target_name + "_shared_library" 270 _shared_library_bundle_data = target_name + "_shared_library_bundle_data" 271 272 shared_library(_link_shared_library_target) { 273 forward_variables_from(invoker, 274 "*", 275 [ 276 "assert_no_deps", 277 "bundle_deps", 278 "code_signing_enabled", 279 "data_deps", 280 "info_plist", 281 "info_plist_target", 282 "output_name", 283 "visibility", 284 ]) 285 visibility = [ 286 ":$_shared_library_bundle_data", 287 ":${_framework_target}+link_nested", 288 ] 289 output_name = _output_name 290 output_prefix_override = true 291 output_extension = "" 292 output_dir = "$target_out_dir/$_link_shared_library_target" 293 } 294 295 bundle_data(_shared_library_bundle_data) { 296 visibility = [ ":$_framework_target" ] 297 forward_variables_from(invoker, [ "testonly" ]) 298 sources = [ "$target_out_dir/$_link_shared_library_target/$_output_name" ] 299 outputs = [ "{{bundle_executable_dir}}/$_output_name" ] 300 public_deps = [ ":$_link_shared_library_target" ] 301 } 302 303 _framework_public_config = _target_name + "_public_config" 304 config(_framework_public_config) { 305 visibility = [ ":$_framework_target+link" ] 306 framework_dirs = [ root_out_dir ] 307 frameworks = [ _framework_name ] 308 } 309 310 create_bundle(_framework_target) { 311 forward_variables_from(invoker, 312 [ 313 "data_deps", 314 "deps", 315 "public_deps", 316 "testonly", 317 ]) 318 319 if (defined(invoker.visibility)) { 320 visibility = invoker.visibility 321 visibility += [ ":$_target_name+link" ] 322 } 323 324 if (!defined(deps)) { 325 deps = [] 326 } 327 deps += [ ":$_info_plist_bundle_data" ] 328 329 if (defined(invoker.bundle_deps)) { 330 deps += invoker.bundle_deps 331 } 332 333 if (!defined(public_deps)) { 334 public_deps = [] 335 } 336 public_deps += [ 337 ":$_framework_package_target", 338 ":$_shared_library_bundle_data", 339 ] 340 341 if (enable_dsyms) { 342 data = [ 343 "$root_out_dir/$_output_name.dSYM/Contents/Info.plist", 344 "$root_out_dir/$_output_name.dSYM/Contents/Resources/DWARF/$_output_name", 345 ] 346 } 347 348 bundle_root_dir = _framework_base_dir 349 bundle_contents_dir = _framework_root_dir 350 bundle_resources_dir = "$bundle_contents_dir/Resources" 351 bundle_executable_dir = bundle_contents_dir 352 } 353 354 group(_target_name + "+link") { 355 forward_variables_from(invoker, 356 [ 357 "public_configs", 358 "testonly", 359 "visibility", 360 ]) 361 public_deps = [ ":$_target_name" ] 362 if (!defined(public_configs)) { 363 public_configs = [] 364 } 365 public_configs += [ ":$_framework_public_config" ] 366 } 367 368 group(_target_name + "+link_nested") { 369 forward_variables_from(invoker, 370 [ 371 "public_configs", 372 "testonly", 373 "visibility", 374 ]) 375 376 # Depend only on the shared library. Nested code will be a dependency of 377 # the create_bundle target, which would be cyclic with depending on the 378 # framework itself. This is sufficient to link; for loading, a proper 379 # install_name should be set. 380 public_deps = [ ":$_link_shared_library_target" ] 381 } 382} 383 384set_defaults("mac_framework_bundle") { 385 configs = default_shared_library_configs 386} 387 388# Template to create a Mac executable application bundle. 389# 390# Arguments 391# 392# package_type: 393# (optional) string, the product package type to create. Options are: 394# "app" to create a .app bundle (default) 395# "xpc" to create an .xpc service bundle 396# 397# info_plist: 398# (optional) string, path to the Info.plist file that will be used for 399# the bundle. 400# 401# info_plist_target: 402# (optional) string, if the info_plist is generated from an action, 403# rather than a regular source file, specify the target name in lieu 404# of info_plist. The two arguments are mutually exclusive. 405# 406# output_name: 407# (optional) string, name of the generated app without the 408# .app suffix. If omitted, defaults to target_name. 409# 410# extra_substitutions: 411# (optional) string array, 'key=value' pairs for extra fields which are 412# specified in a source Info.plist template. 413template("mac_app_bundle") { 414 _target_name = target_name 415 _output_name = target_name 416 if (defined(invoker.output_name)) { 417 _output_name = invoker.output_name 418 } 419 420 _package_type = "app" 421 if (defined(invoker.package_type)) { 422 _package_type = invoker.package_type 423 } 424 425 if (_package_type == "app") { 426 _output_extension = "app" 427 _product_type = "com.apple.product-type.application" 428 _write_pkg_info = true 429 } else if (_package_type == "xpc") { 430 _output_extension = "xpc" 431 _product_type = "com.apple.product-type.xpc-service" 432 _write_pkg_info = false 433 } else if (_package_type == "bundle") { 434 _output_extension = "bundle" 435 _product_type = "com.apple.product-type.bundle" 436 _write_pkg_info = false 437 } else { 438 assert(false, "Unsupported packge_type: " + packge_type) 439 } 440 441 _executable_target = target_name + "_executable" 442 _executable_bundle_data = _executable_target + "_bundle_data" 443 444 _info_plist_target = target_name + "_info_plist" 445 446 mac_info_plist(_info_plist_target) { 447 executable_name = _output_name 448 forward_variables_from(invoker, 449 [ 450 "extra_substitutions", 451 "info_plist", 452 "info_plist_target", 453 "testonly", 454 ]) 455 } 456 457 if (_write_pkg_info) { 458 _pkg_info_target = target_name + "_pkg_info" 459 460 action(_pkg_info_target) { 461 forward_variables_from(invoker, [ "testonly" ]) 462 script = "//build/apple/write_pkg_info.py" 463 inputs = [ "//build/apple/plist_util.py" ] 464 sources = get_target_outputs(":$_info_plist_target") 465 outputs = [ "$target_gen_dir/$_pkg_info_target" ] 466 args = [ "--plist" ] + rebase_path(sources, root_build_dir) + 467 [ "--output" ] + rebase_path(outputs, root_build_dir) 468 deps = [ ":$_info_plist_target" ] 469 } 470 } 471 472 executable(_executable_target) { 473 visibility = [ ":$_executable_bundle_data" ] 474 forward_variables_from(invoker, 475 "*", 476 [ 477 "assert_no_deps", 478 "data_deps", 479 "info_plist", 480 "output_name", 481 "visibility", 482 ]) 483 output_name = _output_name 484 output_dir = "$target_out_dir/$_executable_target" 485 } 486 487 bundle_data(_executable_bundle_data) { 488 visibility = [ ":$_target_name" ] 489 forward_variables_from(invoker, [ "testonly" ]) 490 sources = [ "$target_out_dir/$_executable_target/$_output_name" ] 491 outputs = [ "{{bundle_executable_dir}}/$_output_name" ] 492 public_deps = [ ":$_executable_target" ] 493 } 494 495 _info_plist_bundle_data = _info_plist_target + "_bundle_data" 496 497 bundle_data(_info_plist_bundle_data) { 498 forward_variables_from(invoker, [ "testonly" ]) 499 visibility = [ ":$_target_name" ] 500 sources = get_target_outputs(":$_info_plist_target") 501 outputs = [ "{{bundle_contents_dir}}/Info.plist" ] 502 public_deps = [ ":$_info_plist_target" ] 503 } 504 505 if (_write_pkg_info) { 506 _pkg_info_bundle_data = _pkg_info_target + "_bundle_data" 507 508 bundle_data(_pkg_info_bundle_data) { 509 forward_variables_from(invoker, [ "testonly" ]) 510 visibility = [ ":$_target_name" ] 511 sources = get_target_outputs(":$_pkg_info_target") 512 outputs = [ "{{bundle_contents_dir}}/PkgInfo" ] 513 public_deps = [ ":$_pkg_info_target" ] 514 } 515 } 516 517 create_bundle(_target_name) { 518 forward_variables_from(invoker, 519 [ 520 "data_deps", 521 "deps", 522 "public_deps", 523 "testonly", 524 ]) 525 if (!defined(deps)) { 526 deps = [] 527 } 528 deps += [ 529 ":$_executable_bundle_data", 530 ":$_info_plist_bundle_data", 531 ] 532 if (_write_pkg_info) { 533 deps += [ ":$_pkg_info_bundle_data" ] 534 } 535 536 if (enable_dsyms) { 537 data = [ 538 "$root_out_dir/$_output_name.dSYM/Contents/Info.plist", 539 "$root_out_dir/$_output_name.dSYM/Contents/Resources/DWARF/$_output_name", 540 ] 541 } 542 543 product_type = _product_type 544 bundle_root_dir = "$root_out_dir/${_output_name}.${_output_extension}" 545 bundle_contents_dir = "$bundle_root_dir/Contents" 546 bundle_resources_dir = "$bundle_contents_dir/Resources" 547 bundle_executable_dir = "$bundle_contents_dir/MacOS" 548 } 549} 550 551set_defaults("mac_app_bundle") { 552 configs = default_executable_configs 553} 554 555# Template to package a loadable_module into a .plugin bundle. 556# 557# This takes no extra arguments that differ from a loadable_module. 558template("mac_plugin_bundle") { 559 assert(defined(invoker.deps), 560 "Dependencies must be specified for $target_name") 561 562 _target_name = target_name 563 _loadable_module_target = _target_name + "_loadable_module" 564 _loadable_module_bundle_data = _loadable_module_target + "_bundle_data" 565 566 _output_name = _target_name 567 if (defined(invoker.output_name)) { 568 _output_name = invoker.output_name 569 } 570 571 loadable_module(_loadable_module_target) { 572 visibility = [ ":$_loadable_module_bundle_data" ] 573 forward_variables_from(invoker, 574 "*", 575 [ 576 "assert_no_deps", 577 "data_deps", 578 "output_name", 579 "visibility", 580 ]) 581 output_dir = "$target_out_dir" 582 output_name = _output_name 583 } 584 585 bundle_data(_loadable_module_bundle_data) { 586 forward_variables_from(invoker, [ "testonly" ]) 587 visibility = [ ":$_target_name" ] 588 sources = [ "$target_out_dir/$_output_name.so" ] 589 outputs = [ "{{bundle_executable_dir}}/$_output_name" ] 590 public_deps = [ ":$_loadable_module_target" ] 591 } 592 593 create_bundle(_target_name) { 594 forward_variables_from(invoker, 595 [ 596 "data_deps", 597 "deps", 598 "public_deps", 599 "testonly", 600 "visibility", 601 ]) 602 if (!defined(deps)) { 603 deps = [] 604 } 605 deps += [ ":$_loadable_module_bundle_data" ] 606 607 if (enable_dsyms) { 608 data = [ 609 "$root_out_dir/$_output_name.so.dSYM/Contents/Info.plist", 610 "$root_out_dir/$_output_name.so.dSYM/Contents/Resources/DWARF/$_output_name.so", 611 ] 612 } 613 614 bundle_root_dir = "$root_out_dir/$_output_name.plugin" 615 bundle_contents_dir = "$bundle_root_dir/Contents" 616 bundle_executable_dir = "$bundle_contents_dir/MacOS" 617 } 618} 619