This post proposes to replicate some .cargo/config.toml
settings in Cargo.toml
files. This way, we no longer need to use file system dependent config files for crate-specific settings.
Introduction
The behavior of Cargo can be configured through configuration files named .cargo/config
or .cargo/config.toml
. In contrast to Cargo.toml
files, which specify properties of a Rust crate, these configuration files are only based on the file system hierarchy. This means that any .cargo/config
file applies to all subdirectories of the current folder as well. If multiple config files are found in the hierarchy, their values are merged together.
The following things can be configured through configuration files:
- path overrides
-
custom command aliases, e.g.
cargo rr
forcargo run --release
-
build parameters, e.g. the number of parallel build jobs or additional flags that should be passed to
rustc
-
behavior of
cargo new
, including the author name and email - HTTP behavior, e.g. proxy configuration and SSL version
- install location for
cargo install
- general network configuration, e.g. the number of retries
- profile configuration, e.g. to enable debug info in release builds
- specification of alternate registries, including source replacements
- target specific settings, e.g. setting a runner binary
- configuration of terminal output e.g. whether to use colors
- unstable command-line features
The Problem
While there are some config keys that only affect the cargo
executable itself, many keys also affect crate/package builds in some way. For example, many projects use the build.rustflags
key to pass additional package-specific flags to rustc
. This is problematic because config files are completely package-agnostic and only depend on the file system hierarchy and the current working directory. Thus, a build.rustflags
key might not be applied (if the build is started from a different working directory) or accidentally change the build of a completely unrelated package (if the current working directory contains a config file). The hierarchical merging of config files makes this problem even worse since each config file applies to all subdirectories.
These problems were already reported many times. See the Problems of .cargo/config
files and possible solutions thread on the internals forum for an overview.
Possible Solutions
One possible solution would be to change the behavior of config files, as proposed by josh. Instead of depending on the current working directory, Cargo would choose the config file from the package/workspace that is being compiled. Hierarchical merging would be disabled, with exception of the global configuration file in $HOME
. The problem of this approach is that such a change is not backwards compatible and thus requires a migration period of some sort.
In this document, I want to view the problem from a different angle and propose an alternative solution: The problem isn't that cargo config files are package-agnostic in itself, but that projects are using package-agnostic config files for package-specific configuration. Instead of changing how cargo config files work, I think it makes more sense to move the package-specific configuration to the package related config file we already have: the Cargo.toml
.
Proposal
My impression is that must people only use cargo config files because there is no better way to specify their settings. For example, passing additional package-specific arguments to rustc
is not possible without a .cargo/config
file. Setting a default target for a WASM crate is not possible without a .cargo/config
file either. I'm sure that most people would prefer Cargo.toml
options, if such options were available.
Not all .cargo/config
settings are relevant in Cargo.toml
files, of course. Some of them are clearly package-agnostic, so that .cargo/config
files are the perfect place for them. Many others, however, would be useful to be available in Cargo.toml
too. Below I evaluated all available .cargo/config
options for this:
Option | Might be package-specific, i.e. would make sense in Cargo.toml
|
Why? | PR |
---|---|---|---|
paths | Behavior already available through [patch] section, see Overriding Dependencies - The Cargo Book
|
||
alias | () | doesn't affect the build, but allow shortening package-specific commands | |
build.jobs | should not affect build result | ||
build.rustc | () | are there projects that require a custom rustc binary? |
|
build.rustc-wrapper | () | are there projects that require a custom rustc wrapper? |
|
build.rustdoc | () | are there projects that require a custom rustdoc binary? |
|
build.target | e.g. projects targeting a specific architecture such as WASM or embedded | #9030 | |
build.target-dir | () | maybe to incorporate a package with other build systems? | |
build.rustflags | for package-specific flags | ||
build.rustdocflags | for package-specific flags | ||
build.incremental | () | are there projects that don't work with incremental? | |
build.dep-info-basedir | () | for third-party build systems? | |
build.pipelining | should not affect build result | ||
cargo-new | package-agnostic | ||
http | package-agnostic | ||
install | package-agnostic | ||
net | package-agnostic | ||
profile.<name> |
clearly build-related; most of these settings are already available in Cargo.toml
|
||
registries/registry | () | affects the dependencies of a crate? | |
source | () | affects the dependencies of a crate? | |
target | affects how a crate is built or run | ||
term | only affects cargo output |
||
unstable | most unstable options are either already available in Cargo.toml (e.g. metabuild ) or package-agnostic (e.g. -Z no-index-update ); there are a few exceptions, though: |
||
unstable.build-std | always required for packages built for custom targets | #10308 | |
unstable.build-std-features | affects how a package is built | ||
unstable.doctest-xcompile | required for running doctest of packages built for custom targets | ||
unstable.panic-abort-tests | some tests might only work with this flag |
(I'm happy to discuss and correct this classification!)
(Edit (2022-01-20): Updated the table with a new pull request column)
We see that only a subset of .cargo/config
keys can be package-specific (the keys marked with ). I propose to replicate all these config keys in Cargo.toml
files, so that users can decide which file they use (package-dependent or package-agnostic). This way, we can solve most problems that people currently have with config files in a fully backwards compatible way.
The replicated config keys are not removed from .cargo/config
files. Users can still use them to override the setting specified in Cargo.toml
files, like it is already the case for the [profile]
table.
Challenges
(I don't know much about cargo's internals, so please let me know if something is missing or wrong.)
- The packages of a workspace might have different
build.target
fields after this change. Cargo needs to be able to handle this oncargo build --workspace
, i.e. build the packages for different targets.- Cargo aready supports compiling for multiple targets at once, so this should be doable.
- Similarly, the packages of a workspace might have different
build.rustflags
/build.rustdocflags
, which might impose some challenges when sharing compilation artifacts across packages in a workspace.
Drawbacks
- Since the old configuration options are still present in
.cargo/config
files, there are now two places for configuration, which could lead to confusion.- Clear documentation could mitigate the confusion
- Over time we can deprecate any
.cargo/config
keys that are no longer needed
Alternatives
- Change behavior
.cargo/config
files to disable hierarchical merging and look at package root instead of current working directory. This would be backwards-incompatible and introduce a lot of churn. - In addition to the proposed changes, remove the new
Cargo.toml
keys from.cargo/config
files so that there is only one place to define things. However, this also has drawbacks:- Not backwards compatible
- Users might want to set some keys in a package-agnostic way, e.g. turn on
--verbose
for allrustc
invocations viabuild.rustflags