fixup! [M120 Migration] Languages pak optimization
[platform/framework/web/chromium-efl.git] / tools / grit / grit_rule.gni
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.
4
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.
7 #
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.
11 #
12 # Parameters
13 #
14 #   source (required)
15 #       Path to .grd file.
16 #
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|.
24 #
25 #   inputs  (optional)
26 #       List of additional files, required for grit to process source file.
27 #
28 #   outputs (required)
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
32 #       outputs list here.
33 #
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
38 #       exactly.
39 #
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.
43 #
44 #   defines (optional)
45 #       Extra defines to pass to grit (on top of the global defines in the
46 #       grit_args list).
47 #
48 #   grit_flags (optional)
49 #       List of strings containing extra command-line flags to pass to Grit.
50 #
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.
55 #
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.
61 #
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.
67 #
68 #   configs (optional)
69 #       List of additional configs to be applied to the generated target.
70 #
71 #   deps  (optional)
72 #   testonly (optional)
73 #   visibility  (optional)
74 #       Normal meaning.
75 #
76 #
77 # Example
78 #
79 #   grit("my_resources") {
80 #     # Source and outputs are required.
81 #     source = "myfile.grd"
82 #     outputs = [
83 #       "foo_strings.h",
84 #       "foo_strings.pak",
85 #     ]
86 #
87 #     grit_flags = [ "-E", "foo=bar" ]  # Optional extra flags.
88 #     # You can also put deps here if the grit source depends on generated
89 #     # files.
90 #   }
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"
99
100 grit_resource_id_target = "//tools/gritsettings:default_resource_ids"
101 grit_resource_id_file =
102     get_label_info(grit_resource_id_target, "target_gen_dir") +
103     "/default_resource_ids"
104 grit_info_script = "//tools/grit/grit_info.py"
105
106 # TODO(asvitkine): Add predetermined ids files for other platforms.
107 grit_predetermined_resource_ids_file = ""
108 if (is_mac) {
109   grit_predetermined_resource_ids_file =
110       "//tools/gritsettings/startup_resources_mac.txt"
111 }
112 if (is_win) {
113   grit_predetermined_resource_ids_file =
114       "//tools/gritsettings/startup_resources_win.txt"
115 }
116
117 template("grit") {
118   if (defined(invoker.output_dir)) {
119     _output_dir = invoker.output_dir
120   } else {
121     _output_dir = target_gen_dir
122   }
123
124   _grit_outputs =
125       get_path_info(rebase_path(invoker.outputs, ".", _output_dir), "abspath")
126
127   # Add .info output for all pak files
128   _pak_info_outputs = []
129   foreach(output, _grit_outputs) {
130     if (get_path_info(output, "extension") == "pak") {
131       _pak_info_outputs += [ output + ".info" ]
132     }
133   }
134
135   if (defined(invoker.output_name)) {
136     _grit_output_name = invoker.output_name
137   } else {
138     _grit_output_name = target_name
139   }
140
141   _grit_custom_target = target_name + "_grit"
142   action(_grit_custom_target) {
143     script = "//tools/grit/grit.py"
144     inputs = [ invoker.source ]
145
146     testonly = defined(invoker.testonly) && invoker.testonly
147
148     depfile = "$target_gen_dir/$target_name.d"
149
150     deps = [ "//tools/grit:grit_sources" ]
151     outputs = [ "${depfile}.stamp" ] + _grit_outputs + _pak_info_outputs
152
153     _grit_flags = grit_args
154
155     # Add extra defines with -D flags.
156     if (defined(invoker.defines)) {
157       foreach(i, invoker.defines) {
158         _grit_flags += [
159           "-D",
160           i,
161         ]
162       }
163     }
164
165     if (defined(invoker.grit_flags)) {
166       _grit_flags += invoker.grit_flags
167     }
168
169     _rebased_source_path = rebase_path(invoker.source, root_build_dir)
170     _enable_grit_info =
171         !defined(invoker.enable_input_discovery_for_gn_analyze) ||
172         invoker.enable_input_discovery_for_gn_analyze
173     if (_enable_grit_info && compute_inputs_for_analyze) {
174       # Only call exec_script when the user has explicitly opted into greater
175       # precision at the expense of performance.
176       _rel_inputs = exec_script("//tools/grit/grit_info.py",
177                                 [
178                                       "--inputs",
179                                       _rebased_source_path,
180                                     ] + _grit_flags,
181                                 "list lines")
182       inputs += rebase_path(_rel_inputs, ".", root_build_dir)
183     }
184
185     args = [
186              "-i",
187              _rebased_source_path,
188              "build",
189              "-o",
190              rebase_path(_output_dir, root_build_dir),
191              "--depdir",
192              ".",
193              "--depfile",
194              rebase_path(depfile, root_build_dir),
195              "--write-only-new=1",
196              "--depend-on-stamp",
197            ] + _grit_flags
198
199     # Add brotli executable if using brotli.
200     if (defined(invoker.use_brotli) && invoker.use_brotli) {
201       _brotli_target = "//third_party/brotli:brotli($host_toolchain)"
202       _brotli_executable = get_label_info(_brotli_target, "root_out_dir") +
203                            "/" + get_label_info(_brotli_target, "name")
204       if (host_os == "win") {
205         _brotli_executable += ".exe"
206       }
207
208       inputs += [ _brotli_executable ]
209       args += [
210         "--brotli",
211         rebase_path(_brotli_executable, root_build_dir),
212       ]
213     }
214
215     _resource_ids = grit_resource_id_file
216     if (defined(invoker.resource_ids)) {
217       _resource_ids = invoker.resource_ids
218     }
219
220     if (_resource_ids != "") {
221       inputs += [ _resource_ids ]
222       args += [
223         "-f",
224         rebase_path(_resource_ids, root_build_dir),
225       ]
226       if (_resource_ids == grit_resource_id_file) {
227         deps += [ grit_resource_id_target ]
228       }
229     }
230     if (grit_predetermined_resource_ids_file != "") {
231       inputs += [ grit_predetermined_resource_ids_file ]
232       args += [
233         "-p",
234         rebase_path(grit_predetermined_resource_ids_file, root_build_dir),
235       ]
236     }
237
238     # We want to make sure the declared outputs actually match what Grit is
239     # writing. We write the list to a file (some of the output lists are long
240     # enough to not fit on a Windows command line) and ask Grit to verify those
241     # are the actual outputs at runtime.
242     _asserted_list_file =
243         "$target_out_dir/${_grit_output_name}_expected_outputs.txt"
244     write_file(_asserted_list_file,
245                rebase_path(invoker.outputs, root_build_dir, _output_dir))
246     inputs += [ _asserted_list_file ]
247     args += [
248       "--assert-file-list",
249       rebase_path(_asserted_list_file, root_build_dir),
250     ]
251
252     if (enable_resource_allowlist_generation) {
253       _rc_grit_outputs = []
254       foreach(output, _grit_outputs) {
255         if (get_path_info(output, "extension") == "rc") {
256           _rc_grit_outputs += [ output ]
257         }
258       }
259
260       if (_rc_grit_outputs != []) {
261         # Resource allowlisting cannot be used with .rc files.
262         # Make sure that there aren't any .pak outputs which would require
263         # allowlist annotations.
264         assert(_pak_info_outputs == [], "can't combine .pak and .rc outputs")
265       } else {
266         args += [ "--allowlist-support" ]
267       }
268     }
269     if (_strip_resource_files) {
270       _js_minifier_command = rebase_path(_js_minifier, root_build_dir)
271       _css_minifier_command = rebase_path(_css_minifier, root_build_dir)
272       args += [
273         "--js-minifier",
274         _js_minifier_command,
275         "--css-minifier",
276         _css_minifier_command,
277       ]
278       inputs += [
279         _js_minifier,
280         _css_minifier,
281       ]
282     }
283
284     if (defined(invoker.visibility)) {
285       # This needs to include both what the invoker specified (since they
286       # probably include generated headers from this target), as well as the
287       # generated source set (since there's no guarantee that the visibility
288       # specified by the invoker includes our target).
289       #
290       # Only define visibility at all if the invoker specified it. Otherwise,
291       # we want to keep the public "no visibility specified" default.
292       visibility = [ ":${invoker.target_name}" ] + invoker.visibility
293     }
294
295     if (defined(invoker.use_brotli) && invoker.use_brotli) {
296       if (is_mac && is_asan) {
297         deps += [ "//tools/grit:brotli_mac_asan_workaround" ]
298       } else {
299         deps += [ "//third_party/brotli:brotli($host_toolchain)" ]
300       }
301     }
302     if (defined(invoker.deps)) {
303       deps += invoker.deps
304     }
305     if (defined(invoker.inputs)) {
306       inputs += invoker.inputs
307     }
308   }
309
310   # This is the thing that people actually link with, it must be named the
311   # same as the argument the template was invoked with.
312   source_set(target_name) {
313     testonly = defined(invoker.testonly) && invoker.testonly
314
315     # Since we generate a file, we need to be run before the targets that
316     # depend on us.
317     sources = []
318     foreach(_output, _grit_outputs) {
319       _extension = get_path_info(_output, "extension")
320       if (_extension != "json" && _extension != "gz" && _extension != "pak" &&
321           _extension != "xml") {
322         sources += [ _output ]
323       }
324     }
325
326     # Deps set on the template invocation will go on the action that runs
327     # grit above rather than this library. This target needs to depend on the
328     # action publicly so other scripts can take the outputs from the grit
329     # script as inputs.
330     public_deps = [ ":$_grit_custom_target" ]
331
332     if (defined(invoker.public_configs)) {
333       public_configs += invoker.public_configs
334     }
335
336     configs += [ "//build/config/compiler:wexit_time_destructors" ]
337     if (defined(invoker.configs)) {
338       configs += invoker.configs
339     }
340
341     if (defined(invoker.visibility)) {
342       visibility = invoker.visibility
343     }
344     output_name = _grit_output_name
345   }
346 }
347
348 if (is_android) {
349   import("//build/config/android/rules.gni")
350
351   # Declare a target that generates localized strings.xml from a .grd file.
352   #
353   # If this target is included in the deps of an android resources/library/apk,
354   # the strings.xml will be included with that target.
355   #
356   # Variables
357   #   deps: Specifies the dependencies of this target.
358   #   grd_file: Path to the .grd file to generate strings.xml from.
359   #   outputs: Expected grit outputs (see grit rule).
360   #
361   # Example
362   #  java_strings_grd("foo_strings_grd") {
363   #    grd_file = "foo_strings.grd"
364   #  }
365   template("java_strings_grd") {
366     forward_variables_from(invoker, [ "testonly" ])
367
368     _resources_zip = "$target_out_dir/$target_name.resources.zip"
369     _grit_target_name = "${target_name}__grit"
370     _grit_output_dir = "$target_gen_dir/${target_name}_grit_output"
371
372     grit(_grit_target_name) {
373       forward_variables_from(invoker,
374                              [
375                                "deps",
376                                "defines",
377                              ])
378       grit_flags = [
379         "-E",
380         "ANDROID_JAVA_TAGGED_ONLY=false",
381       ]
382       output_dir = _grit_output_dir
383       resource_ids = ""
384       source = invoker.grd_file
385       outputs = invoker.outputs
386     }
387
388     _zip_target_name = "${target_name}__zip"
389
390     zip(_zip_target_name) {
391       base_dir = _grit_output_dir
392
393       # No need to depend on the source_set().
394       _grit_dep = ":${_grit_target_name}_grit"
395       deps = [ _grit_dep ]
396       inputs = filter_exclude(get_target_outputs(_grit_dep), [ "*.stamp" ])
397       output = _resources_zip
398     }
399
400     android_generated_resources(target_name) {
401       forward_variables_from(invoker,
402                              [
403                                "resource_overlay",
404                                "visibility",
405                              ])
406       generating_target = ":$_zip_target_name"
407       generated_resources_zip = _resources_zip
408     }
409   }
410
411   # Declare a target that packages strings.xml generated from a grd file.
412   #
413   # If this target is included in the deps of an android resources/library/apk,
414   # the strings.xml will be included with that target.
415   #
416   # Variables
417   #  grit_output_dir: directory containing grit-generated files.
418   #  generated_files: list of android resource files to package.
419   #
420   # Example
421   #  java_strings_grd_prebuilt("foo_strings_grd") {
422   #    grit_output_dir = "$root_gen_dir/foo/grit"
423   #    generated_files = [
424   #      "values/strings.xml"
425   #    ]
426   #  }
427   template("java_strings_grd_prebuilt") {
428     forward_variables_from(invoker, [ "testonly" ])
429
430     _resources_zip = "$target_out_dir/$target_name.resources.zip"
431     _zip_target_name = "${target_name}__zip"
432
433     zip(_zip_target_name) {
434       base_dir = invoker.grit_output_dir
435       inputs = rebase_path(invoker.generated_files, ".", base_dir)
436       output = _resources_zip
437       if (defined(invoker.deps)) {
438         deps = []
439         foreach(_dep, invoker.deps) {
440           deps += [ "${_dep}_grit" ]
441         }
442       }
443     }
444
445     android_generated_resources(target_name) {
446       forward_variables_from(invoker,
447                              [
448                                "resource_overlay",
449                                "visibility",
450                              ])
451       generating_target = ":$_zip_target_name"
452       generated_resources_zip = _resources_zip
453     }
454   }
455 }