• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021 The Chromium Project. 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
5import("//build/config/chrome_build.gni")
6import("//build/config/compiler/compiler.gni")
7import("//build/config/sanitizers/sanitizers.gni")
8import("//build/toolchain/toolchain.gni")
9
10if (is_android) {
11  import("//build/config/android/config.gni")
12}
13
14if (is_ios) {
15  import("//build/config/ios/config.gni")  # For `target_environment`
16  import("//build/config/ios/ios_sdk.gni")  # For `xcode_version_int`
17}
18
19declare_args() {
20  # Rust is available in the Chromium build but 3p repos that use //build may
21  # not use Rust and thus won't want to depend on having the Rust toolchain
22  # present, so this defaults to off in those cases.
23  #
24  # Chromium-based projects that are built for for architectures Chrome does not
25  # support may need to disable this as well, though they may need to replace
26  # code with C/C++ to get a functional product.
27  enable_rust = build_with_chromium
28
29  # The CXX tool is in //third_party/rust which is not shared with downstream
30  # projects yet. So they need to copy the required dependencies and GN files
31  # into their project to enable CXX there.
32  enable_cxx = build_with_chromium
33
34  # As we incrementally enable Rust on mainstream builders, we want to enable
35  # the toolchain (by switching 'enable_rust' to true) while still disabling
36  # almost all Rust features). Yet we still want to have some builders with
37  # all Rust features enabled.
38  enable_all_rust_features = false
39
40  # Chromium provides a Rust toolchain in //third_party/rust-toolchain when
41  # checkout_rust is True (which is being rolled out by default over time).
42  #
43  # To use a custom toolchain instead, specify an absolute path to the root of
44  # a Rust sysroot, which will have a 'bin' directory and others. Commonly
45  # <home dir>/.rustup/toolchains/nightly-<something>-<something>
46  rust_sysroot_absolute = ""
47
48  # If you're using a Rust toolchain as specified by rust_sysroot_absolute,
49  # set this to the output of `rustc -V`. Changing this string will cause all
50  # Rust targets to be rebuilt, which allows you to update your toolchain and
51  # not break incremental builds.
52  rustc_version = ""
53
54  # If you're using a Rust toolchain as specified by rust_sysroot_absolute,
55  # you can specify whether it supports nacl here.
56  rust_toolchain_supports_nacl = false
57
58  # Any extra std rlibs in your Rust toolchain, relative to the standard
59  # Rust toolchain. Typically used with 'rust_sysroot_absolute'
60  added_rust_stdlib_libs = []
61
62  # Any removed std rlibs in your Rust toolchain, relative to the standard
63  # Rust toolchain. Typically used with 'rust_sysroot_absolute'
64  removed_rust_stdlib_libs = []
65
66  # Non-rlib libs provided in the toolchain sysroot. Usually this is empty, but
67  # e.g. the Android Rust Toolchain provides a libunwind.a that rustc expects.
68  extra_sysroot_libs = []
69
70  # Use goma for Rust builds. Experimental. The only known problem is
71  # b/193072381, but then again, we don't expect a build speedup before much
72  # more work is done.
73  use_goma_rust = false
74
75  # Force-enable `--color=always` for rustc, even when it would be disabled for
76  # a platform. Mostly applicable to Windows, where new versions can handle ANSI
77  # escape sequences but it's not reliable in general.
78  force_rustc_color_output = false
79}
80
81# Use a separate declare_args so these variables' defaults can depend on the
82# ones above.
83declare_args() {
84  # Individual Rust components.
85
86  # Conversions between Rust types and C++ types.
87  enable_rust_base_conversions = enable_rust
88
89  # The base::JSONReader implementation. Requires base conversions.
90  enable_rust_json = enable_rust && enable_all_rust_features
91
92  # Support for chrome://crash-rust to check crash dump collection works.
93  enable_rust_crash = enable_rust
94
95  # Support for Rust mojo bindings.
96  enable_rust_mojo = enable_rust && enable_all_rust_features
97
98  # Rust gtest interop.
99  enable_rust_gtest_interop = enable_rust
100
101  # Enable Boringssl Rust bindings generation
102  enable_rust_boringssl = enable_rust && enable_all_rust_features
103
104  # Enable experimental Fontations Rust font stack.
105  use_typeface_fontations = enable_rust
106}
107
108# Use the Rust toolchain built in-tree. When false, we use the prebuilt Rust
109# stdlibs that come with the specified custom toolchain.
110use_chromium_rust_toolchain = rust_sysroot_absolute == ""
111
112# Platform support for the Rust toolchain.
113chromium_toolchain_supports_platform = !is_nacl
114custom_toolchain_supports_platform = !is_nacl || rust_toolchain_supports_nacl
115
116# Not all target triples (GN toolchains) are supported by the Rust compiler.
117# Define if we support the current GN toolchain.
118toolchain_has_rust = false
119
120# The rustc_revision is used to introduce a dependency on the toolchain version
121# (so e.g. rust targets are rebuilt, and the standard library is re-copied when
122# the toolchain changes). It is left empty for custom toolchains.
123rustc_revision = ""
124
125if (enable_rust) {
126  if (use_chromium_rust_toolchain) {
127    toolchain_has_rust = chromium_toolchain_supports_platform
128    if (toolchain_has_rust) {
129      update_rust_args = [ "--print-package-version" ]
130      rustc_revision = exec_script("//tools/rust/update_rust.py",
131                                   update_rust_args,
132                                   "trim string")
133    }
134
135    # The same as written in `config.toml.template`.
136    rust_channel = "dev"
137  } else {
138    toolchain_has_rust = custom_toolchain_supports_platform
139    rustc_revision = rustc_version
140  }
141}
142
143# TODO(crbug.com/1278030): To build unit tests for Android we need to build
144# them as a dylib and put them into an APK. We should reuse all the same logic
145# for gtests from the `//testing/test:test` template.
146can_build_rust_unit_tests = toolchain_has_rust && !is_android
147
148# Whether artifacts produced by the Rust compiler can participate in ThinLTO.
149#
150# One important consideration is whether the linker uses the same LLVM
151# version as `rustc` (i.e. if it can understand the LLVM-IR from the
152# compilation artifacts produced by `rustc`).  In LaCrOS and ash builds this may
153# not be true - see b/299483903.
154#
155# TODO(https://crbug.com/1482525): Re-enable ThinLTO for Rust on LaCrOS
156# TODO(b/300937673): Re-enable ThinLTO for Rust on ash-chrome
157toolchain_supports_rust_thin_lto = !is_chromeos
158
159# We want to store rust_sysroot as a source-relative variable for ninja
160# portability. In practice if an external toolchain was specified, it might
161# be an absolute path, but we'll do our best.
162if (enable_rust) {
163  if (use_chromium_rust_toolchain) {
164    rust_sysroot = "//third_party/rust-toolchain"
165  } else {
166    rust_sysroot = get_path_info(rust_sysroot_absolute, "abspath")
167  }
168
169  # Prebuilt toolchains won't come with bindgen, so we unconditionally use the
170  # bindgen we ship with the Rust toolchain. This could be made configurable
171  # if folks want to supply a bindgen with their toolchain.
172  rust_bindgen_root = "//third_party/rust-toolchain"
173}
174
175# Figure out the Rust target triple (aka 'rust_abi_target')
176#
177# This is here rather than in the toolchain files because it's used also by
178# //build/rust/std to find the Rust standard library and construct a sysroot for
179# rustc invocations.
180#
181# The list of architectures supported by Rust is here:
182# https://doc.rust-lang.org/nightly/rustc/platform-support.html. We map Chromium
183# targets to Rust targets comprehensively despite not having official support
184# (see '*_toolchain_supports_platform above') to enable experimentation with
185# other toolchains.
186rust_abi_target = ""
187if (is_linux || is_chromeos) {
188  if (current_cpu == "arm64") {
189    rust_abi_target = "aarch64-unknown-linux-gnu"
190  } else if (current_cpu == "x86") {
191    rust_abi_target = "i686-unknown-linux-gnu"
192  } else if (current_cpu == "x64") {
193    rust_abi_target = "x86_64-unknown-linux-gnu"
194  } else if (current_cpu == "arm") {
195    if (arm_float_abi == "hard") {
196      float_suffix = "hf"
197    } else {
198      float_suffix = ""
199    }
200    if (arm_arch == "armv7-a" || arm_arch == "armv7") {
201      # No way to inform Rust about the -a suffix.
202      rust_abi_target = "armv7-unknown-linux-gnueabi" + float_suffix
203    } else {
204      rust_abi_target = "arm-unknown-linux-gnueabi" + float_suffix
205    }
206  } else {
207    # Best guess for other future platforms.
208    rust_abi_target = current_cpu + "-unknown-linux-gnu"
209  }
210} else if (is_android) {
211  import("//build/config/android/abi.gni")
212  rust_abi_target = android_abi_target
213  if (rust_abi_target == "arm-linux-androideabi") {
214    # Android clang target specifications mostly match Rust, but this
215    # is an exception
216    rust_abi_target = "armv7-linux-androideabi"
217  }
218} else if (is_fuchsia) {
219  if (current_cpu == "arm64") {
220    rust_abi_target = "aarch64-fuchsia"
221  } else if (current_cpu == "x64") {
222    rust_abi_target = "x86_64-fuchsia"
223  } else {
224    assert(false, "Architecture not supported")
225  }
226} else if (is_ios) {
227  if (current_cpu == "arm64") {
228    if (target_environment == "simulator") {
229      rust_abi_target = "aarch64-apple-ios-sim"
230    } else if (target_environment == "catalyst") {
231      rust_abi_target = "aarch64-apple-ios-macabi"
232    } else {
233      rust_abi_target = "aarch64-apple-ios"
234    }
235  } else if (current_cpu == "arm") {
236    # There's also an armv7s-apple-ios, which targets a more recent ARMv7
237    # generation CPU found in later iPhones. We'll go with the older one for
238    # maximal compatibility. As we come to support all the different platforms
239    # with Rust, we might want to be more precise here.
240    rust_abi_target = "armv7-apple-ios"
241  } else if (current_cpu == "x64") {
242    if (target_environment == "catalyst") {
243      rust_abi_target = "x86_64-apple-ios-macabi"
244    } else {
245      rust_abi_target = "x86_64-apple-ios"
246    }
247  } else if (current_cpu == "x86") {
248    rust_abi_target = "i386-apple-ios"
249  } else {
250    assert(false, "Architecture not supported")
251  }
252} else if (is_mac) {
253  if (current_cpu == "arm64") {
254    rust_abi_target = "aarch64-apple-darwin"
255  } else if (current_cpu == "x64") {
256    rust_abi_target = "x86_64-apple-darwin"
257  } else {
258    assert(false, "Architecture not supported")
259  }
260} else if (is_win) {
261  if (current_cpu == "arm64") {
262    rust_abi_target = "aarch64-pc-windows-msvc"
263  } else if (current_cpu == "x64") {
264    rust_abi_target = "x86_64-pc-windows-msvc"
265  } else if (current_cpu == "x86") {
266    rust_abi_target = "i686-pc-windows-msvc"
267  } else {
268    assert(false, "Architecture not supported")
269  }
270}
271
272assert(!toolchain_has_rust || rust_abi_target != "")
273
274# This variable is passed to the Rust libstd build.
275rust_target_arch = ""
276if (current_cpu == "x86") {
277  rust_target_arch = "x86"
278} else if (current_cpu == "x64") {
279  rust_target_arch = "x86_64"
280} else if (current_cpu == "arm") {
281  rust_target_arch = "arm"
282} else if (current_cpu == "arm64") {
283  rust_target_arch = "aarch64"
284} else if (current_cpu == "mipsel") {
285  rust_target_arch = "mips"
286} else if (current_cpu == "mips64el") {
287  rust_target_arch = "mips64"
288} else if (current_cpu == "s390x") {
289  rust_target_arch = "s390x"
290} else if (current_cpu == "ppc64") {
291  rust_target_arch = "powerpc64"
292} else if (current_cpu == "riscv64") {
293  rust_target_arch = "riscv64"
294}
295
296assert(!toolchain_has_rust || rust_target_arch != "")
297
298# Arguments for Rust invocation.
299# This is common between gcc/clang, Mac and Windows toolchains so specify once,
300# here. This is not the complete command-line: toolchains should add -o
301# and probably --emit arguments too.
302rustc_common_args = "--crate-name {{crate_name}} {{source}} --crate-type {{crate_type}} {{rustflags}}"
303
304# Rust procedural macros are shared objects loaded into a prebuilt host rustc
305# binary. To build them, we obviously need to build for the host. Not only
306# that, but because the host rustc is prebuilt, it lacks the machinery to be
307# able to load shared objects built using sanitizers (ASAN etc.). For that
308# reason, we need to use a host toolchain that lacks sanitizers. Additionally,
309# proc macros should use panic=unwind, which means they need a stdlib that is
310# compiled the same way, as is the stdlib that we ship with the compiler.
311if (toolchain_for_rust_host_build_tools) {
312  rust_macro_toolchain = current_toolchain
313} else {
314  rust_macro_toolchain = "${host_toolchain}_for_rust_host_build_tools"
315}
316
317# When this is true, a prebuilt Rust stdlib will be used. This has implications
318# such as that the panic strategy (unwind, abort) must match how the stdlib is
319# compiled, which is typically as unwind.
320rust_prebuilt_stdlib =
321    !use_chromium_rust_toolchain || toolchain_for_rust_host_build_tools
322