Clone this repo:

Branches

  1. 8ef41db Disable licenses for Pigweed GN by Jiacheng Lu · 8 weeks ago main
  2. a7675e3 Remove $host_toolchain from proc_macro rule by Jiacheng Lu · 8 weeks ago
  3. e20efa1 Move edition from rustflags to an attribute by Jiacheng Lu · 8 weeks ago
  4. db66e16 Add templates_pw for Pigweed GN by Jiacheng Lu · 8 weeks ago
  5. 68ad8a0 Commit Cargo.lock to pin down the dep versions by Jiacheng Lu · 9 weeks ago

Cargo GNaw

Tooling to convert Cargo.toml files into native GN rules

crates.io license docs.rs cargo-gnaw

Install

$ cargo install --path ~/cargo-gnaw

Run

$ cargo gnaw --manifest-path ~/fuchsia/third_party/rust_crates/Cargo.toml -o ~/fuchsia/third_party/rust_crates/BUILD.gn

Options

  • --skip-root - Skip the root package in the Cargo.toml and treat it's dependencies as the top-level targets
  • --gn-bin - Path to GN binary for formatting the output

How it works

Cargo GNaw operates on vendored crates to convert them into GN rules. The resulting BUILD.gn file is expected to be vendored with the crates and provides targets for the GN build system to reference.

All top-level crates are given an easy to use GN alias group that references the version exposed in the Cargo.toml. Direct dependencies of the root crate can be “lifted” to the top-level by skipping the default root crate.

Simple Example

[package]
name = "simple"
version = "1.0.25"
authors = ["Benjamin Brittain <bwb@google.com>"]
edition = "2018"

[dependencies]

converts to:


group("simple") { deps = [":simple-1-0-25"] } rust_library("simple-1-0-25") { crate_name = "simple" crate_root = "//tools/cargo-gnaw/src/tests/simple/src/lib.rs" output_name = "simple-9ac42213326ac72d" deps = [] rustenv = [] rustflags = ["--cap-lints=allow", "--edition=2018", "-Cmetadata=9ac42213326ac72d", "-Cextra-filename=-9ac42213326ac72d"] }

Build Scripts

GNaw intentionally does not handle build.rs scripts at compilation time. Any evaluation of a build.rs script is done when the crate is vendored. The resulting configuration which is usually produced by the build.rs script is put into a section in the source Cargo.toml. Simple build.rs scripts (ones that only depend upon Rust's std library) evaluate and automatically provide the author with the expected configuration.

Packages vs. targets vs. crates

The difference between a “package”, “target”, and a “crate” is useful knowledge when working with GNaw:

  • A Cargo “target” corresponds to source files that can be compiled into a Rust “crate”. There are multiple target types, including library and binary.
  • A Cargo “package” contains one or more “targets”, and can contain at most one library target.

(Paraphrased from https://doc.rust-lang.org/cargo/reference/cargo-targets.html)

Many Cargo packages only contain a single library target that produces a single library crate. Because of this (and because of the catchiness of the term) “crate” is often used imprecisely to refer to any of those three items depending on the context. However, when packages contain multiple targets, like one or more binaries alongside the library, it becomes important to distinguish between these terms.

GN configs

Some targets, including but not limited to those that use build.rs scripts, require additional configuration that can be specified in the Cargo.toml file. This configuration is consumed by GNaw, not Cargo, and used when generating GN targets.

Basic configuration

Basic configuration for a package's library target is specified as gn.package.<PackageName>.<ExactVersion>. This configuration will be applied to the GN library target unconditionally (for all platforms) and can include the following arrays:

  • configs - native GN config
  • deps - native GN dependency
  • env_vars - environment variables, usually used for pretending to be Cargo
  • rustflags - flags to pass through to rustc

Example

[gn.package.anyhow."1.0.25"]
rustflags = [ "--cfg=backtrace" ]

Platform-specific configuration

Configuration can also be applied to only specific platforms, for example only when building for Fuchsia or only when building for a specific host platform.

Platforms are specified in the Rust cfg format (e.g. cfg(unix)). The same four configuration fields (configs, deps, env_vars, rustflags) documented above are supported.

Example

[gn.package.foo."1.2.3".platform."cfg(target_os = \"fuchsia\")"]
configs = [ "//some:fuchsia_specific_config" ]

Generating executables for binary targets

GNaw also supports generating GN executable targets for Cargo binary targets. GNaw must be told to generate such targets; none are generated by default.

Platform-independent or -dependent configuration can be specified as well, similar to above. The same four configuration fields (configs, deps, env_vars, rustflags) documented above are supported.

In the example below, my-gn-name will become both the name of the group target to depend upon and the executable's output_name, so usages can assume output_name == target_name (and must since get_target_outputs only works within the same file).

Example

This example generates a group target named my-gn-name and an executable target that produces my-gn-name from the binary my-cargo-target target inside package my-cargo-package version 1.2.3. Also, when building for Unix this example applies an extra GN config.

[gn.package.my-cargo-package."1.2.3".binary.my-cargo-target]
output_name = "my-gn-name"
rustflags = [ "--cfg=feature" ]

[gn.package.my-cargo-package."1.2.3".binary.my-cargo-target.platform."cfg(unix)"]
configs = [ "//some:unix_specific_config" ]