BUILD.gn 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  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. # This file provides the ability for our C++ toolchain to successfully
  5. # link binaries containing arbitrary Rust code.
  6. #
  7. # By "arbitrary Rust code" I mean .rlib archives full of Rust code, which
  8. # is actually a static archive.
  9. #
  10. # Those static libraries don't link as-is into a final executable because
  11. # they're designed for downstream processing by further invocations of rustc
  12. # which link into a final binary. That final invocation of rustc knows how
  13. # to do two things:
  14. # * Find the Rust standard library.
  15. # * Remap some generic allocator symbols to the specific allocator symbols
  16. # in use.
  17. # This file does both those things. Any C++ target containing Rust .rlibs
  18. # should simply depend on :std within this file and it will be taken care of.
  19. # In practice, this will in future be taken care of by a standard template
  20. # used for each Rust source set, so that a typical user of Rust need not
  21. # think about it.
  22. #
  23. # This is obviously a bit fragile - rustc might do other magic in future.
  24. # But, linking with a final C++ toolchain is something often needed, and
  25. # https://github.com/rust-lang/rust/issues/64191 aims to make this
  26. # officially possible.
  27. import("//build/config/compiler/compiler.gni")
  28. import("//build/config/rust.gni")
  29. if (toolchain_has_rust) {
  30. # List of Rust stdlib rlibs which are present in the official
  31. # Rust toolchain we are using from the Android team. This is usually
  32. # a version or two behind nightly.
  33. # See //docs/security/rust-toolchain.md#building-on-non_linux-platforms
  34. # for how to maintain this list.
  35. stdlib_files = [
  36. "std", # List first because it makes depfiles more debuggable (see below)
  37. "addr2line",
  38. "adler",
  39. "alloc",
  40. "cfg_if",
  41. "compiler_builtins",
  42. "core",
  43. "getopts",
  44. "gimli",
  45. "hashbrown",
  46. "libc",
  47. "memchr",
  48. "miniz_oxide",
  49. "object",
  50. "panic_abort",
  51. "panic_unwind",
  52. "proc_macro",
  53. "rustc_demangle",
  54. "std_detect",
  55. "test",
  56. "unicode_width",
  57. "unwind",
  58. ]
  59. # Different Rust toolchains may add or remove files relative to the above
  60. # list. That can be specified in gn args for anyone using (for instance)
  61. # nightly or some other experimental toolchain, prior to it becoming official.
  62. stdlib_files -= removed_rust_stdlib_libs
  63. stdlib_files += added_rust_stdlib_libs
  64. if (!use_unverified_rust_toolchain) {
  65. # rlib files which are distributed alongside Rust's prebuilt stdlib, but we
  66. # don't need to pass to the C++ linker because they're used for specialized
  67. # purposes.
  68. skip_stdlib_files = [
  69. "profiler_builtins",
  70. "rustc_std_workspace_alloc",
  71. "rustc_std_workspace_core",
  72. "rustc_std_workspace_std",
  73. ]
  74. }
  75. action("find_stdlib") {
  76. # Specifics of what we're doing here.
  77. #
  78. # We are using prebuilt Rust rlibs supplied along with the toolchain.
  79. # The Rust standard library consists of rlibs with roughly all the names
  80. # above.
  81. #
  82. # However, their filenames are not predictable, and therefore we can't
  83. # have ninja rules which depend upon them. (gn offers a facility to
  84. # build rules dynamically, but it's frowned upon because a script needs
  85. # to run each time).
  86. #
  87. # Instead therefore we copy these unpredictable .rlib paths to apredictable
  88. # location. That's what this script does. Furthermore, it generates a
  89. # .d file in order to teach Ninja that it only needs to do this copying
  90. # once, unless the source .rlibs change.
  91. #
  92. # The script accepts the list of known libraries and will raise an
  93. # exception if the list on disk differs. (Either 'Found stdlib rlib
  94. # that wasn't expected' or 'We failed to find all expected stdlib
  95. # rlibs').
  96. #
  97. # The script does one final job, which is to check that the rustc
  98. # version matches that in the gn arg 'rustc_version'. This is
  99. # technically orthogonal to the stdlib-finding job that we do here,
  100. # but it's something we want to be sure of running during any
  101. # typical Rust build, and this target happens to be depended upon
  102. # almost everywhere, so it's a good fit.
  103. script = "find_std_rlibs.py"
  104. depfile = "$target_out_dir/stdlib.d"
  105. out_libdir = rebase_path(target_out_dir, root_build_dir)
  106. out_depfile = rebase_path(depfile, root_build_dir)
  107. args = [
  108. "--rust-bin-dir",
  109. rebase_path("${rust_sysroot}/bin", root_build_dir),
  110. "--output",
  111. out_libdir,
  112. "--depfile",
  113. out_depfile,
  114. # Due to limitations in Ninja's handling of .d files, we have to pick
  115. # *the first* of our outputs. To make diagnostics more obviously
  116. # related to the Rust standard library, we ensure libstd.rlib is first.
  117. "--depfile-target",
  118. stdlib_files[0],
  119. "--expected-rustc-version",
  120. rustc_version,
  121. ]
  122. if (!use_unverified_rust_toolchain) {
  123. args += [
  124. "--stdlibs",
  125. string_join(",", stdlib_files),
  126. "--skip",
  127. string_join(",", skip_stdlib_files),
  128. ]
  129. }
  130. if (rust_abi_target != "") {
  131. args += [
  132. "--target",
  133. rust_abi_target,
  134. ]
  135. }
  136. outputs = []
  137. foreach(lib, stdlib_files) {
  138. outputs += [ "$target_out_dir/lib$lib.rlib" ]
  139. }
  140. }
  141. config("rust_stdlib_config") {
  142. ldflags = []
  143. out_libdir = rebase_path(target_out_dir, root_build_dir)
  144. foreach(lib, stdlib_files) {
  145. this_file = "$out_libdir/lib$lib.rlib"
  146. ldflags += [ this_file ]
  147. }
  148. }
  149. source_set("remap_alloc") {
  150. sources = [
  151. "immediate_crash.h",
  152. "remap_alloc.cc",
  153. ]
  154. }
  155. group("std") {
  156. assert(
  157. enable_rust,
  158. "Some C++ target is including Rust code even though enable_rust=false")
  159. all_dependent_configs = [ ":rust_stdlib_config" ]
  160. deps = [
  161. ":find_stdlib",
  162. ":remap_alloc",
  163. ]
  164. }
  165. }