• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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