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