f0e7fdf8e3a1382b76424ded5949b27e8a96a86f
[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 grit_defines = []
100
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"
106
107 # TODO(asvitkine): Add predetermined ids files for other platforms.
108 grit_predetermined_resource_ids_file = ""
109 if (is_mac) {
110   grit_predetermined_resource_ids_file =
111       "//tools/gritsettings/startup_resources_mac.txt"
112 }
113 if (is_win) {
114   grit_predetermined_resource_ids_file =
115       "//tools/gritsettings/startup_resources_win.txt"
116 }
117
118 if (is_tizen) {
119   grit_defines += [
120     "-D",
121     "is_tizen",
122   ]
123 }
124
125 template("grit") {
126   if (defined(invoker.output_dir)) {
127     _output_dir = invoker.output_dir
128   } else {
129     _output_dir = target_gen_dir
130   }
131
132   _grit_outputs =
133       get_path_info(rebase_path(invoker.outputs, ".", _output_dir), "abspath")
134
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" ]
140     }
141   }
142
143   if (defined(invoker.output_name)) {
144     _grit_output_name = invoker.output_name
145   } else {
146     _grit_output_name = target_name
147   }
148
149   _grit_custom_target = target_name + "_grit"
150   action(_grit_custom_target) {
151     script = "//tools/grit/grit.py"
152     inputs = [ invoker.source ]
153
154     testonly = defined(invoker.testonly) && invoker.testonly
155
156     depfile = "$target_gen_dir/$target_name.d"
157
158     deps = [ "//tools/grit:grit_sources" ]
159     outputs = [ "${depfile}.stamp" ] + _grit_outputs + _pak_info_outputs
160
161     _grit_flags = grit_args
162
163     # Add extra defines with -D flags.
164     if (defined(invoker.defines)) {
165       foreach(i, invoker.defines) {
166         _grit_flags += [
167           "-D",
168           i,
169         ]
170       }
171     }
172
173     if (defined(invoker.grit_flags)) {
174       _grit_flags += invoker.grit_flags
175     }
176
177     _rebased_source_path = rebase_path(invoker.source, root_build_dir)
178     _enable_grit_info =
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",
185                                 [
186                                       "--inputs",
187                                       _rebased_source_path,
188                                     ] + _grit_flags,
189                                 "list lines")
190       inputs += rebase_path(_rel_inputs, ".", root_build_dir)
191     }
192
193     args = [
194              "-i",
195              _rebased_source_path,
196              "build",
197              "-o",
198              rebase_path(_output_dir, root_build_dir),
199              "--depdir",
200              ".",
201              "--depfile",
202              rebase_path(depfile, root_build_dir),
203              "--write-only-new=1",
204              "--depend-on-stamp",
205            ] + _grit_flags + grit_defines
206
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"
214       }
215
216       inputs += [ _brotli_executable ]
217       args += [
218         "--brotli",
219         rebase_path(_brotli_executable, root_build_dir),
220       ]
221     }
222
223     _resource_ids = grit_resource_id_file
224     if (defined(invoker.resource_ids)) {
225       _resource_ids = invoker.resource_ids
226     }
227
228     if (_resource_ids != "") {
229       inputs += [ _resource_ids ]
230       args += [
231         "-f",
232         rebase_path(_resource_ids, root_build_dir),
233       ]
234       if (_resource_ids == grit_resource_id_file) {
235         deps += [ grit_resource_id_target ]
236       }
237     }
238     if (grit_predetermined_resource_ids_file != "") {
239       inputs += [ grit_predetermined_resource_ids_file ]
240       args += [
241         "-p",
242         rebase_path(grit_predetermined_resource_ids_file, root_build_dir),
243       ]
244     }
245
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 ]
255     args += [
256       "--assert-file-list",
257       rebase_path(_asserted_list_file, root_build_dir),
258     ]
259
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 ]
265         }
266       }
267
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")
273       } else {
274         args += [ "--allowlist-support" ]
275       }
276     }
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)
280       args += [
281         "--js-minifier",
282         _js_minifier_command,
283         "--css-minifier",
284         _css_minifier_command,
285       ]
286       inputs += [
287         _js_minifier,
288         _css_minifier,
289       ]
290     }
291
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).
297       #
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
301     }
302
303     if (defined(invoker.use_brotli) && invoker.use_brotli) {
304       if (is_mac && is_asan) {
305         deps += [ "//tools/grit:brotli_mac_asan_workaround" ]
306       } else {
307         deps += [ "//third_party/brotli:brotli($host_toolchain)" ]
308       }
309     }
310     if (defined(invoker.deps)) {
311       deps += invoker.deps
312     }
313     if (defined(invoker.inputs)) {
314       inputs += invoker.inputs
315     }
316   }
317
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
322
323     # Since we generate a file, we need to be run before the targets that
324     # depend on us.
325     sources = []
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 ]
331       }
332     }
333
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
337     # script as inputs.
338     public_deps = [ ":$_grit_custom_target" ]
339
340     if (defined(invoker.public_configs)) {
341       public_configs += invoker.public_configs
342     }
343
344     configs += [ "//build/config/compiler:wexit_time_destructors" ]
345     if (defined(invoker.configs)) {
346       configs += invoker.configs
347     }
348
349     if (defined(invoker.visibility)) {
350       visibility = invoker.visibility
351     }
352     output_name = _grit_output_name
353   }
354 }
355
356 if (is_android) {
357   import("//build/config/android/rules.gni")
358
359   # Declare a target that generates localized strings.xml from a .grd file.
360   #
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.
363   #
364   # Variables
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).
368   #
369   # Example
370   #  java_strings_grd("foo_strings_grd") {
371   #    grd_file = "foo_strings.grd"
372   #  }
373   template("java_strings_grd") {
374     forward_variables_from(invoker, [ "testonly" ])
375
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"
379
380     grit(_grit_target_name) {
381       forward_variables_from(invoker,
382                              [
383                                "deps",
384                                "defines",
385                              ])
386       grit_flags = [
387         "-E",
388         "ANDROID_JAVA_TAGGED_ONLY=false",
389       ]
390       output_dir = _grit_output_dir
391       resource_ids = ""
392       source = invoker.grd_file
393       outputs = invoker.outputs
394     }
395
396     _zip_target_name = "${target_name}__zip"
397
398     zip(_zip_target_name) {
399       base_dir = _grit_output_dir
400
401       # No need to depend on the source_set().
402       _grit_dep = ":${_grit_target_name}_grit"
403       deps = [ _grit_dep ]
404       inputs = filter_exclude(get_target_outputs(_grit_dep), [ "*.stamp" ])
405       output = _resources_zip
406     }
407
408     android_generated_resources(target_name) {
409       forward_variables_from(invoker,
410                              [
411                                "resource_overlay",
412                                "visibility",
413                              ])
414       generating_target = ":$_zip_target_name"
415       generated_resources_zip = _resources_zip
416     }
417   }
418
419   # Declare a target that packages strings.xml generated from a grd file.
420   #
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.
423   #
424   # Variables
425   #  grit_output_dir: directory containing grit-generated files.
426   #  generated_files: list of android resource files to package.
427   #
428   # Example
429   #  java_strings_grd_prebuilt("foo_strings_grd") {
430   #    grit_output_dir = "$root_gen_dir/foo/grit"
431   #    generated_files = [
432   #      "values/strings.xml"
433   #    ]
434   #  }
435   template("java_strings_grd_prebuilt") {
436     forward_variables_from(invoker, [ "testonly" ])
437
438     _resources_zip = "$target_out_dir/$target_name.resources.zip"
439     _zip_target_name = "${target_name}__zip"
440
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)) {
446         deps = []
447         foreach(_dep, invoker.deps) {
448           deps += [ "${_dep}_grit" ]
449         }
450       }
451     }
452
453     android_generated_resources(target_name) {
454       forward_variables_from(invoker,
455                              [
456                                "resource_overlay",
457                                "visibility",
458                              ])
459       generating_target = ":$_zip_target_name"
460       generated_resources_zip = _resources_zip
461     }
462   }
463 }