| # Cargo GNaw |
| **Tooling to convert Cargo.toml files into native GN rules** |
| |
| [](https://crates.io/crates/cargo-gnaw) |
| [](https://github.com/google/cargo-gnaw/LICENSE) |
| [](https://docs.rs/crate/cargo-gnaw/) |
|  |
| |
| ## Install |
| ```sh |
| $ cargo install --path ~/cargo-gnaw |
| ``` |
| |
| ## Run |
| ```sh |
| $ 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](https://gn.googlesource.com/gn/+/HEAD/docs/reference.md) 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 |
| ```toml |
| [package] |
| name = "simple" |
| version = "1.0.25" |
| authors = ["Benjamin Brittain <bwb@google.com>"] |
| edition = "2018" |
| |
| [dependencies] |
| ``` |
| |
| converts to: |
| |
| ```gn |
| |
| 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](#gn-configs). |
| 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 |
| ```toml |
| [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 |
| ```toml |
| [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. |
| |
| ```toml |
| [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" ] |
| ``` |