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.
The behavior of Cargo can be configured through configuration files named
.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 run --release
build parameters, e.g. the number of parallel build jobs or additional flags that should be passed to
cargo new, including the author name and email
- HTTP behavior, e.g. proxy configuration and SSL version
- install location for
- 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
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.
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
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.
.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
|paths||Behavior already available through
|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
|build.rustc-wrapper||()||are there projects that require a custom
|build.rustdoc||()||are there projects that require a custom
|build.target||e.g. projects targeting a specific architecture such as WASM or embedded|
|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|
||clearly build-related; most of these settings are already available in
|registries/registry||()||affects the dependencies of a crate?|
|source||()||affects the dependencies of a crate?|
|target||affects how a crate is built or run|
|unstable||most unstable options are either already available in
|unstable.build-std||always required for packages built for custom targets|
|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!)
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
(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.targetfields after this change. Cargo needs to be able to handle this on
cargo 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.rustdocflags, which might impose some challenges when sharing compilation artifacts across packages in a workspace.
- Since the old configuration options are still present in
.cargo/configfiles, 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/configkeys that are no longer needed
- Change behavior
.cargo/configfiles 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/configfiles 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