xref: /aosp_15_r20/external/angle/build/config/apple/create_signed_bundle.gni (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
1# Copyright 2024 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/config/apple/mobile_config.gni")
6import("//build_overrides/build.gni")
7
8# Constants corresponding to the bundle type identifiers use application,
9# application extension, XCTest and XCUITest targets respectively.
10apple_mobile_xcode_app_bundle_id = "com.apple.product-type.application"
11apple_mobile_xcode_appex_bundle_id = "com.apple.product-type.app-extension"
12apple_mobile_xcode_xctest_bundle_id = "com.apple.product-type.bundle.unit-test"
13apple_mobile_xcode_xcuitest_bundle_id =
14    "com.apple.product-type.bundle.ui-testing"
15
16# Wrapper around create_bundle taking care of code signature settings.
17#
18# Arguments
19#
20#   product_type
21#       string, product type for the generated Xcode project.
22#
23#   platform_sdk_name
24#       string, the name of the platform SDK
25#
26#   bundle_gen_dir
27#       (optional) directory where the bundle is generated; must be below
28#       root_out_dir and defaults to root_out_dir if omitted.
29#
30#   bundle_deps
31#       (optional) list of additional dependencies.
32#
33#   bundle_deps_filter
34#       (optional) list of dependencies to filter (for more information
35#       see "gn help bundle_deps_filter").
36#
37#   bundle_extension
38#       string, extension of the bundle, used to generate bundle name.
39#
40#   bundle_binary_target
41#       (optional) string, label of the target generating the bundle main
42#       binary. This target and bundle_binary_path are mutually exclusive.
43#
44#   bundle_binary_output
45#       (optional) string, base name of the binary generated by the
46#       bundle_binary_target target, defaults to the target name.
47#
48#   bundle_binary_path
49#       (optional) string, path to the bundle main binary. This target and
50#       bundle_binary_target are mutually exclusive.
51#
52#   output_name:
53#       (optional) string, name of the generated application, if omitted,
54#       defaults to the target_name.
55#
56#   extra_system_frameworks
57#       (optional) list of system framework to copy to the bundle.
58#
59#   enable_code_signing
60#       (optional) boolean, control whether code signing is enabled or not,
61#       default to ios_enable_code_signing if not defined.
62#
63#   entitlements_path:
64#       (optional) path to the template to use to generate the application
65#       entitlements by performing variable substitutions, defaults to
66#       //build/config/ios/entitlements.plist.
67#
68#   entitlements_target:
69#       (optional) label of the target generating the application
70#       entitlements (must generate a single file as output); cannot be
71#       defined if entitlements_path is set.
72#
73#   has_public_headers:
74#       (optional) boolean, defaults to false; only meaningful if the bundle
75#       is a framework bundle; if true, then the frameworks includes public
76#       headers
77#
78#   disable_entitlements
79#       (optional, defaults to false) boolean, control whether entitlements willi
80#       be embedded in the application during signature. If false and no
81#       entitlements are provided, default empty entitlements will be used.
82#
83#   disable_embedded_mobileprovision
84#       (optional, default to false) boolean, control whether mobile provisions
85#       will be embedded in the bundle. If true, the existing
86#       embedded.mobileprovision will be deleted.
87#
88#   xcode_extra_attributes
89#       (optional) scope, extra attributes for Xcode projects.
90#
91#   xcode_test_application_name:
92#       (optional) string, name of the test application for Xcode unit or ui
93#       test target.
94#
95#   xcode_product_bundle_id:
96#       (optional) string, the bundle ID that will be added in the XCode
97#       attributes to enable some features when debugging (e.g. MetricKit).
98#
99#   primary_info_plist:
100#       (optional) path to Info.plist to merge with the $partial_info_plist
101#       generated by the compilation of the asset catalog.
102#
103#   partial_info_plist:
104#       (optional) path to the partial Info.plist generated by the asset
105#       catalog compiler; if defined $primary_info_plist must also be defined.
106#
107#   transparent
108#       (optional) boolean, whether the bundle is "transparent"; defaults to
109#       "false" if omitted; a bundle is considered "transparent" if it does
110#       not package the "bundle_data" deps but forward them to all targets
111#       the depend on it (unless the "bundle_data" target sets "product_type"
112#       to the same value as the "create_signed_bundle" target).
113#
114template("apple_mobile_create_signed_bundle") {
115  assert(defined(invoker.product_type),
116         "product_type must be defined for $target_name")
117  assert(defined(invoker.platform_sdk_name),
118         "platform_sdk_name must be defined for $target_name")
119  assert(defined(invoker.bundle_extension),
120         "bundle_extension must be defined for $target_name")
121  assert(defined(invoker.bundle_binary_target) !=
122             defined(invoker.bundle_binary_path),
123         "Only one of bundle_binary_target or bundle_binary_path may be " +
124             "specified for $target_name")
125  assert(!defined(invoker.partial_info_plist) ||
126             defined(invoker.primary_info_plist),
127         "primary_info_plist must be defined when partial_info_plist is " +
128             "defined for $target_name")
129
130  if (defined(invoker.xcode_test_application_name)) {
131    assert(
132        invoker.product_type == apple_mobile_xcode_xctest_bundle_id ||
133            invoker.product_type == apple_mobile_xcode_xcuitest_bundle_id,
134        "xcode_test_application_name can be only defined for Xcode unit or ui test target.")
135  }
136
137  _target_name = target_name
138  _output_name = target_name
139  if (defined(invoker.output_name)) {
140    _output_name = invoker.output_name
141  }
142
143  if (defined(invoker.bundle_binary_path)) {
144    _bundle_binary_path = invoker.bundle_binary_path
145  } else {
146    _bundle_binary_target = invoker.bundle_binary_target
147    _bundle_binary_output = get_label_info(_bundle_binary_target, "name")
148    if (defined(invoker.bundle_binary_output)) {
149      _bundle_binary_output = invoker.bundle_binary_output
150    }
151    _bundle_binary_path =
152        get_label_info(_bundle_binary_target, "target_out_dir") +
153        "/$_bundle_binary_output"
154  }
155
156  _bundle_gen_dir = root_out_dir
157  if (defined(invoker.bundle_gen_dir)) {
158    _bundle_gen_dir = invoker.bundle_gen_dir
159  }
160
161  _bundle_extension = invoker.bundle_extension
162
163  _enable_embedded_mobileprovision = true
164  if (defined(invoker.disable_embedded_mobileprovision)) {
165    _enable_embedded_mobileprovision = !invoker.disable_embedded_mobileprovision
166  }
167
168  if (target_environment == "catalyst") {
169    _enable_embedded_mobileprovision = false
170  }
171
172  _enable_entitlements = true
173  if (defined(invoker.disable_entitlements)) {
174    _enable_entitlements = !invoker.disable_entitlements
175  }
176
177  if (_enable_entitlements) {
178    if (!defined(invoker.entitlements_target)) {
179      _entitlements_path = "//build/config/ios/entitlements.plist"
180      if (defined(invoker.entitlements_path)) {
181        _entitlements_path = invoker.entitlements_path
182      }
183    } else {
184      assert(!defined(invoker.entitlements_path),
185             "Cannot define both entitlements_path and entitlements_target " +
186                 "for $target_name")
187
188      _entitlements_target_outputs =
189          get_target_outputs(invoker.entitlements_target)
190      _entitlements_path = _entitlements_target_outputs[0]
191    }
192  }
193
194  _enable_code_signing = ios_enable_code_signing
195  if (defined(invoker.enable_code_signing)) {
196    _enable_code_signing = invoker.enable_code_signing
197  }
198
199  create_bundle(_target_name) {
200    forward_variables_from(invoker,
201                           [
202                             "bundle_deps_filter",
203                             "data_deps",
204                             "deps",
205                             "partial_info_plist",
206                             "product_type",
207                             "public_configs",
208                             "public_deps",
209                             "testonly",
210                             "transparent",
211                             "visibility",
212                             "xcode_test_application_name",
213                           ])
214
215    bundle_root_dir = "$_bundle_gen_dir/$_output_name$_bundle_extension"
216    if (target_environment == "simulator" || target_environment == "device") {
217      bundle_contents_dir = bundle_root_dir
218      bundle_resources_dir = bundle_contents_dir
219      bundle_executable_dir = bundle_contents_dir
220    } else if (target_environment == "catalyst") {
221      if (_bundle_extension != ".framework") {
222        bundle_contents_dir = "$bundle_root_dir/Contents"
223        bundle_resources_dir = "$bundle_contents_dir/Resources"
224        bundle_executable_dir = "$bundle_contents_dir/MacOS"
225      } else {
226        bundle_contents_dir = "$bundle_root_dir/Versions/A"
227        bundle_resources_dir = "$bundle_contents_dir/Resources"
228        bundle_executable_dir = bundle_contents_dir
229      }
230    }
231
232    if (!defined(public_deps)) {
233      public_deps = []
234    }
235
236    _bundle_identifier = ""
237    if (defined(invoker.xcode_product_bundle_id)) {
238      _bundle_identifier = invoker.xcode_product_bundle_id
239      assert(_bundle_identifier == string_replace(_bundle_identifier, "_", "-"),
240             "$target_name: bundle_identifier does not respect rfc1034: " +
241                 _bundle_identifier)
242    }
243
244    xcode_extra_attributes = {
245      PRODUCT_BUNDLE_IDENTIFIER = _bundle_identifier
246      CODE_SIGNING_REQUIRED = "NO"
247      CODE_SIGNING_ALLOWED = "NO"
248      CODE_SIGN_IDENTITY = ""
249      DONT_GENERATE_INFOPLIST_FILE = "YES"
250
251      # If invoker has defined extra attributes, they override the defaults.
252      if (defined(invoker.xcode_extra_attributes)) {
253        forward_variables_from(invoker.xcode_extra_attributes, "*")
254      }
255    }
256
257    if (defined(invoker.bundle_binary_target)) {
258      public_deps += [ invoker.bundle_binary_target ]
259    }
260
261    if (defined(invoker.bundle_deps)) {
262      if (!defined(deps)) {
263        deps = []
264      }
265      deps += invoker.bundle_deps
266    }
267    if (!defined(deps)) {
268      deps = []
269    }
270
271    post_processing_script = "//build/config/apple/codesign.py"
272    post_processing_sources = [ _bundle_binary_path ]
273    if (_enable_entitlements) {
274      if (defined(invoker.entitlements_target)) {
275        deps += [ invoker.entitlements_target ]
276      }
277      post_processing_sources += [ _entitlements_path ]
278    }
279    post_processing_outputs = [ "$bundle_executable_dir/$_output_name" ]
280    if (_enable_code_signing) {
281      post_processing_outputs +=
282          [ "$bundle_contents_dir/_CodeSignature/CodeResources" ]
283    }
284    if (ios_code_signing_identity != "" && target_environment == "device" &&
285        _enable_embedded_mobileprovision) {
286      post_processing_outputs +=
287          [ "$bundle_contents_dir/embedded.mobileprovision" ]
288    }
289    if (_bundle_extension == ".framework") {
290      if (target_environment == "catalyst") {
291        post_processing_outputs += [
292          "$bundle_root_dir/Versions/Current",
293          "$bundle_root_dir/$_output_name",
294        ]
295
296        if (defined(invoker.has_public_headers) && invoker.has_public_headers) {
297          post_processing_outputs += [
298            "$bundle_root_dir/Headers",
299            "$bundle_root_dir/Modules",
300          ]
301        }
302      } else {
303        not_needed(invoker, [ "has_public_headers" ])
304      }
305    }
306
307    if (defined(invoker.extra_system_frameworks)) {
308      foreach(_framework, invoker.extra_system_frameworks) {
309        post_processing_outputs += [ "$bundle_contents_dir/Frameworks/" +
310                                     get_path_info(_framework, "file") ]
311      }
312    }
313
314    post_processing_args = [
315      "code-sign-bundle",
316      "-t=" + invoker.platform_sdk_name,
317      "-i=" + ios_code_signing_identity,
318      "-b=" + rebase_path(_bundle_binary_path, root_build_dir),
319    ]
320    foreach(mobileprovision, ios_mobileprovision_files) {
321      post_processing_args +=
322          [ "-m=" + rebase_path(mobileprovision, root_build_dir) ]
323    }
324    post_processing_sources += ios_mobileprovision_files
325    if (_enable_entitlements) {
326      post_processing_args +=
327          [ "-e=" + rebase_path(_entitlements_path, root_build_dir) ]
328    }
329    if (!_enable_embedded_mobileprovision) {
330      post_processing_args += [ "--disable-embedded-mobileprovision" ]
331    }
332    post_processing_args += [ rebase_path(bundle_root_dir, root_build_dir) ]
333    if (!_enable_code_signing) {
334      post_processing_args += [ "--disable-code-signature" ]
335    }
336    if (defined(invoker.extra_system_frameworks)) {
337      # All framework in extra_system_frameworks are expected to be system
338      # framework and the path to be already system absolute so do not use
339      # rebase_path here unless using RBE and system Xcode (as in that
340      # case the system framework are found via a symlink in root_build_dir).
341      foreach(_framework, invoker.extra_system_frameworks) {
342        if (use_system_xcode && use_remoteexec) {
343          _framework_path = rebase_path(_framework, root_build_dir)
344        } else {
345          _framework_path = _framework
346        }
347        post_processing_args += [ "-F=$_framework_path" ]
348      }
349    }
350    if (defined(invoker.partial_info_plist)) {
351      _partial_info_plists = [
352        invoker.primary_info_plist,
353        invoker.partial_info_plist,
354      ]
355
356      _plist_compiler_path = "//build/apple/plist_util.py"
357
358      post_processing_sources += _partial_info_plists
359      post_processing_sources += [ _plist_compiler_path ]
360      if (target_environment != "catalyst" ||
361          _bundle_extension != ".framework") {
362        post_processing_outputs += [ "$bundle_contents_dir/Info.plist" ]
363      } else {
364        post_processing_outputs += [ "$bundle_resources_dir/Info.plist" ]
365      }
366
367      post_processing_args +=
368          [ "-P=" + rebase_path(_plist_compiler_path, root_build_dir) ]
369      foreach(_partial_info_plist, _partial_info_plists) {
370        post_processing_args +=
371            [ "-p=" + rebase_path(_partial_info_plist, root_build_dir) ]
372      }
373    }
374  }
375}
376