Rust Build Errors Guide

This document lists Rust-related build errors that are noteworthy in the context of Chromium builds.

Unsafe Rust

Chromium builds disallow unsafe Rust by default. Unexpected unsafe Rust can cause build errors below:

error: usage of an `unsafe` block
error: declaration of an `unsafe` function
error: implementation of an `unsafe` trait
error: implementation of an `unsafe` method
...
note: requested on the command line with `-F unsafe-code`

unsafe Rust is disallowed by default to:

  • Discourage using unsafe Rust code
  • Make code reviews easier (e.g. //third_party/rust crates with allow_unsafe = false can get a bit less scrutiny).

To fix the errors above you can either:

  • Express the same code in safe Rust if possible (e.g. using slice[i] or slice.get(i) rather than slice.get_unchecked(i), unless disassembly results show that the compiler cannot elide the checks and/or performance measurements show significant runtime difference)
  • Allow unsafe code in the given crate (ideally only for a small, easy-to-reason-about crate that encapsulates the unsafety behind a safe public API).
    • In manually-authored BUILD.gn files (e.g. in first-party code) you can set allow_unsafe = true in rust_static_library
    • In gnrt-generated BUILD.gn files you can set extra_kv.allow_unsafe property to true in third_party/rust/chromium_crates_io/gnrt_config.toml (and then regenerate BUILD.gn with tools/crates/run_gnrt.py gen).

Unstable features

Chromium builds require an explicit opt-in to use unstable Rust features (see the policy in //tools/rust/unstable_rust_feature_usage.md). Unexpected usage of unstable Rust features can cause build errors below:

error[E0725]: the feature `feature_name` is not in the list of allowed features
error[E0658]: use of unstable library feature `feature_name`
...
note: see issue #XXXXX <https://github.com/rust-lang/rust/issues/XXXXX> for more information
help: add `#![feature(feature_name)]` to the crate attributes to enable

To opt into allowing certain unstable features, you need to:

  • Opt into allowing an unstable feature in the BUILD.gn of a Rust crate (justifying edits to the policy in //tools/rust/unstable_rust_feature_usage.md as needed)
    • In manually-authored BUILD.gn files (e.g. in first-party code) you can set the following properties of rust_static_library:
      • rustflags = [ "-Zallow-features=feature_name" ]
      • configs -= [ "//build/config/compiler:disallow_unstable_features" ]
    • In gnrt-generated BUILD.gn files you can set extra_kv.allow_unstable_features property in third_party/rust/chromium_crates_io/gnrt_config.toml to the list of allowed feature names (and then regenerate BUILD.gn with tools/crates/run_gnrt.py gen).
  • Opt into allowing an unstable feature in the root module of a Rust crate. To do this add #![feature(feature_name)] to lib.rs. See also:

Missing sources

gn and ninja know about build target inputs and sources through input and/or sources properties specified in BUILD.gn files. rustc independently discovers all .rs files by starting from a crate root, and then following mod foo; declarations. Chromium build will report an error when those 2 sources of information are out of sync - for example:

ERROR: Rust source file or input not in GN sources: ../../foo/bar/baz.rs

To fix errors like the one above you should ensure that the BUILD.gn lists the same source files and inputs as the ones actually used in .rs source code:

  • In manually-authored BUILD.gn files (e.g. in first-party code) you should double-check the sources property (or the inputs property in less common cases like when using include! macro).
    • TODO(lukasza): Figure out if/why it matters whether an .rs or .rs.incl file is listed in sources vs inputs.
  • In gnrt-generated BUILD.gn files, gnrt typically can discover all .rs files on its own, but sometimes gnrt may need extra crate metadata that you can provide via gnrt_config.toml - for example:
    • extra_src_roots (or extra_input_roots) can list source files to append to sources (or inputs) for the main Rust target
    • extra_build_script_src_roots (or extra_build_script_input_roots) can list sources files to append to sources (or inputs) for the build.rs script
    • See a comment at the top of gnrt_config.toml for more information
    • After editing gnrt_config.toml run tools/crates/run_gnrt.py gen to regenerate BUILD.gn files.

Can't find and include build.rs output

Third-party crates may depend on build.rs output - typically through include! of one or more files from the env!("OUT_DIR") directory. If gn and ninja are not aware of these build.rs outputs, then it may lead to build errors like the one:

   --> ../../third_party/rust/chromium_crates_io/vendor/rustversion-v1/src/lib.rs:217:30
    |
217 | const RUSTVERSION: Version = include!(concat!(env!("OUT_DIR"), "/version.expr"));
    |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ in this macro invocation
    |
   --> library/core/src/macros/mod.rs:1487:4
    |
    = note: in this expansion of `include!`

To fix the error above:

  • check if build_script_outputs in gnrt_config.toml lists all build.rs outputs.
    • See a comment at the top of gnrt_config.toml for more information
    • After editing gnrt_config.toml run tools/crates/run_gnrt.py gen to regenerate BUILD.gn files.

Dependency not visible to an internal Rust target

Rust target templates like rust_static_library("some_target") internally expand into multiple smaller targets (e.g. a rust_library for invoking rustc, an action for invoking clippy-driver, cxx-supporting targets, etc.). This may cause gn gen errors when a dependency is exposed to the main target (e.g. ":some_target"), but not to the internal targets (e.g. ":some_target_clippy" or ":some_target_generator").

Example error:

$ gn gen out/Default
ERROR at //build/rust/gni_impl/rust_target.gni:587:9: Dependency not allowed.
        action("${_clippy_target_name}") {
        ^---------------------------------
The item //foo/bar:some_target_clippy
can not depend on //foo/bar:internal_impl
because it is not in //foo/bar:internal_impl's visibility list: [
  //foo/bar:internal_target1
  //foo/bar:internal_target2
]

To fix the error above, we recommend the following approach to visibility declarations in BUILD.gn files:

  • Public targets should use unrestricted visibility
  • Private targets should restrict their visibility to specific directories - e.g. visibility = [ ":*" ]
  • Avoid restricting target visibility to specific, individual targets - e.g. do not say visibility = [ ":some_target" ].

Note: Other fix approaches have been discussed with @gn-dev here.