xref: /aosp_15_r20/external/cronet/build/config/mac/rules.gni (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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