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