Cargo configuration files (named .cargo/config
or .cargo/config.toml
) provide extensive configuration options for Cargo invocations. See the official documentation for a detailed explanation of Cargo's configuration system.
Unfortunately, there are a few general problems of configuration files in my opinion that often lead to errors and confusion in practice. This document tries to categorize and summarize these issues (as suggested by the Cargo team), with the goal of eventually resolving them. I categorized the issues into three classes: builds with --manifest-path
, hierarchical merging, and overriding config values.
Builds with --manifest-path
Cargo supports building a project in a different directory using the --manifest-path
command-line argument. Since this does not change the current working directory, it still reads the .cargo/config
files that apply to the directory that cargo was invoked from, instead of reading the config files relative to the crate that is being built. This can lead to build errors or other unexpected results.
Example
Consider the following file system layout:
foo/
.cargo/config.toml
bar/
.cargo/config.toml
Cargo.toml
src/
Imagine we are currently in directory foo
and try to build the crate in the bar
directory using cargo's --manifest-path
flag:
cargo build --manifest-path ../bar/Cargo.toml
Since the current working directory is foo
, cargo will read the foo/.cargo/config.toml
file for the build, not the bar/.cargo/config.toml
file, which would be used if we started the build from within the bar
folder.
There are basically two problems with this: First, the config values of the foo
directory are applied, which might be incompatible with the bar
crate. Second, the bar
crate might require the config values specified in its configuration for a successful build, but this file is completely ignored.
The working directory does change for the build
While not directly related, it is worth mentioning that cargo does change the current working directory to the root of the crate that is being compiled, but it only does so after parsing the configuration. For example, a relative path in a build.rs
build script will always resolve relative to the project root, even if the crate is built from a different directory using the --manifest-path
argument.
Proposed Solutions
The current behavior frequently causes problems in practice, so multiple proposals have been created to change this behavior or at least allow to customize it:
-
Cargo does not always search for .cargo/config file in project root
- Proposes to always choose config file at project root instead of depending on current working directory
- Main motivation:
--manifest-path
and--package
flags should use config of selected package - Problems:
- Breaking change
- When using different config files on
--package
: Which config should be chosen if multiple packages are built (e.g. oncargo build --workspace
)?
-
env var for original invocation directory
- Motivation: Builds with
--manifest-path
parse config of current working directory -> leads to build errors - Proposes a
CARGO_INVOCATION_PWD
make cargo change its working directory before starting the build - Problems:
- Environment variables cumbersome to use (maybe add a command-line flag too?)
- More general than it needs to be (maybe only allow changing the working directory to the crate root instead of allowing arbitrary directories?)
- Motivation: Builds with
-
Add a
--ignore-local-config
flag for ignoring local.cargo/config.toml
files- Proposal: Provide a way to completely ignore config files
- This allows builds with
--manifest-path
to at least opt-out of applying the configuration of the current working directory. - The target crate config can then be included by using the
config-include
/config-cli
features on the command line. - Exception: Still consider the
.cargo/config
file at the user's home directory, similar to the behavior ofcargo install
(for system-wide settings such asterm.color
)
- This allows builds with
- Proposal: Provide a way to completely ignore config files
Hierarchical Merging
Config files are automatically merged together with all config files in root directories. This can lead to problems because a config file in a parent directory can break the build or cause other undesired behavior.
As one example, consider a auto-generated crate created in a temporary /tmp/foo
directory. Building this crate will automatically apply a /tmp/.cargo/config.toml
file if present, which could easily have been created by another program.
Proposed Solutions
There are multiple proposals to allow disabling hierarchical merging if desired:
-
Add flag to ignore all parent directory configs
- Proposes a
--no-parent
CLI flag that disables the hierarchical merging of config files - Motivation: Cargo behaves unexpectedly because of config values set in parent directories
- Proposes a
-
Fine-grain control of Config.toml discovery
- Motivation: No way to opt-out of hierarchical merging of config files
- Proposal: Add a
CARGO_CONFIG_PATH
environment variable that explicitly specifies all the locations where Cargo is allowed to read config values from- Similar to the system's
PATH
environment variable - Completely overrides the default hierarchical config discovery
- Similar to the system's
- Problems:
- Might require changing the environment variable for every project (if different config files should be considered)
- Some config files might rely on hierarchical merging
- The
--ignore-local-config
proposal from above might be also relevant here.
Overriding Config Values
Cargo config files are very useful for setting reasonable default values for a project. For example, an embedded crate that is only buildable on a single target system might have a config file that sets build.target
so that the developer does not need to pass a --target
argument on every build.
However, there are sometimes special cases where the configured default values do not work. For example, a sub-crate might want to disable incremental compilation for some reasons.
Basic Override Support
There were the following proposals for adding basic support for overriding .cargo/config.toml
settings:
-
Proposal: Command-line config
- This was accepted and implemented in #7649
- Adds an unstable
--config
command line argument for overriding specific config values (documented here, tracked in #7722) - Adds support for including other configuration files, both from within a config file and from the command line (documented here, tracked in #7723)
-
Want env var specifying overriding config file
- Proposes a
CARGO_CONFIG_INCLUDE
environment variable that allows listing additional config files that should be considered by Cargo - Motivation: Overriding specific config settings for some Cargo invocations
- Mostly resolved by the implementation of the "command-line config" proposal
- Proposes a
Reset a Config Key
While the command-line config support allows overriding all config keys, it is still not possible to reset all config keys back to their "not-set" state. For example, there is currently no way to disable a default target set in a build.target
key, so that cargo build
uses the host target again.
I personally stumbled across this many times, so I opened multiple proposals to fix some problems that this causes in practice:
-
Add
--target HOST
alias?- Unset a default target set in a config file
-
Allow to unset a default target by setting
build.target
to the empty string- Unset a default target for a subdirectory
-
Unset .cargo/config key for subdirectory
- Discusses general solutions for resetting a config key for a subdirectory
-
AIlow to unset
.cargo/config
settings through a newreset
config key- Add a new
reset
array key to config files that allows listing the keys that should be reset to their default values again. - Would allow to unset any configuration key from both child config files, the command line (through the config-cli feature) and an environment variable.
- Add a new
Feedback
Have you encountered any of the above issues in practice? Which solutions would you prefer? Do you see any other issues of the cargo configuration system that don't fall into the categories above?