rust_target.gni 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. # Copyright 2021 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. import("//build/config/rust.gni")
  5. import("//build/rust/rust_unit_test.gni")
  6. # The //build directory is re-used for non-Chromium products. We do not
  7. # support cxx/autocxx bindings in such contexts, because
  8. # //third_party may be missing.
  9. if (build_with_chromium) {
  10. import("//third_party/rust/autocxx/chromium_integration/rust_autocxx.gni")
  11. }
  12. # Creates a Rust target (rlib, executable, proc macro etc.) with
  13. # ability to understand some handy variables such as "edition" and
  14. # "features" and also to build any associated unit tests.
  15. #
  16. # Normally, you should not use this directly. Use either
  17. # - cargo_crate.gni - for 3p crates only
  18. # - rust_static_library.gni - for 1p Rust code
  19. # - mixed_static_library.gni - for 1p C++ and Rust code together.
  20. #
  21. # Because the common use of this is rust_static_library, all the documentation
  22. # for the supported options is given in rust_static_library.gni. Please refer
  23. # over there.
  24. #
  25. # If you're using rust_target directly, you will also need to specify:
  26. # target_type
  27. # executable, rust_library etc. per GN norms
  28. #
  29. # support_use_from_cpp (bool)
  30. # Whether both C++ and Rust may link against this. If so, the Rust standard
  31. # library will be explicitly included for C++ to link against. This is
  32. # always true if cxx_bindings is non-empty, in which case [auto]cxx
  33. # will also be implicitly depended on.
  34. #
  35. # There is one area where this differs from `rust_static_library`: configs.
  36. # Here, you must specify `executable_configs` or `library_configs`
  37. # depending on the type of thing you're generating. This is so that
  38. # different defaults can be provided.
  39. template("rust_target") {
  40. # Only one of `crate_root` or `generate_crate_root` can be specified, or
  41. # neither.
  42. assert(!defined(invoker.crate_root) ||
  43. !(defined(invoker.generate_crate_root) && invoker.generate_crate_root))
  44. _target_name = target_name
  45. _crate_name = target_name
  46. if (defined(invoker.crate_name)) {
  47. _crate_name = invoker.crate_name
  48. }
  49. if (defined(invoker.output_dir) && invoker.output_dir != "") {
  50. _out_dir = invoker.output_dir
  51. } else {
  52. _out_dir = target_out_dir
  53. }
  54. if (defined(invoker.generate_crate_root) && invoker.generate_crate_root) {
  55. generated_file("${_target_name}_crate_root") {
  56. outputs = [ "${target_gen_dir}/${target_name}.rs" ]
  57. contents = [
  58. "// Generated crate root for ${_target_name}.",
  59. "// @generated",
  60. "",
  61. ]
  62. foreach(rs, invoker.sources) {
  63. rs_path_from_root = rebase_path(rs, target_gen_dir)
  64. contents += [ "#[path = \"${rs_path_from_root}\"]" ]
  65. # Drop the file extension from the module name.
  66. rs_modname = string_replace(rs, ".rs", "")
  67. # Replace invalid "/" chars in the source file path.
  68. rs_modname = string_replace(rs_modname, "/", "_")
  69. # Since source files are specified relative to the BUILD.gn they may
  70. # also have ".." path components.
  71. rs_modname = string_replace(rs_modname, "..", "dotdot")
  72. contents += [
  73. "mod ${rs_modname};",
  74. "",
  75. ]
  76. }
  77. }
  78. _crate_root =
  79. string_join("", get_target_outputs(":${_target_name}_crate_root"))
  80. } else if (defined(invoker.crate_root)) {
  81. _crate_root = invoker.crate_root
  82. } else if (invoker.target_type == "executable") {
  83. _crate_root = "src/main.rs"
  84. } else {
  85. _crate_root = "src/lib.rs"
  86. }
  87. _testonly = false
  88. if (defined(invoker.testonly)) {
  89. _testonly = invoker.testonly
  90. }
  91. if (defined(invoker.visibility)) {
  92. _visibility = invoker.visibility
  93. }
  94. _rustflags = []
  95. if (defined(invoker.rustflags)) {
  96. _rustflags += invoker.rustflags
  97. }
  98. if (defined(invoker.features)) {
  99. foreach(i, invoker.features) {
  100. _rustflags += [ "--cfg=feature=\"${i}\"" ]
  101. }
  102. }
  103. _edition = "2021"
  104. if (defined(invoker.edition)) {
  105. _edition = invoker.edition
  106. }
  107. _configs = [ string_join("",
  108. [
  109. "//build/rust:edition_",
  110. _edition,
  111. ]) ]
  112. if (invoker.target_type == "executable") {
  113. if (defined(invoker.executable_configs)) {
  114. _configs += invoker.executable_configs
  115. }
  116. } else {
  117. if (defined(invoker.library_configs)) {
  118. _configs += invoker.library_configs
  119. }
  120. }
  121. _forward_to_host_toolchain = false
  122. if (invoker.target_type == "rust_proc_macro") {
  123. # TODO(crbug.com/gn/104): GN rust_proc_macro targets are missing this
  124. # command line flag, for the proc_macro crate which is provided by rustc for
  125. # compiling proc-macros.
  126. _rustflags += [
  127. "--extern",
  128. "proc_macro",
  129. ]
  130. if (current_toolchain != host_toolchain) {
  131. _forward_to_host_toolchain = true
  132. }
  133. _main_target_suffix = "${target_name}__proc_macro"
  134. } else {
  135. _main_target_suffix = "__rlib"
  136. }
  137. _deps = []
  138. if (defined(invoker.deps)) {
  139. _deps += invoker.deps
  140. }
  141. _public_deps = []
  142. if (defined(invoker.public_deps)) {
  143. _public_deps += invoker.public_deps
  144. }
  145. _build_unit_tests = false
  146. if (defined(invoker.build_native_rust_unit_tests)) {
  147. _build_unit_tests =
  148. invoker.build_native_rust_unit_tests && can_build_rust_unit_tests
  149. }
  150. # Declares that the Rust crate generates bindings between C++ and Rust via the
  151. # Cxx/autocxx crates. It may generate C++ headers and/or use the cxx crate macros
  152. # to generate Rust code internally, depending on what bindings are declared. If
  153. # set, it's a set of rust files that include Cxx or autocxx bindings declarations.
  154. _cxx_bindings = []
  155. if (defined(invoker.cxx_bindings)) {
  156. assert(
  157. build_with_chromium,
  158. "cxx/autocxx bindings are not supported when building rust targets " +
  159. "outside the Chromium build.")
  160. _cxx_bindings = invoker.cxx_bindings
  161. }
  162. _rustenv = []
  163. if (defined(invoker.rustenv)) {
  164. _rustenv += invoker.rustenv
  165. }
  166. foreach(_autocxx_generated, _cxx_bindings) {
  167. # TODO(crbug.com/1306841): Currently we support only a single
  168. # include_cpp! macro per target and this ugly environment
  169. # variable is necessary. Meanwhile, this path must match that of
  170. # out_gen0_rs in rust_autocxx.gni.
  171. _rustenv += [ "AUTOCXX_RS_FILE=" + rebase_path(
  172. "$target_gen_dir/$_autocxx_generated/gen0.include.rs") ]
  173. }
  174. # Normally we generate a C++ bindings group only if there are C++ bindings,
  175. # since it's not useful otherwise. But mixed targets want to be able to depend
  176. # on the Rust side regardless, or other Rust targets that provide interop
  177. # without using Cxx to generate bindings (such as via #[no_mangle] functions).
  178. _support_use_from_cpp = _cxx_bindings != []
  179. if (defined(invoker.support_use_from_cpp) && invoker.support_use_from_cpp) {
  180. _support_use_from_cpp = true
  181. }
  182. if (defined(invoker.mutually_dependent_target)) {
  183. _mutually_dependent_target = invoker.mutually_dependent_target
  184. _mutually_dependent_public_deps = invoker.mutually_dependent_public_deps
  185. } else {
  186. assert(!defined(_mutually_dependent_public_deps))
  187. }
  188. # TODO(danakj): This could be a hash generated from the input crate, such as
  189. # from its path, in which case the BUILD.gn would not need to specify
  190. # anything. But GN doesn't give us a hash function to make that easy.
  191. _metadata = "0"
  192. if (defined(invoker.epoch)) {
  193. _metadata = invoker.epoch
  194. }
  195. # We require that all source files are listed, even though this is
  196. # not a requirement for rustc. The reason is to ensure that tools
  197. # such as `gn deps` give the correct answer, and thus we trigger
  198. # the right test suites etc. on code change.
  199. # TODO(crbug.com/1256930) - verify this is correct
  200. assert(defined(invoker.sources), "sources must be listed")
  201. if (_forward_to_host_toolchain) {
  202. # Redirect to the host toolchain.
  203. group(_target_name) {
  204. testonly = _testonly
  205. if (defined(_visibility)) {
  206. visibility = _visibility
  207. }
  208. public_deps =
  209. [ ":${_target_name}${_main_target_suffix}($host_toolchain)" ]
  210. }
  211. not_needed(invoker, "*")
  212. not_needed([
  213. "_build_unit_tests",
  214. "_crate_root",
  215. "_crate_name",
  216. "_cxx_bindings",
  217. "_deps",
  218. "_metadata",
  219. "_mutually_dependent_public_deps",
  220. "_mutually_dependent_target",
  221. "_out_dir",
  222. "_public_deps",
  223. "_rustenv",
  224. "_support_use_from_cpp",
  225. "_test_deps",
  226. "_testonly",
  227. "_visibility",
  228. "proc_macro_target",
  229. ])
  230. } else {
  231. group(_target_name) {
  232. testonly = _testonly
  233. if (defined(_visibility)) {
  234. visibility = _visibility
  235. }
  236. # Both the C++ bindings (if present) and the Rust crate should be treated
  237. # like direct dependencies, so we expose them both in public_deps.
  238. public_deps = [ ":${_target_name}${_main_target_suffix}" ]
  239. if (_support_use_from_cpp) {
  240. if (_cxx_bindings != []) {
  241. public_deps += [ ":${_target_name}_autocxx_generated" ]
  242. # Additionally, C++ bindings generated by Cxx can include C++ types
  243. # that come from the Cxx library, such as `rust::Str`. So any C++
  244. # target that depends on a rust target directly may need access to Cxx
  245. # as well, which means it must appear in public_deps.
  246. public_deps += [ "//build/rust:cxx_cppdeps" ]
  247. } else {
  248. # If we're supporting use from C++ but not using Cxx bindings, then we
  249. # just need to make sure C++ links in the Rust stdlib.
  250. deps = [ "//build/rust/std" ]
  251. }
  252. } else {
  253. # Mixed targets (which define the below) always enable use from C++.
  254. assert(!defined(_mutually_dependent_target))
  255. }
  256. }
  257. _rust_deps = _deps
  258. _rust_public_deps = _public_deps
  259. _autocxx_deps = _deps + _public_deps
  260. # In a mixed target, the C++ bindings may include headers from the C++
  261. # part of the mixed target. Those headers rely on being used with the
  262. # correct dependencies present.
  263. if (defined(_mutually_dependent_public_deps)) {
  264. _autocxx_deps += _mutually_dependent_public_deps
  265. }
  266. # The Rust target (and unit tests) need the autocxx & cxx crates when using
  267. # them to generate bindings - both are in autocxx_rustdeps. We also need
  268. # to depend upon the autocxx code generation step, since when we build
  269. # our Rust code, a procedural macro will look for a file generated by that
  270. # codegen step.
  271. if (_cxx_bindings != []) {
  272. _rust_deps +=
  273. [ "//third_party/rust/autocxx/chromium_integration:autocxx_rustdeps" ]
  274. # Generated bindings are a public dep so that the unit tests can include
  275. # them.
  276. _rust_public_deps += [ ":${_target_name}_autocxx_generated" ]
  277. }
  278. # You must go through the groups above to get to these targets.
  279. _visibility = []
  280. _visibility = [ ":${_target_name}" ]
  281. target(invoker.target_type, "${_target_name}${_main_target_suffix}") {
  282. forward_variables_from(invoker,
  283. "*",
  284. TESTONLY_AND_VISIBILITY + [
  285. "features",
  286. "deps",
  287. "public_deps",
  288. "rustflags",
  289. "rustenv",
  290. "configs",
  291. "output_dir",
  292. "unit_test_target",
  293. "test_inputs",
  294. ])
  295. testonly = _testonly
  296. visibility = _visibility
  297. crate_name = _crate_name
  298. crate_root = _crate_root
  299. configs = []
  300. configs = _configs
  301. deps = _rust_deps
  302. public_deps = _rust_public_deps
  303. rustflags = _rustflags
  304. rustflags += [ string_join("",
  305. [
  306. "-Cmetadata=",
  307. _metadata,
  308. ]) ]
  309. rustenv = _rustenv
  310. rustenv += [ "OUT_DIR=" + rebase_path(_out_dir) ]
  311. # The Rust tool() declarations, like C++ ones, use the output_name and
  312. # output_dir, so that GN targets can override these if needed. Here we
  313. # give them their default values, or allow them to be overridden.
  314. output_dir = _out_dir
  315. if (!defined(output_name) || output_name == "") {
  316. output_name = crate_name
  317. }
  318. }
  319. if (_cxx_bindings != []) {
  320. rust_autocxx("${_target_name}_autocxx_generated") {
  321. testonly = _testonly
  322. visibility = [ ":${_target_name}${_main_target_suffix}" ]
  323. if (defined(_visibility)) {
  324. visibility += _visibility
  325. }
  326. sources = _cxx_bindings
  327. deps = _autocxx_deps
  328. configs = _configs
  329. if (is_component_build) {
  330. # In a component_build the cxx bindings may be linked into a shared
  331. # library at any point up the dependency tree, so always export.
  332. export_symbols = true
  333. } else if (invoker.target_type == "shared_library") {
  334. export_symbols = true
  335. } else {
  336. export_symbols = false
  337. }
  338. }
  339. } else {
  340. not_needed([
  341. "_autocxx_deps",
  342. "_mutually_dependent_public_deps",
  343. ])
  344. }
  345. if (_build_unit_tests) {
  346. _unit_test_target = "${_target_name}_unittests"
  347. if (defined(invoker.unit_test_target)) {
  348. _unit_test_target = invoker.unit_test_target
  349. }
  350. rust_unit_test(_unit_test_target) {
  351. forward_variables_from(invoker, [ "sources" ])
  352. testonly = true
  353. crate_root = _crate_root
  354. rustflags = _rustflags
  355. output_dir = _out_dir
  356. deps = _rust_deps + _public_deps
  357. if (defined(invoker.test_deps)) {
  358. deps += invoker.test_deps
  359. }
  360. inputs = []
  361. if (defined(invoker.inputs)) {
  362. inputs += invoker.inputs
  363. }
  364. if (defined(invoker.test_inputs)) {
  365. inputs += invoker.test_inputs
  366. }
  367. if (defined(_mutually_dependent_target)) {
  368. # This routes through the C++ mixed target rule to get back to the
  369. # Rust $_target_name.
  370. public_deps = [ _mutually_dependent_target ]
  371. } else {
  372. public_deps = [ ":${_target_name}" ]
  373. }
  374. if (defined(invoker.executable_configs)) {
  375. configs = []
  376. configs = invoker.executable_configs
  377. }
  378. rustenv = _rustenv
  379. }
  380. } else {
  381. not_needed([
  382. "_crate_root",
  383. "_crate_name",
  384. "_metadata",
  385. "_mutually_dependent_target",
  386. ])
  387. }
  388. }
  389. }
  390. set_defaults("rust_target") {
  391. executable_configs = default_executable_configs
  392. library_configs = default_compiler_configs
  393. }