1 # Copyright 2014 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.
5 # Instantiate grit. This will produce a script target to run grit (named
6 # ${target_name}_grit), and a static library that compiles the .cc files.
8 # In general, code should depend on the static library. However, if the
9 # generated files are only processed by other actions to generate other
10 # files, it is possible to depend on the script target directly.
17 # enable_input_discovery_for_gn_analyze (default=true)
18 # Runs grit_info.py via exec_script() when compute_inputs_for_analyze=true
19 # in order to discover all files that affect this target.
20 # Turn this off when the .grd file is generated, or an <include> with
21 # flattenhtml=true points to a generated file.
22 # For "gn analyze" to be correct with this arg disabled, all inputs
23 # must be listed via |inputs|.
26 # List of additional files, required for grit to process source file.
29 # List of outputs from grit, relative to the target_gen_dir. Grit will
30 # verify at build time that this list is correct and will fail if there
31 # is a mismatch between the outputs specified by the .grd file and the
34 # To get this list, you can look in the .grd file for
35 # <output filename="..." and put those filename here. The base directory
36 # of the list in Grit and the output list specified in the GN grit target
37 # are the same (the target_gen_dir) so you can generally copy the names
40 # To get the list of outputs programatically, run:
41 # python tools/grit/grit_info.py --outputs . path/to/your.grd
42 # And strip the leading "./" from the output files.
45 # Extra defines to pass to grit (on top of the global defines in the
48 # grit_flags (optional)
49 # List of strings containing extra command-line flags to pass to Grit.
51 # resource_ids (optional)
52 # Path to a grit "firstidsfile". Default is
53 # //tools/gritsettings/resource_ids. Set to "" to use the value specified
54 # in the <grit> nodes of the processed files.
56 # output_dir (optional)
57 # Directory for generated files. If you specify this, you will often
58 # want to specify output_name if the target name is not particularly
59 # unique, since this can cause files from multiple grit targets to
60 # overwrite each other.
62 # output_name (optional)
63 # Provide an alternate base name for the generated files, like the .d
64 # files. Normally these are based on the target name and go in the
65 # output_dir, but if multiple targets with the same name end up in
66 # the same output_dir, they can collide.
69 # List of additional configs to be applied to the generated target.
73 # visibility (optional)
79 # grit("my_resources") {
80 # # Source and outputs are required.
81 # source = "myfile.grd"
87 # grit_flags = [ "-E", "foo=bar" ] # Optional extra flags.
88 # # You can also put deps here if the grit source depends on generated
91 import("//build/config/compiler/compiler.gni")
92 import("//build/config/compute_inputs_for_analyze.gni")
93 import("//build/config/sanitizers/sanitizers.gni")
94 import("//build/toolchain/gcc_toolchain.gni")
95 import("//tools/grit/grit_args.gni")
96 _strip_resource_files = is_android && is_official_build
97 _js_minifier = "//tools/grit/minify_js.py"
98 _css_minifier = "//tools/grit/minimize_css.py"
101 grit_resource_id_target = "//tools/gritsettings:default_resource_ids"
102 grit_resource_id_file =
103 get_label_info(grit_resource_id_target, "target_gen_dir") +
104 "/default_resource_ids"
105 grit_info_script = "//tools/grit/grit_info.py"
107 # TODO(asvitkine): Add predetermined ids files for other platforms.
108 grit_predetermined_resource_ids_file = ""
110 grit_predetermined_resource_ids_file =
111 "//tools/gritsettings/startup_resources_mac.txt"
114 grit_predetermined_resource_ids_file =
115 "//tools/gritsettings/startup_resources_win.txt"
126 if (defined(invoker.output_dir)) {
127 _output_dir = invoker.output_dir
129 _output_dir = target_gen_dir
133 get_path_info(rebase_path(invoker.outputs, ".", _output_dir), "abspath")
135 # Add .info output for all pak files
136 _pak_info_outputs = []
137 foreach(output, _grit_outputs) {
138 if (get_path_info(output, "extension") == "pak") {
139 _pak_info_outputs += [ output + ".info" ]
143 if (defined(invoker.output_name)) {
144 _grit_output_name = invoker.output_name
146 _grit_output_name = target_name
149 _grit_custom_target = target_name + "_grit"
150 action(_grit_custom_target) {
151 script = "//tools/grit/grit.py"
152 inputs = [ invoker.source ]
154 testonly = defined(invoker.testonly) && invoker.testonly
156 depfile = "$target_gen_dir/$target_name.d"
158 deps = [ "//tools/grit:grit_sources" ]
159 outputs = [ "${depfile}.stamp" ] + _grit_outputs + _pak_info_outputs
161 _grit_flags = grit_args
163 # Add extra defines with -D flags.
164 if (defined(invoker.defines)) {
165 foreach(i, invoker.defines) {
173 if (defined(invoker.grit_flags)) {
174 _grit_flags += invoker.grit_flags
177 _rebased_source_path = rebase_path(invoker.source, root_build_dir)
179 !defined(invoker.enable_input_discovery_for_gn_analyze) ||
180 invoker.enable_input_discovery_for_gn_analyze
181 if (_enable_grit_info && compute_inputs_for_analyze) {
182 # Only call exec_script when the user has explicitly opted into greater
183 # precision at the expense of performance.
184 _rel_inputs = exec_script("//tools/grit/grit_info.py",
187 _rebased_source_path,
190 inputs += rebase_path(_rel_inputs, ".", root_build_dir)
195 _rebased_source_path,
198 rebase_path(_output_dir, root_build_dir),
202 rebase_path(depfile, root_build_dir),
203 "--write-only-new=1",
205 ] + _grit_flags + grit_defines
207 # Add brotli executable if using brotli.
208 if (defined(invoker.use_brotli) && invoker.use_brotli) {
209 _brotli_target = "//third_party/brotli:brotli($host_toolchain)"
210 _brotli_executable = get_label_info(_brotli_target, "root_out_dir") +
211 "/" + get_label_info(_brotli_target, "name")
212 if (host_os == "win") {
213 _brotli_executable += ".exe"
216 inputs += [ _brotli_executable ]
219 rebase_path(_brotli_executable, root_build_dir),
223 _resource_ids = grit_resource_id_file
224 if (defined(invoker.resource_ids)) {
225 _resource_ids = invoker.resource_ids
228 if (_resource_ids != "") {
229 inputs += [ _resource_ids ]
232 rebase_path(_resource_ids, root_build_dir),
234 if (_resource_ids == grit_resource_id_file) {
235 deps += [ grit_resource_id_target ]
238 if (grit_predetermined_resource_ids_file != "") {
239 inputs += [ grit_predetermined_resource_ids_file ]
242 rebase_path(grit_predetermined_resource_ids_file, root_build_dir),
246 # We want to make sure the declared outputs actually match what Grit is
247 # writing. We write the list to a file (some of the output lists are long
248 # enough to not fit on a Windows command line) and ask Grit to verify those
249 # are the actual outputs at runtime.
250 _asserted_list_file =
251 "$target_out_dir/${_grit_output_name}_expected_outputs.txt"
252 write_file(_asserted_list_file,
253 rebase_path(invoker.outputs, root_build_dir, _output_dir))
254 inputs += [ _asserted_list_file ]
256 "--assert-file-list",
257 rebase_path(_asserted_list_file, root_build_dir),
260 if (enable_resource_allowlist_generation) {
261 _rc_grit_outputs = []
262 foreach(output, _grit_outputs) {
263 if (get_path_info(output, "extension") == "rc") {
264 _rc_grit_outputs += [ output ]
268 if (_rc_grit_outputs != []) {
269 # Resource allowlisting cannot be used with .rc files.
270 # Make sure that there aren't any .pak outputs which would require
271 # allowlist annotations.
272 assert(_pak_info_outputs == [], "can't combine .pak and .rc outputs")
274 args += [ "--allowlist-support" ]
277 if (_strip_resource_files) {
278 _js_minifier_command = rebase_path(_js_minifier, root_build_dir)
279 _css_minifier_command = rebase_path(_css_minifier, root_build_dir)
282 _js_minifier_command,
284 _css_minifier_command,
292 if (defined(invoker.visibility)) {
293 # This needs to include both what the invoker specified (since they
294 # probably include generated headers from this target), as well as the
295 # generated source set (since there's no guarantee that the visibility
296 # specified by the invoker includes our target).
298 # Only define visibility at all if the invoker specified it. Otherwise,
299 # we want to keep the public "no visibility specified" default.
300 visibility = [ ":${invoker.target_name}" ] + invoker.visibility
303 if (defined(invoker.use_brotli) && invoker.use_brotli) {
304 if (is_mac && is_asan) {
305 deps += [ "//tools/grit:brotli_mac_asan_workaround" ]
307 deps += [ "//third_party/brotli:brotli($host_toolchain)" ]
310 if (defined(invoker.deps)) {
313 if (defined(invoker.inputs)) {
314 inputs += invoker.inputs
318 # This is the thing that people actually link with, it must be named the
319 # same as the argument the template was invoked with.
320 source_set(target_name) {
321 testonly = defined(invoker.testonly) && invoker.testonly
323 # Since we generate a file, we need to be run before the targets that
326 foreach(_output, _grit_outputs) {
327 _extension = get_path_info(_output, "extension")
328 if (_extension != "json" && _extension != "gz" && _extension != "pak" &&
329 _extension != "xml") {
330 sources += [ _output ]
334 # Deps set on the template invocation will go on the action that runs
335 # grit above rather than this library. This target needs to depend on the
336 # action publicly so other scripts can take the outputs from the grit
338 public_deps = [ ":$_grit_custom_target" ]
340 if (defined(invoker.public_configs)) {
341 public_configs += invoker.public_configs
344 configs += [ "//build/config/compiler:wexit_time_destructors" ]
345 if (defined(invoker.configs)) {
346 configs += invoker.configs
349 if (defined(invoker.visibility)) {
350 visibility = invoker.visibility
352 output_name = _grit_output_name
357 import("//build/config/android/rules.gni")
359 # Declare a target that generates localized strings.xml from a .grd file.
361 # If this target is included in the deps of an android resources/library/apk,
362 # the strings.xml will be included with that target.
365 # deps: Specifies the dependencies of this target.
366 # grd_file: Path to the .grd file to generate strings.xml from.
367 # outputs: Expected grit outputs (see grit rule).
370 # java_strings_grd("foo_strings_grd") {
371 # grd_file = "foo_strings.grd"
373 template("java_strings_grd") {
374 forward_variables_from(invoker, [ "testonly" ])
376 _resources_zip = "$target_out_dir/$target_name.resources.zip"
377 _grit_target_name = "${target_name}__grit"
378 _grit_output_dir = "$target_gen_dir/${target_name}_grit_output"
380 grit(_grit_target_name) {
381 forward_variables_from(invoker,
388 "ANDROID_JAVA_TAGGED_ONLY=false",
390 output_dir = _grit_output_dir
392 source = invoker.grd_file
393 outputs = invoker.outputs
396 _zip_target_name = "${target_name}__zip"
398 zip(_zip_target_name) {
399 base_dir = _grit_output_dir
401 # No need to depend on the source_set().
402 _grit_dep = ":${_grit_target_name}_grit"
404 inputs = filter_exclude(get_target_outputs(_grit_dep), [ "*.stamp" ])
405 output = _resources_zip
408 android_generated_resources(target_name) {
409 forward_variables_from(invoker,
414 generating_target = ":$_zip_target_name"
415 generated_resources_zip = _resources_zip
419 # Declare a target that packages strings.xml generated from a grd file.
421 # If this target is included in the deps of an android resources/library/apk,
422 # the strings.xml will be included with that target.
425 # grit_output_dir: directory containing grit-generated files.
426 # generated_files: list of android resource files to package.
429 # java_strings_grd_prebuilt("foo_strings_grd") {
430 # grit_output_dir = "$root_gen_dir/foo/grit"
431 # generated_files = [
432 # "values/strings.xml"
435 template("java_strings_grd_prebuilt") {
436 forward_variables_from(invoker, [ "testonly" ])
438 _resources_zip = "$target_out_dir/$target_name.resources.zip"
439 _zip_target_name = "${target_name}__zip"
441 zip(_zip_target_name) {
442 base_dir = invoker.grit_output_dir
443 inputs = rebase_path(invoker.generated_files, ".", base_dir)
444 output = _resources_zip
445 if (defined(invoker.deps)) {
447 foreach(_dep, invoker.deps) {
448 deps += [ "${_dep}_grit" ]
453 android_generated_resources(target_name) {
454 forward_variables_from(invoker,
459 generating_target = ":$_zip_target_name"
460 generated_resources_zip = _resources_zip