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