August 15, 2019·4 min read·engineeringrustcargodependenciesoptimization

Rust 1.37 puts dependency vendoring inside Cargo

Cargo now fetches and unpacks dependency sources with a built-in vendor command. Its generated source configuration is a necessary second step, while profile-guided optimization changes how the compiler uses workload feedback.

Copying dependency source into a directory does not tell a build tool to use it. Cargo's newly integrated vendor command handles the first operation and prints the configuration needed for the second. Keeping those steps distinct explains both the command's value and the remaining responsibility of the build environment.

The August 15 Rust 1.37 announcement makes cargo vendor a built-in command after its earlier availability as a separate crate. It fetches dependencies and unpacks them into a local directory, with vendor/ as the ordinary destination. The release also adds compiler support for profile-guided optimization.

I find dependency visibility useful when evaluating how a systems project can be built and maintained. A local collection of source makes the inputs available for inspection and distribution. Explicit configuration then establishes that the build actually consumes those inputs, which is a separate fact from their presence on disk.

Vendoring includes remote source dependencies

The versioned Cargo command documentation describes vendoring crates.io and Git dependencies. It can write to a selected destination and include additional manifests. This makes it useful for more than a single directory with a few direct registry dependencies.

The basic command can use an explicit path.

cargo vendor third-party/vendor

Cargo prints configuration for using the resulting sources. That output belongs in .cargo/config, according to the command documentation. A project distributing the directory without the corresponding configuration has supplied code without necessarily changing how Cargo resolves its source locations.

The release identifies existing uses of vendoring, including shipping the Rust compiler's dependencies in release archives and committing dependencies in monorepositories. Those are examples supplied by the Rust team. They explain the distribution need without implying that every project should make the same repository choice.

The --sync option accepts extra manifests for workspaces whose dependencies should join the output. A shared vendor directory can therefore cover the inputs of more than the default manifest. Its intended scope must be supplied to the command, rather than inferred from unrelated projects elsewhere on the machine.

The command also exposes --no-delete to retain existing contents and --respect-source-config to honor source configuration while downloading. The documentation says existing source configuration is otherwise ignored by default for this operation. Those controls matter when regenerating an established vendor tree, because preserving existing files and choosing a download source are explicit behaviors.

Availability is different from lockfile freshness

The command documentation includes --locked and --frozen. Both require an up-to-date Cargo.lock, failing if it is absent or needs a change. --frozen additionally prevents network access to determine whether it is out of date. These options establish constraints around the operation rather than changing what a dependency's source code means.

Rust 1.36's offline support provides related context. Offline resolution uses locally cached dependencies and fails if required inputs would need network access. A prepopulated cache and a vendored source directory are different arrangements for local availability.

Vendoring makes source an explicit directory that can be distributed with a project. Offline mode selects an operation that cannot fetch missing data from the network. Neither arrangement should be described as automatically supplying every external input a build script might use. The release's documented guarantee concerns Cargo's dependency sources.

This distinction keeps a reproducibility claim specific. A lockfile records dependency choices, local sources supply code and source configuration directs Cargo to that code. A successful explanation of the build needs all the applicable pieces, rather than assuming one directory proves the entire environment is reproducible.

I prefer that concrete account because it gives another engineer something to verify. The source tree and configuration can be inspected together. An assertion that a project is self-contained is less useful unless it identifies which inputs are actually present and which operation uses them.

PGO feeds execution information back into compilation

The compiler's new profile-guided optimization support addresses generated code rather than dependency distribution. Rust's announcement describes a two-build process using -C profile-generate and -C profile-use. Its first build adds instrumentation, and executions of that program produce profile data.

A second build consumes the profile. The compiler can then use observed workload behavior to inform code placement, inlining and other decisions. This differs from choosing a static optimization setting without information about how the program ran.

The release supplies the mechanism, not a universal speedup figure. Profile data describes the sample executions used to produce it. A claim about the resulting application's performance would require evidence from that application, which the announcement does not provide.

The existence of a second build also matters for understanding artifacts. An instrumented program collects information for the optimization process, while the profile-using build is generated using that information. Treating the initial instrumented binary as the finished optimized result would skip the step that uses the profile.

The two features can be understood independently in a build description. Vendoring controls which dependency sources are available locally and where Cargo obtains them. Profile-guided optimization supplies execution feedback to the compiler. A project can adopt either mechanism without the release implying that the other is required, and each produces different inputs that belong in an explanation of the final executable.

Smaller changes remove specific source friction

Rust 1.37 lets enum variants be named through type aliases, including Self::Variant inside an implementation. That makes methods less dependent on repeating the enum's full name. The announcement describes this through type-relative resolution, with examples of aliases for Option<u8> and enum implementations.

Cargo also gains default-run in the package section of Cargo.toml. A package with multiple binaries can choose the default for cargo run while preserving --bin for an explicit selection. The manifest now records which executable ordinary runs should select.

These changes have narrower effects than vendoring or compiler feedback. They still make intent more visible in source and configuration. For dependency distribution, the main result is a supported command inside Cargo that materializes the sources and supplies the configuration needed to use them in subsequent builds.