| # 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", |
| ] |
| } |
| } |