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