1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
|
# Copyright 2021 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# This file provides the Rust standard library for GN targets.
#
# For Rust targets, it either copies a prebuilt stdlib or builds a stdlib, and
# then points rustc to it with `--sysroot`.
#
# When linking it ensures the libraries (and their C library dependencies) are
# part of the linker line. If Rust drives the linking, this is redundant but if
# Clang drives the linking it is required.
#
# Part of the standard library provided here is "remap_alloc" which maps
# allocator functions to PartitionAlloc when `use_partition_alloc_as_malloc` is
# true, so that Rust and C++ use the same allocator backend.
import("//build/config/compiler/compiler.gni")
import("//build/config/coverage/coverage.gni")
import("//build/config/rust.gni")
import("//build/config/sanitizers/sanitizers.gni")
if (toolchain_has_rust) {
# List of Rust stdlib rlibs which are present in the official Rust toolchain
# we are using from the Android team. This is usually a version or two behind
# nightly. Generally this matches the toolchain we build ourselves, but if
# they differ, append or remove libraries based on the
# `use_chromium_rust_toolchain` GN variable.
#
# If the build fails due to missing symbols, it would be because of a missing
# library that needs to be added here in a newer stdlib.
stdlib_files = [
"std", # List first because it makes depfiles more debuggable (see below)
"alloc",
"cfg_if",
"compiler_builtins",
"core",
"getopts",
"hashbrown",
"panic_abort",
"panic_unwind",
"rustc_demangle",
"std_detect",
"test",
"unicode_width",
"unwind",
]
if (!is_win) {
# These are no longer present in the Windows toolchain.
stdlib_files += [
"addr2line",
"adler",
"gimli",
"libc",
"memchr",
"miniz_oxide",
"object",
]
}
if (toolchain_for_rust_host_build_tools) {
# When building proc macros, include the proc_macro crate in what should be
# copied with find_stdlib. Otherwise it is not copied since it will be
# unused.
stdlib_files += [ "proc_macro" ]
}
# Different Rust toolchains may add or remove files relative to the above
# list. That can be specified in gn args for anyone using (for instance)
# nightly or some other experimental toolchain, prior to it becoming official.
stdlib_files -= removed_rust_stdlib_libs
stdlib_files += added_rust_stdlib_libs
# rlib files which are distributed alongside Rust's prebuilt stdlib, but we
# don't need to pass to the C++ linker because they're used for specialized
# purposes.
skip_stdlib_files = [
"profiler_builtins",
"rustc_std_workspace_alloc",
"rustc_std_workspace_core",
"rustc_std_workspace_std",
]
config("stdlib_dependent_libs") {
# TODO(crbug.com/40264561): These should really be `libs`, however that
# breaks. Normally, we specify lib files with the `.lib` suffix but
# then when rustc links an EXE, it invokes lld-link with `.lib.lib`
# instead.
#
# Omitting the `.lib` suffix breaks linking as well, when clang drives
# the linking step of a C++ EXE that depends on Rust.
if (is_win) {
# The libc crate tries to link in the Windows CRT, but we specify the CRT
# library ourselves in //build/config/win:dynamic_crt and
# //build/config/win:static_crt because Rustc does not allow us to specify
# using the debug CRT: https://github.com/rust-lang/rust/issues/39016
#
# As such, we have disabled all #[link] directives from the libc crate,
# and we need to add any non-CRT libs here.
ldflags = [ "legacy_stdio_definitions.lib" ]
}
}
config("stdlib_public_dependent_libs") {
# TODO(crbug.com/40264561): These should really be `libs`, however that
# breaks. Normally, we specify lib files with the `.lib` suffix but
# then when rustc links an EXE, it invokes lld-link with `.lib.lib`
# instead.
#
# Omitting the `.lib` suffix breaks linking as well, when clang drives
# the linking step of a C++ EXE that depends on Rust.
if (is_win) {
# These libs provide functions that are used by the stdlib. Rust crates
# will try to link them in with #[link] directives. However these don't
# get propagated to the linker if Rust isn't driving the linking (a C++
# target that depends on a Rust rlib). So these need to be specified
# explicitly.
ldflags = [
"advapi32.lib",
"bcrypt.lib",
"kernel32.lib",
"ntdll.lib",
"synchronization.lib",
"userenv.lib",
"ws2_32.lib",
]
}
# From rust/library/std/src/sys/unix/mod.rs.
#
# libs = [ "System" ] (meaning /usr/lib/libSystem.B.dylib) is intentionally
# omitted here on Apple platforms, because the linker driver is responsible
# for adding it, much like libc on most other POSIX platforms. It can be
# ordering-sensitive, and including it here can alter its order relative to
# other libraries. https://crbug.com/367764848 is an example of a bug caused
# by specifying libSystem too early.
#
# TODO(danakj): We should generate this list somehow when building or
# rolling the Rust toolchain?
if (is_android) {
libs = [ "dl" ]
} else if (target_os == "freebsd") {
libs = [
"execinfo",
"pthread",
]
} else if (target_os == "netbsd") {
libs = [
"rt",
"pthread",
]
} else if (is_ios) {
libs = [ "objc" ]
frameworks = [
"Security.framework",
"Foundation.framework",
]
} else if (is_fuchsia) {
libs = [
"zircon",
"fdio",
]
}
}
# Construct sysroots for rustc invocations to better control what libraries
# are linked. We have two: one with copied prebuilt libraries, and one with
# our locally-built std. Both reside in root_out_dir: we must only have one of
# each per GN toolchain anyway.
sysroot_lib_subdir = "lib/rustlib/$rust_abi_target/lib"
if (!rust_prebuilt_stdlib) {
local_rustc_sysroot = "$root_out_dir/local_rustc_sysroot"
# All std targets starting with core build with our sysroot. It starts empty
# and is incrementally built. The directory must exist at the start.
generated_file("empty_sysroot_for_std_build") {
outputs = [ "$local_rustc_sysroot/$sysroot_lib_subdir/.empty" ]
contents = ""
visibility = [ ":*" ]
}
# Target to be depended on by std build targets. Creates the initially empty
# sysroot.
group("std_build_deps") {
deps = [ ":empty_sysroot_for_std_build" ]
public_configs = [ ":local_stdlib_sysroot" ]
visibility = [ "rules:*" ]
}
profiler_builtins_crates = [
"core",
"compiler_builtins",
"profiler_builtins",
]
# When using instrumentation, profiler_builtins and its deps must be built
# before other std crates. Other crates depend on this target so they are
# built in the right order.
group("profiler_builtins_group") {
deps = []
foreach(libname, profiler_builtins_crates) {
deps += [ "rules:$libname" ]
}
visibility = [ "rules:*" ]
}
config("local_stdlib_sysroot") {
sysroot = rebase_path(local_rustc_sysroot, root_build_dir)
rustflags = [ "--sysroot=$sysroot" ]
visibility = [ ":*" ]
}
# Builds and links against the Rust stdlib. Both Rust and C++ targets should
# depend on this, as it provides the path to the library and includes the
# allocator hooks.
group("std") {
assert(toolchain_has_rust,
"Some C++ target is depending on Rust code even though " +
"toolchain_has_rust=false. Usually this would mean" +
"a NaCl target is depending on Rust, as there's no Rust " +
"toolchain targetting NaCl.")
all_dependent_configs = [
":stdlib_public_dependent_libs",
":local_stdlib_sysroot",
":stdlib_dependent_libs",
]
deps = []
foreach(libname, stdlib_files + skip_stdlib_files) {
deps += [ "rules:$libname" ]
}
}
} else {
action("find_stdlib") {
# Collect prebuilt Rust libraries from toolchain package and copy to a
# known location.
#
# The Rust toolchain contains prebuilt rlibs for the standard library and
# its dependencies. However, they have unstable names: an unpredictable
# metadata hash is appended to the known crate name.
#
# We must depend on these rlibs explicitly when rustc is not in charge of
# linking. However, it is difficult to construct GN rules to do so when
# the names can't be known statically.
#
# This action copies the prebuilt rlibs to a known location, removing the
# metadata part of the name. In the process it verifies we have all the
# libraries we expect and none that we don't. A depfile is generated so
# this step is re-run when any libraries change. The action script
# additionally verifies rustc matches the expected version, which is
# unrelated but this is a convenient place to do so.
#
# The action refers to `stdlib_files`, `skip_stdlib_files`, and the
# associated //build/config/rust.gni vars `removed_rust_stdlib_libs` and
# `added_rust_stdlib_libs` for which rlib files to expect.
# `extra_sysroot_libs` is also used to copy non-std libs, if any.
script = "find_std_rlibs.py"
depfile = "$target_out_dir/stdlib.d"
out_libdir = rebase_path(target_out_dir, root_build_dir)
out_depfile = rebase_path(depfile, root_build_dir)
# For the rustc sysroot we must include even the rlibs we don't pass to
# the C++ linker.
all_stdlibs_to_copy = stdlib_files + skip_stdlib_files
args = [
"--rust-bin-dir",
rebase_path("${rust_sysroot}/bin", root_build_dir),
"--output",
out_libdir,
"--depfile",
out_depfile,
# Due to limitations in Ninja's handling of .d files, we have to pick
# *the first* of our outputs. To make diagnostics more obviously
# related to the Rust standard library, we ensure libstd.rlib is first.
"--depfile-target",
stdlib_files[0],
# Create a dependency on the rustc version so this action is re-run when
# it changes. This argument is not actually read by the script.
"--rustc-revision",
rustc_revision,
]
if (extra_sysroot_libs != []) {
args += [
"--extra-libs",
string_join(",", extra_sysroot_libs),
]
}
args += [
"--target",
rust_abi_target,
]
outputs = []
foreach(lib, all_stdlibs_to_copy) {
outputs += [ "$target_out_dir/lib$lib.rlib" ]
}
foreach(lib, extra_sysroot_libs) {
outputs += [ "$target_out_dir/$lib" ]
}
visibility = [ ":*" ]
}
prebuilt_rustc_sysroot = "$root_out_dir/prebuilt_rustc_sysroot"
copy("prebuilt_rustc_copy_to_sysroot") {
assert(enable_rust,
"Some C++ target is including Rust code even though " +
"enable_rust=false")
deps = [ ":find_stdlib" ]
sources = get_target_outputs(":find_stdlib")
outputs =
[ "$prebuilt_rustc_sysroot/$sysroot_lib_subdir/{{source_file_part}}" ]
visibility = [ ":*" ]
}
config("prebuilt_stdlib_sysroot") {
# Match the output directory of :prebuilt_rustc_copy_to_sysroot
sysroot = rebase_path(prebuilt_rustc_sysroot, root_build_dir)
rustflags = [ "--sysroot=$sysroot" ]
visibility = [ ":*" ]
}
config("prebuilt_stdlib_libs") {
ldflags = []
lib_dir = rebase_path("$prebuilt_rustc_sysroot/$sysroot_lib_subdir",
root_build_dir)
# We're unable to make these files regular gn dependencies because
# they're prebuilt. Instead, we'll pass them in the ldflags. This doesn't
# work for all types of build because ldflags propagate differently from
# actual dependencies and therefore can end up in different targets from
# the remap_alloc.cc above. For example, in a component build, we might
# apply the remap_alloc.cc file and these ldlags to shared object A,
# while shared object B (that depends upon A) might get only the ldflags
# but not remap_alloc.cc, and thus the build will fail. There is
# currently no known solution to this for the prebuilt stdlib - this
# problem does not apply with configurations where we build the stdlib
# ourselves, which is what we'll use in production.
foreach(lib, stdlib_files) {
this_file = "$lib_dir/lib$lib.rlib"
ldflags += [ this_file ]
}
visibility = [ ":*" ]
}
group("std") {
all_dependent_configs = [
":prebuilt_stdlib_libs",
":stdlib_public_dependent_libs",
]
deps = [ ":prebuilt_rustc_copy_to_sysroot" ]
}
}
}
|