summaryrefslogtreecommitdiff
path: root/chromium/build/rust/std/BUILD.gn
blob: a5a922b6c143879ed68ac73b1a2a6285b0a843b3 (plain)
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
# 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 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",
    ]
  }
}