1# Copyright 2018 The Chromium Authors. All rights reserved.
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/sysroot.gni")
6
7# Creates a Fuchsia .far package file containing a Fuchsia component.
8#
9# Parameters are:
10# package_name_override: Specifies the name of the package to generate,
11#     if different than |target_name|.
12# archive_filename_override: Specifies the filename of the generated FAR.
13#     If left unset, defaults to |package_name_override|.
14#     Defaults to the target name.
15# binary: The executable target which should be launched.
16# manifest: A path to the manifest that will be used.
17#     "testonly" targets default to using
18#     //build/config/fuchsia/tests-with-exec.cmx.
19#     Non-test targets must explicitly specify a |manifest|.
20# additional_manifests: Manifest files that should be included in the package in
21#     the /meta directory. This allows to package more than one component per
22#     manifest. These manifest files must specify program/binary to run, which
23#     is not required for the main manifest file where this parameter is added
24#     during build.
25# component_name_override: If set, specifies the name of the component.
26#     By default, the component name is the same as the package name.
27# deps: Additional targets to build and include in the package (optional).
28#
29# TODO(https://crbug.com/1050703): Migrate consumers to GN SDK equivalents.
30template("cr_fuchsia_package") {
31  pkg = {
32    forward_variables_from(invoker, "*")
33
34    if (defined(package_name_override)) {
35      package_name = package_name_override
36    } else {
37      package_name = invoker.target_name
38    }
39
40    if (defined(archive_name_override)) {
41      archive_filename = archive_name_override
42    } else {
43      archive_filename = package_name
44    }
45
46    if (!defined(manifest)) {
47      assert(testonly == true)
48
49      # TODO(1019938): switch the default to tests.cmx which doesn't request
50      # the deprecated-ambient-replace-as-executable feature.
51      manifest = "//build/config/fuchsia/tests-with-exec.cmx"
52    }
53  }
54  assert(defined(pkg.binary))
55
56  _pm_tool_path = "//third_party/fuchsia-sdk/sdk/tools/pm"
57
58  _pkg_out_dir = "${target_gen_dir}/${pkg.archive_filename}"
59  _runtime_deps_file = "$_pkg_out_dir/${pkg.archive_filename}.runtime_deps"
60  _archive_manifest = "$_pkg_out_dir/${pkg.archive_filename}.archive_manifest"
61  _build_ids_file = "$_pkg_out_dir/ids.txt"
62  _meta_far_file = "$_pkg_out_dir/meta.far"
63  _combined_far_file = "$_pkg_out_dir/${pkg.package_name}-0.far"
64  _final_far_file = "$_pkg_out_dir/${pkg.archive_filename}.far"
65  _package_info_path = "$_pkg_out_dir/package"
66
67  if (defined(pkg.component_name_override)) {
68    _generated_cmx = "$_pkg_out_dir/${pkg.component_name_override}.cmx"
69  } else {
70    _generated_cmx = "$_pkg_out_dir/${pkg.package_name}.cmx"
71  }
72
73  _write_manifest_target = "${pkg.package_name}__write_manifest"
74  _package_target = "${pkg.package_name}__pkg"
75  _bundle_target = "${pkg.package_name}__bundle"
76
77  # Generates a manifest file based on the GN runtime deps
78  # suitable for "pm" tool consumption.
79  action(_write_manifest_target) {
80    _depfile = "${target_gen_dir}/${target_name}_stamp.d"
81
82    forward_variables_from(invoker,
83                           [
84                             "data",
85                             "deps",
86                             "testonly",
87                           ])
88
89    script = "//build/config/fuchsia/prepare_package_inputs.py"
90
91    inputs = [
92      _runtime_deps_file,
93      pkg.manifest,
94    ]
95
96    outputs = [
97      _archive_manifest,
98      _build_ids_file,
99      _generated_cmx,
100    ]
101
102    if (!defined(deps)) {
103      deps = []
104    }
105    deps += [ pkg.binary ]
106    data_deps = deps
107
108    # Use a depfile to trigger package rebuilds if any of the files (static
109    # assets, shared libraries, etc.) included by the package have changed.
110    depfile = _depfile
111
112    args = [
113      "--root-dir",
114      rebase_path("//", root_build_dir),
115      "--out-dir",
116      rebase_path(root_out_dir, root_build_dir),
117      "--app-name",
118      pkg.package_name,
119      "--app-filename",
120      get_label_info(pkg.binary, "name"),
121      "--manifest-input-path",
122      rebase_path(pkg.manifest, root_build_dir),
123      "--runtime-deps-file",
124      rebase_path(_runtime_deps_file, root_build_dir),
125      "--depfile-path",
126      rebase_path(_depfile, root_build_dir),
127      "--package-manifest-path",
128      rebase_path(_archive_manifest, root_build_dir),
129      "--component-manifest-path",
130      rebase_path(_generated_cmx, root_build_dir),
131      "--build-ids-file",
132      rebase_path(_build_ids_file, root_build_dir),
133    ]
134
135    if (defined(pkg.excluded_files)) {
136      foreach(filename, pkg.excluded_files) {
137        args += [
138          "--exclude-file",
139          filename,
140        ]
141      }
142    }
143
144    if (defined(pkg.additional_manifests)) {
145      foreach(filename, pkg.additional_manifests) {
146        args += [
147          "--additional-manifest",
148          rebase_path(filename),
149        ]
150      }
151    }
152
153    write_runtime_deps = _runtime_deps_file
154  }
155
156  # Creates a signed Fuchsia metadata package.
157  action(_package_target) {
158    forward_variables_from(invoker, [ "testonly" ])
159
160    script = "//build/gn_run_binary.py"
161
162    deps = [ ":$_write_manifest_target" ]
163
164    inputs = [
165      # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
166      "//third_party/fuchsia-sdk/sdk/.hash",
167    ]
168
169    if (defined(pkg.additional_manifests)) {
170      inputs += pkg.additional_manifests
171    }
172
173    outputs = [ _meta_far_file ]
174
175    args = [
176      rebase_path(_pm_tool_path, root_build_dir),
177      "-o",
178      rebase_path(_pkg_out_dir, root_build_dir),
179      "-m",
180      rebase_path(_archive_manifest, root_build_dir),
181      "build",
182    ]
183  }
184
185  # Creates a package containing the metadata archive and blob data.
186  action(_bundle_target) {
187    forward_variables_from(invoker, [ "testonly" ])
188
189    script = "//build/gn_run_binary.py"
190
191    deps = [
192      ":$_package_target",
193      ":$_write_manifest_target",
194    ]
195
196    inputs = [
197      # Depend on the SDK hash, to ensure rebuild if the SDK tools change.
198      "//third_party/fuchsia-sdk/sdk/.hash",
199      _meta_far_file,
200      _archive_manifest,
201    ]
202
203    outputs = [ _combined_far_file ]
204
205    args = [
206      rebase_path(_pm_tool_path, root_build_dir),
207      "-o",
208      rebase_path(_pkg_out_dir, root_build_dir),
209      "-m",
210      rebase_path(_archive_manifest, root_build_dir),
211      "archive",
212    ]
213  }
214
215  # Copies the archive to a well-known path.
216  # TODO(kmarshall): Use a 'pm' output flag to write directly to the desired
217  # file path instead.
218  copy(target_name) {
219    forward_variables_from(invoker, [ "testonly" ])
220
221    # Allows dependent targets to make use of "ids.txt".
222    public_deps = [ ":$_write_manifest_target" ]
223
224    deps = [ ":$_bundle_target" ]
225
226    data = [
227      _final_far_file,
228
229      # Files specified here so that they can be read by isolated testbots.
230      _package_info_path,
231      _build_ids_file,
232    ]
233
234    sources = [ _combined_far_file ]
235    outputs = [ _final_far_file ]
236  }
237}
238