123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- # Copyright 2021 The Chromium Authors. All rights reserved.
- # Use of this source code is governed by a BSD-style license that can be
- # found in the LICENSE file.
- # This file provides the ability for our C++ toolchain to successfully
- # link binaries containing arbitrary Rust code.
- #
- # By "arbitrary Rust code" I mean .rlib archives full of Rust code, which
- # is actually a static archive.
- #
- # Those static libraries don't link as-is into a final executable because
- # they're designed for downstream processing by further invocations of rustc
- # which link into a final binary. That final invocation of rustc knows how
- # to do two things:
- # * Find the Rust standard library.
- # * Remap some generic allocator symbols to the specific allocator symbols
- # in use.
- # This file does both those things. Any C++ target containing Rust .rlibs
- # should simply depend on :std within this file and it will be taken care of.
- # In practice, this will in future be taken care of by a standard template
- # used for each Rust source set, so that a typical user of Rust need not
- # think about it.
- #
- # This is obviously a bit fragile - rustc might do other magic in future.
- # But, linking with a final C++ toolchain is something often needed, and
- # https://github.com/rust-lang/rust/issues/64191 aims to make this
- # officially possible.
- import("//build/config/compiler/compiler.gni")
- import("//build/config/rust.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.
- # See //docs/security/rust-toolchain.md#building-on-non_linux-platforms
- # for how to maintain this list.
- stdlib_files = [
- "std", # List first because it makes depfiles more debuggable (see below)
- "addr2line",
- "adler",
- "alloc",
- "cfg_if",
- "compiler_builtins",
- "core",
- "getopts",
- "gimli",
- "hashbrown",
- "libc",
- "memchr",
- "miniz_oxide",
- "object",
- "panic_abort",
- "panic_unwind",
- "proc_macro",
- "rustc_demangle",
- "std_detect",
- "test",
- "unicode_width",
- "unwind",
- ]
- # 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
- if (!use_unverified_rust_toolchain) {
- # 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",
- ]
- }
- action("find_stdlib") {
- # Specifics of what we're doing here.
- #
- # We are using prebuilt Rust rlibs supplied along with the toolchain.
- # The Rust standard library consists of rlibs with roughly all the names
- # above.
- #
- # However, their filenames are not predictable, and therefore we can't
- # have ninja rules which depend upon them. (gn offers a facility to
- # build rules dynamically, but it's frowned upon because a script needs
- # to run each time).
- #
- # Instead therefore we copy these unpredictable .rlib paths to apredictable
- # location. That's what this script does. Furthermore, it generates a
- # .d file in order to teach Ninja that it only needs to do this copying
- # once, unless the source .rlibs change.
- #
- # The script accepts the list of known libraries and will raise an
- # exception if the list on disk differs. (Either 'Found stdlib rlib
- # that wasn't expected' or 'We failed to find all expected stdlib
- # rlibs').
- #
- # The script does one final job, which is to check that the rustc
- # version matches that in the gn arg 'rustc_version'. This is
- # technically orthogonal to the stdlib-finding job that we do here,
- # but it's something we want to be sure of running during any
- # typical Rust build, and this target happens to be depended upon
- # almost everywhere, so it's a good fit.
- 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)
- 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],
- "--expected-rustc-version",
- rustc_version,
- ]
- if (!use_unverified_rust_toolchain) {
- args += [
- "--stdlibs",
- string_join(",", stdlib_files),
- "--skip",
- string_join(",", skip_stdlib_files),
- ]
- }
- if (rust_abi_target != "") {
- args += [
- "--target",
- rust_abi_target,
- ]
- }
- outputs = []
- foreach(lib, stdlib_files) {
- outputs += [ "$target_out_dir/lib$lib.rlib" ]
- }
- }
- config("rust_stdlib_config") {
- ldflags = []
- out_libdir = rebase_path(target_out_dir, root_build_dir)
- foreach(lib, stdlib_files) {
- this_file = "$out_libdir/lib$lib.rlib"
- ldflags += [ this_file ]
- }
- }
- source_set("remap_alloc") {
- sources = [
- "immediate_crash.h",
- "remap_alloc.cc",
- ]
- }
- group("std") {
- assert(
- enable_rust,
- "Some C++ target is including Rust code even though enable_rust=false")
- all_dependent_configs = [ ":rust_stdlib_config" ]
- deps = [
- ":find_stdlib",
- ":remap_alloc",
- ]
- }
- }
|