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