grit_rule.gni 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. # Copyright 2014 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. # Instantiate grit. This will produce a script target to run grit (named
  5. # ${target_name}_grit), and a static library that compiles the .cc files.
  6. #
  7. # In general, code should depend on the static library. However, if the
  8. # generated files are only processed by other actions to generate other
  9. # files, it is possible to depend on the script target directly.
  10. #
  11. # Parameters
  12. #
  13. # source (required)
  14. # Path to .grd file.
  15. #
  16. # enable_input_discovery_for_gn_analyze (default=true)
  17. # Runs grit_info.py via exec_script() when compute_inputs_for_analyze=true
  18. # in order to discover all files that affect this target.
  19. # Turn this off when the .grd file is generated, or an <include> with
  20. # flattenhtml=true points to a generated file.
  21. # For "gn analyze" to be correct with this arg disabled, all inputs
  22. # must be listed via |inputs|.
  23. #
  24. # inputs (optional)
  25. # List of additional files, required for grit to process source file.
  26. #
  27. # outputs (required)
  28. # List of outputs from grit, relative to the target_gen_dir. Grit will
  29. # verify at build time that this list is correct and will fail if there
  30. # is a mismatch between the outputs specified by the .grd file and the
  31. # outputs list here.
  32. #
  33. # To get this list, you can look in the .grd file for
  34. # <output filename="..." and put those filename here. The base directory
  35. # of the list in Grit and the output list specified in the GN grit target
  36. # are the same (the target_gen_dir) so you can generally copy the names
  37. # exactly.
  38. #
  39. # To get the list of outputs programatically, run:
  40. # python tools/grit/grit_info.py --outputs . path/to/your.grd
  41. # And strip the leading "./" from the output files.
  42. #
  43. # defines (optional)
  44. # Extra defines to pass to grit (on top of the global defines in the
  45. # grit_args list).
  46. #
  47. # grit_flags (optional)
  48. # List of strings containing extra command-line flags to pass to Grit.
  49. #
  50. # resource_ids (optional)
  51. # Path to a grit "firstidsfile". Default is
  52. # //tools/gritsettings/resource_ids. Set to "" to use the value specified
  53. # in the <grit> nodes of the processed files.
  54. #
  55. # output_dir (optional)
  56. # Directory for generated files. If you specify this, you will often
  57. # want to specify output_name if the target name is not particularly
  58. # unique, since this can cause files from multiple grit targets to
  59. # overwrite each other.
  60. #
  61. # output_name (optional)
  62. # Provide an alternate base name for the generated files, like the .d
  63. # files. Normally these are based on the target name and go in the
  64. # output_dir, but if multiple targets with the same name end up in
  65. # the same output_dir, they can collide.
  66. #
  67. # configs (optional)
  68. # List of additional configs to be applied to the generated target.
  69. #
  70. # deps (optional)
  71. # testonly (optional)
  72. # visibility (optional)
  73. # Normal meaning.
  74. #
  75. #
  76. # Example
  77. #
  78. # grit("my_resources") {
  79. # # Source and outputs are required.
  80. # source = "myfile.grd"
  81. # outputs = [
  82. # "foo_strings.h",
  83. # "foo_strings.pak",
  84. # ]
  85. #
  86. # grit_flags = [ "-E", "foo=bar" ] # Optional extra flags.
  87. # # You can also put deps here if the grit source depends on generated
  88. # # files.
  89. # }
  90. import("//build/config/compiler/compiler.gni")
  91. import("//build/config/compute_inputs_for_analyze.gni")
  92. import("//build/config/sanitizers/sanitizers.gni")
  93. import("//build/toolchain/gcc_toolchain.gni")
  94. import("//tools/grit/grit_args.gni")
  95. _strip_resource_files = is_android && is_official_build
  96. _js_minifier = "//tools/grit/minify_with_uglify.py"
  97. _css_minifier = "//tools/grit/minimize_css.py"
  98. grit_resource_id_target = "//tools/gritsettings:default_resource_ids"
  99. grit_resource_id_file =
  100. get_label_info(grit_resource_id_target, "target_gen_dir") +
  101. "/default_resource_ids"
  102. grit_info_script = "//tools/grit/grit_info.py"
  103. # TODO(asvitkine): Add predetermined ids files for other platforms.
  104. grit_predetermined_resource_ids_file = ""
  105. if (is_mac) {
  106. grit_predetermined_resource_ids_file =
  107. "//tools/gritsettings/startup_resources_mac.txt"
  108. }
  109. if (is_win) {
  110. grit_predetermined_resource_ids_file =
  111. "//tools/gritsettings/startup_resources_win.txt"
  112. }
  113. template("grit") {
  114. if (defined(invoker.output_dir)) {
  115. _output_dir = invoker.output_dir
  116. } else {
  117. _output_dir = target_gen_dir
  118. }
  119. _grit_outputs =
  120. get_path_info(rebase_path(invoker.outputs, ".", _output_dir), "abspath")
  121. # Add .info output for all pak files
  122. _pak_info_outputs = []
  123. foreach(output, _grit_outputs) {
  124. if (get_path_info(output, "extension") == "pak") {
  125. _pak_info_outputs += [ output + ".info" ]
  126. }
  127. }
  128. if (defined(invoker.output_name)) {
  129. _grit_output_name = invoker.output_name
  130. } else {
  131. _grit_output_name = target_name
  132. }
  133. _grit_custom_target = target_name + "_grit"
  134. action(_grit_custom_target) {
  135. script = "//tools/grit/grit.py"
  136. inputs = [ invoker.source ]
  137. testonly = defined(invoker.testonly) && invoker.testonly
  138. depfile = "$target_gen_dir/$target_name.d"
  139. deps = [ "//tools/grit:grit_sources" ]
  140. outputs = [ "${depfile}.stamp" ] + _grit_outputs + _pak_info_outputs
  141. _grit_flags = grit_args
  142. # Add extra defines with -D flags.
  143. if (defined(invoker.defines)) {
  144. foreach(i, invoker.defines) {
  145. _grit_flags += [
  146. "-D",
  147. i,
  148. ]
  149. }
  150. }
  151. if (defined(invoker.grit_flags)) {
  152. _grit_flags += invoker.grit_flags
  153. }
  154. _rebased_source_path = rebase_path(invoker.source, root_build_dir)
  155. _enable_grit_info =
  156. !defined(invoker.enable_input_discovery_for_gn_analyze) ||
  157. invoker.enable_input_discovery_for_gn_analyze
  158. if (_enable_grit_info && compute_inputs_for_analyze) {
  159. # Only call exec_script when the user has explicitly opted into greater
  160. # precision at the expense of performance.
  161. _rel_inputs = exec_script("//tools/grit/grit_info.py",
  162. [
  163. "--inputs",
  164. _rebased_source_path,
  165. ] + _grit_flags,
  166. "list lines")
  167. inputs += rebase_path(_rel_inputs, ".", root_build_dir)
  168. }
  169. args = [
  170. "-i",
  171. _rebased_source_path,
  172. "build",
  173. "-o",
  174. rebase_path(_output_dir, root_build_dir),
  175. "--depdir",
  176. ".",
  177. "--depfile",
  178. rebase_path(depfile, root_build_dir),
  179. "--write-only-new=1",
  180. "--depend-on-stamp",
  181. ] + _grit_flags
  182. # Add brotli executable if using brotli.
  183. if (defined(invoker.use_brotli) && invoker.use_brotli) {
  184. _brotli_target = "//third_party/brotli:brotli($host_toolchain)"
  185. _brotli_executable = get_label_info(_brotli_target, "root_out_dir") +
  186. "/" + get_label_info(_brotli_target, "name")
  187. if (host_os == "win") {
  188. _brotli_executable += ".exe"
  189. }
  190. inputs += [ _brotli_executable ]
  191. args += [
  192. "--brotli",
  193. rebase_path(_brotli_executable, root_build_dir),
  194. ]
  195. }
  196. _resource_ids = grit_resource_id_file
  197. if (defined(invoker.resource_ids)) {
  198. _resource_ids = invoker.resource_ids
  199. }
  200. if (_resource_ids != "") {
  201. inputs += [ _resource_ids ]
  202. args += [
  203. "-f",
  204. rebase_path(_resource_ids, root_build_dir),
  205. ]
  206. if (_resource_ids == grit_resource_id_file) {
  207. deps += [ grit_resource_id_target ]
  208. }
  209. }
  210. if (grit_predetermined_resource_ids_file != "") {
  211. inputs += [ grit_predetermined_resource_ids_file ]
  212. args += [
  213. "-p",
  214. rebase_path(grit_predetermined_resource_ids_file, root_build_dir),
  215. ]
  216. }
  217. # We want to make sure the declared outputs actually match what Grit is
  218. # writing. We write the list to a file (some of the output lists are long
  219. # enough to not fit on a Windows command line) and ask Grit to verify those
  220. # are the actual outputs at runtime.
  221. _asserted_list_file =
  222. "$target_out_dir/${_grit_output_name}_expected_outputs.txt"
  223. write_file(_asserted_list_file,
  224. rebase_path(invoker.outputs, root_build_dir, _output_dir))
  225. inputs += [ _asserted_list_file ]
  226. args += [
  227. "--assert-file-list",
  228. rebase_path(_asserted_list_file, root_build_dir),
  229. ]
  230. if (enable_resource_allowlist_generation) {
  231. _rc_grit_outputs = []
  232. foreach(output, _grit_outputs) {
  233. if (get_path_info(output, "extension") == "rc") {
  234. _rc_grit_outputs += [ output ]
  235. }
  236. }
  237. if (_rc_grit_outputs != []) {
  238. # Resource allowlisting cannot be used with .rc files.
  239. # Make sure that there aren't any .pak outputs which would require
  240. # allowlist annotations.
  241. assert(_pak_info_outputs == [], "can't combine .pak and .rc outputs")
  242. } else {
  243. args += [ "--allowlist-support" ]
  244. }
  245. }
  246. if (_strip_resource_files) {
  247. _js_minifier_command = rebase_path(_js_minifier, root_build_dir)
  248. _css_minifier_command = rebase_path(_css_minifier, root_build_dir)
  249. args += [
  250. "--js-minifier",
  251. _js_minifier_command,
  252. "--css-minifier",
  253. _css_minifier_command,
  254. ]
  255. inputs += [
  256. _js_minifier,
  257. _css_minifier,
  258. ]
  259. }
  260. if (defined(invoker.visibility)) {
  261. # This needs to include both what the invoker specified (since they
  262. # probably include generated headers from this target), as well as the
  263. # generated source set (since there's no guarantee that the visibility
  264. # specified by the invoker includes our target).
  265. #
  266. # Only define visibility at all if the invoker specified it. Otherwise,
  267. # we want to keep the public "no visibility specified" default.
  268. visibility = [ ":${invoker.target_name}" ] + invoker.visibility
  269. }
  270. if (defined(invoker.use_brotli) && invoker.use_brotli) {
  271. if (is_mac && is_asan) {
  272. deps += [ "//tools/grit:brotli_mac_asan_workaround" ]
  273. } else {
  274. deps += [ "//third_party/brotli:brotli($host_toolchain)" ]
  275. }
  276. }
  277. if (defined(invoker.deps)) {
  278. deps += invoker.deps
  279. }
  280. if (defined(invoker.inputs)) {
  281. inputs += invoker.inputs
  282. }
  283. }
  284. # This is the thing that people actually link with, it must be named the
  285. # same as the argument the template was invoked with.
  286. source_set(target_name) {
  287. testonly = defined(invoker.testonly) && invoker.testonly
  288. # Since we generate a file, we need to be run before the targets that
  289. # depend on us.
  290. sources = []
  291. foreach(_output, _grit_outputs) {
  292. _extension = get_path_info(_output, "extension")
  293. if (_extension != "json" && _extension != "gz" && _extension != "pak" &&
  294. _extension != "xml") {
  295. sources += [ _output ]
  296. }
  297. }
  298. # Deps set on the template invocation will go on the action that runs
  299. # grit above rather than this library. This target needs to depend on the
  300. # action publicly so other scripts can take the outputs from the grit
  301. # script as inputs.
  302. public_deps = [ ":$_grit_custom_target" ]
  303. deps = [ "//base" ]
  304. if (defined(invoker.public_configs)) {
  305. public_configs += invoker.public_configs
  306. }
  307. if (defined(invoker.configs)) {
  308. configs += invoker.configs
  309. }
  310. if (defined(invoker.visibility)) {
  311. visibility = invoker.visibility
  312. }
  313. output_name = _grit_output_name
  314. }
  315. }
  316. if (is_android) {
  317. import("//build/config/android/rules.gni")
  318. # Declare a target that generates localized strings.xml from a .grd file.
  319. #
  320. # If this target is included in the deps of an android resources/library/apk,
  321. # the strings.xml will be included with that target.
  322. #
  323. # Variables
  324. # deps: Specifies the dependencies of this target.
  325. # grd_file: Path to the .grd file to generate strings.xml from.
  326. # outputs: Expected grit outputs (see grit rule).
  327. #
  328. # Example
  329. # java_strings_grd("foo_strings_grd") {
  330. # grd_file = "foo_strings.grd"
  331. # }
  332. template("java_strings_grd") {
  333. forward_variables_from(invoker, [ "testonly" ])
  334. _resources_zip = "$target_out_dir/$target_name.resources.zip"
  335. _grit_target_name = "${target_name}__grit"
  336. _grit_output_dir = "$target_gen_dir/${target_name}_grit_output"
  337. grit(_grit_target_name) {
  338. forward_variables_from(invoker,
  339. [
  340. "deps",
  341. "defines",
  342. ])
  343. grit_flags = [
  344. "-E",
  345. "ANDROID_JAVA_TAGGED_ONLY=false",
  346. ]
  347. output_dir = _grit_output_dir
  348. resource_ids = ""
  349. source = invoker.grd_file
  350. outputs = invoker.outputs
  351. }
  352. _zip_target_name = "${target_name}__zip"
  353. zip(_zip_target_name) {
  354. base_dir = _grit_output_dir
  355. # No need to depend on the source_set().
  356. _grit_dep = ":${_grit_target_name}_grit"
  357. deps = [ _grit_dep ]
  358. inputs = filter_exclude(get_target_outputs(_grit_dep), [ "*.stamp" ])
  359. output = _resources_zip
  360. }
  361. android_generated_resources(target_name) {
  362. forward_variables_from(invoker,
  363. [
  364. "resource_overlay",
  365. "visibility",
  366. ])
  367. generating_target = ":$_zip_target_name"
  368. generated_resources_zip = _resources_zip
  369. }
  370. }
  371. # Declare a target that packages strings.xml generated from a grd file.
  372. #
  373. # If this target is included in the deps of an android resources/library/apk,
  374. # the strings.xml will be included with that target.
  375. #
  376. # Variables
  377. # grit_output_dir: directory containing grit-generated files.
  378. # generated_files: list of android resource files to package.
  379. #
  380. # Example
  381. # java_strings_grd_prebuilt("foo_strings_grd") {
  382. # grit_output_dir = "$root_gen_dir/foo/grit"
  383. # generated_files = [
  384. # "values/strings.xml"
  385. # ]
  386. # }
  387. template("java_strings_grd_prebuilt") {
  388. forward_variables_from(invoker, [ "testonly" ])
  389. _resources_zip = "$target_out_dir/$target_name.resources.zip"
  390. _zip_target_name = "${target_name}__zip"
  391. zip(_zip_target_name) {
  392. base_dir = invoker.grit_output_dir
  393. inputs = rebase_path(invoker.generated_files, ".", base_dir)
  394. output = _resources_zip
  395. if (defined(invoker.deps)) {
  396. deps = invoker.deps
  397. }
  398. }
  399. android_generated_resources(target_name) {
  400. forward_variables_from(invoker,
  401. [
  402. "resource_overlay",
  403. "visibility",
  404. ])
  405. generating_target = ":$_zip_target_name"
  406. generated_resources_zip = _resources_zip
  407. }
  408. }
  409. }