-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat: stabilize -Zconfig-include
#16284
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
df5a6c3 to
a209213
Compare
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
This comment was marked as outdated.
|
@rfcbot fcp merge T-cargo |
|
Team member @weihanglo has proposed to merge this. The next step is review by the rest of the tagged team members: No concerns currently listed. Once a majority of reviewers approve (and at most 2 approvals are outstanding), this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
|
Disclosure: This is an AI assisted stabilization report. I (@weihanglo) have reviewed and revised it (quite a lot?) so the full responsibility of it is on me. |
This reserves future possibility for us to support globa syntax and templated paths. Addressing rust-lang#16284 (comment)
…6286) ### What does this PR try to resolve? Address feedback: #16284 (comment)
### What does this PR try to resolve? This reserves future possibility for us to support globa syntax and templated paths. Addressing #16284 (comment)
a209213 to
3e9e9bd
Compare
This comment has been minimized.
This comment has been minimized.
8174e7e to
34de4ef
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
### What does this PR try to resolve? Discussed in 2025-11-25 t-cargo meeting. We prefer inline tables over array of tables for `include`. * `include` is special and should appear early in config files, before other configuration keys * Array-of-tables syntax allows interleaving with other config, which creates confusion about merge order and precedence * Inline tables keep all `include` declarations together at the top, making the load order behavior clearer Part of #7723 and #16284 ### How to test and review this PR?
# Stabilization report ## Summary The `include` key in Cargo configuration files allows loading additional config files, enabling better organization, sharing, and management of Cargo configurations across projects and environments. This feature has been available under the `-Zconfig-include` flag since 2019 (Cargo 1.42) and has seen real-world usage. The stabilization includes support for multiple syntax forms and the `optional` field, which were added in October 2025 based on user feedback. Tracking issue: rust-lang#7723 ### What is stabilized The `include` configuration key allows loading additional config files. **Supported syntax:** - Array: `include = ["a.toml", "b.toml"]` - Inline tables (preferred): `include = [{ path = "optional.toml", optional = true }]` - Array of tables (not preferred): `[[include]]` with `path` and `optional` fields **Key behaviors:** - Paths are relative to the including config file and must end with `.toml` - Glob syntax and templated paths (with `{}` braces} are disallowed in paths. - Merge follows precedence order: included files (left-to-right) → parent config - `optional = true` silently skips missing files (default: `false`) - Cyclic includes are detected and reported as errors See the config documentation for complete details and examples. ### Future extensions Several potential extensions are not implemented at this time: * Glob patterns: like `include = "config.d/*.toml"` — rust-lang#9306 * Conditional include: conditions like gitconfig's `includeIf` — rust-lang#7723 (comment) * Variable substitution and template: placeholders like `{CONFIG_DIR}` or `{CARGO_HOME}` — rust-lang#15769 * Implicit-include: like `.cargo/config.user.toml` or `.cargo/config.d` for config fragments — [#t-cargo > Built-in &rust-lang#96;.cargo/config.local.toml&rust-lang#96;for non-committed config](https://rust-lang.zulipchat.com/#narrow/channel/246057-t-cargo/topic/Built-in.20.60.2Ecargo.2Fconfig.2Elocal.2Etoml.60for.20non-committed.20config/with/558705263) * Environment variable include support: like `CARGO_INCLUDE=path/to/config.toml` — rust-lang#6728 See "Doors closed" for more. ## Design ### Key evolution All significant changes occurred during the unstable period (2019-2024) and were approved by the Cargo team. **1. File naming restrictions** (rust-lang#12298, 2023-06-21) (rust-lang#16285, 2025-11-21) The syntax has a couple restrictions: * Path must end with `.toml` extension * Path must not contain glob syntax or template braces The team considered the restriction was reasonable. The restriction applies to config file discovery but not to `--config` CLI arguments which has already been stabilized. **2. Loading precedence for arrays** Config values in array elements are loaded left to right, with later values taking precedence. The parent config file's values always take precedence over included configs. This provides intuitive layering behavior. **3. Syntax complexity** (rust-lang#16174, 2025-10-30) (rust-lang#16298 2025-11-25) The feature started with simple string/array syntax. The team debated and decided to add table syntax, and remove single string shorthand before stabilization to allow future extensions and reduce complexity. **4. Optional includes by default vs. explicit** (rust-lang#16180, 2025-10-31) Some users wanted missing files to be silently ignored by default for local customization workflows. Others wanted errors to catch typos. The team chose to error by default but added an explicit `optional = true` field, requiring users to be intentional about optional behavior. ### Nightly extensions No nightly-only extensions remain. The feature is fully stabilized as implemented. ### Doors closed **This stabilization commits to**: 1. Supporting the `include` key in Cargo configuration 2. Relative path resolution from the including config file 3. Left-to-right merge order for arrays 4. Parent config taking precedence over includes 5. The `path` and `optional` fields in table syntax **This does NOT prevent**: - Adding glob/wildcard support - Adding conditional includes - Adding variable substitution and template **This MAY prevent**: * Adding new implicit-include for user local config or config fragments directory As we are going to allow all file paths. Adding any implicit includes after stabilization might break the merge precedence if people already include those paths. The only possible way to support it is accepting `.cargo/config.toml/` as a directory and treat it as a config fragments directory. `.cargo/config.toml` (and the legacy `cargo/config/`) is the only path Cargo reserves. ## Feedback ### Call for testing No formal "call for testing" was issued, but the feature has been available under `-Zconfig-include` since Cargo 1.42 (2019) and has seen real-world adoption. ### Use cases Users reported use cases: - **Sharing flags and environment conditionally**: [Tock OS](https://github.com/tock/tock), [esp-hal](https://github.com/esp-rs/esp-hal), rtos, and some FFI libraries use it for preset management across multiple board configurations for different hardware platforms, architectures, and downstream crates. A board's config (used by entering its directory) is defined by pulling from role-based config slices. - **Beyond hierarchical discovery**: Some use cases require explicit includes because configs need to be loaded from locations outside the hierarchical path, or need to be conditionally included based on per-package or per-machine requirements that can't rely on the directory structure alone. This usually happens in a meta build system that generates configs, especially when setting `CARGO_HOME` to a different location off the hierarchical path. - **User and project configuration**: Projects with checked-in configs (e.g., `[profile.test] debug = false` for CI) can allow developers to override settings locally without modifying the checked-in file. Developers can include an optional `.cargo/local-config.toml` without using git workarounds like `update-index --assume-unchanged`. ### Coverage Test coverage is comprehensive in `tests/testsuite/config_include.rs`: - Merge behavior: left-to-right order, hierarchy interaction - Path handling: relative paths, different directory structures - Cycle detection: Direct and indirect cycles - Error cases: missing files, invalid paths, wrong extensions, missing required fields - Syntax variations: string, array, inline table, array of tables - Optional includes: missing optional files, mixed optional/required - CLI integration: includes from `--config` arguments - Forward compatibility: unknown table fields, glob/template syntax restrictions ### Known limitations Issue rust-lang#15769 tracks inconsistent relative path behavior between `include` paths (relative to config file) and other config paths like `build.target-dir` (relative to cargo root). This is considered a known limitation and confusion that can be addressed separately and doesn't block stabilization. No other known limitations blocking stabilization. ## History - 2019-02-25: Original proposal (rust-lang#6699) - 2019-12-19: initial implementation (rust-lang#7649) - 2023-06-21: file extension restriction added (rust-lang#12298) - 2025-10-30: table syntax support added (rust-lang#16174) - 2025-10-31: optional field support added (rust-lang#16180) - 2025-11-21: glob and template syntax restriction added (rust-lang#16285) - 2025-11-25: single string shorthand syntax removed (rust-lang#16298) ## Acknowledgments Contributors to this feature: - `@ehuss` for initial implementation and design - `@weihanglo` for extra syntax support and enhancement - `@rust-lang/cargo` team for the support, review and feedback - All users providing feedback in rust-lang#7723
34de4ef to
c329526
Compare
|
This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
Stabilization report
Summary
The
includekey in Cargo configuration files allows loading additional config files, enabling better organization, sharing, and management of Cargo configurations across projects and environments.This feature has been available under the
-Zconfig-includeflag since 2019 (Cargo 1.42) and has seen real-world usage.The stabilization includes support for multiple syntax forms and the
optionalfield, which were added in October 2025 based on user feedback.Tracking issue: #7723
What is stabilized
The
includeconfiguration key allows loading additional config files.Supported syntax:
include = ["a.toml", "b.toml"]include = [{ path = "optional.toml", optional = true }][[include]]withpathandoptionalfieldsKey behaviors:
.toml{}braces} are disallowed in paths.optional = truesilently skips missing files (default:false)See the config documentation for complete details and examples.
Future extensions
Several potential extensions are not implemented at this time:
include = "config.d/*.toml"— Support multiple cargo configuration files in.cargo#9306includeIf— Tracking issue for config-include #7723 (comment){CONFIG_DIR}or{CARGO_HOME}— Inconsistent relative path behavior between config include and other fields #15769.cargo/config.user.tomlor.cargo/config.dfor config fragments — #t-cargo > Built-in `.cargo/config.local.toml`for non-committed configCARGO_INCLUDE=path/to/config.toml— Want env var specifying overriding config file #6728See "Doors closed" for more.
Design
Key evolution
All significant changes occurred during the unstable period (2019-2024) and were approved by the Cargo team.
1. File naming restrictions (#12298, 2023-06-21) (#16285, 2025-11-21)
The syntax has a couple restrictions:
.tomlextensionThe team considered the restriction was reasonable. The restriction applies to config file discovery but not to
--configCLI arguments which has already been stabilized.2. Loading precedence for arrays
Config values in array elements are loaded left to right, with later values taking precedence. The parent config file's values always take precedence over included configs. This provides intuitive layering behavior.
3. Syntax complexity (#16174, 2025-10-30) (#16298 2025-11-25)
The feature started with simple string/array syntax. The team debated and decided to add table syntax, and remove single string shorthand before stabilization to allow future extensions and reduce complexity.
4. Optional includes by default vs. explicit (#16180, 2025-10-31)
Some users wanted missing files to be silently ignored by default for local customization workflows. Others wanted errors to catch typos. The team chose to error by default but added an explicit
optional = truefield, requiring users to be intentional about optional behavior.Nightly extensions
No nightly-only extensions remain. The feature is fully stabilized as implemented.
Doors closed
This stabilization commits to:
includekey in Cargo configurationpathandoptionalfields in table syntaxThis does NOT prevent:
This MAY prevent:
As we are going to allow all file paths. Adding any implicit includes after stabilization might break the merge precedence if people already include those paths.
The only possible way to support it is accepting
.cargo/config.toml/as a directory and treat it as a config fragments directory..cargo/config.toml(and the legacycargo/config/) is the only path Cargo reserves.Feedback
Call for testing
No formal "call for testing" was issued, but the feature has been available under
-Zconfig-includesince Cargo 1.42 (2019) and has seen real-world adoption.Use cases
Users reported use cases:
Sharing flags and environment conditionally: Tock OS, esp-hal, rtos, and some FFI libraries use it for preset management across multiple board configurations for different hardware platforms, architectures, and downstream crates. A board's config (used by entering its directory) is defined by pulling from role-based config slices.
Beyond hierarchical discovery: Some use cases require explicit includes because configs need to be loaded from locations outside the hierarchical path, or need to be conditionally included based on per-package or per-machine requirements that can't rely on the directory structure alone. This usually happens in a meta build system that generates configs, especially when setting
CARGO_HOMEto a different location off the hierarchical path.User and project configuration: Projects with checked-in configs (e.g.,
[profile.test] debug = falsefor CI) can allow developers to override settings locally without modifying the checked-in file. Developers can include an optional.cargo/local-config.tomlwithout using git workarounds likeupdate-index --assume-unchanged.Coverage
Test coverage is comprehensive in
tests/testsuite/config_include.rs:--configargumentsKnown limitations
Issue #15769 tracks inconsistent relative path behavior between
includepaths (relative to config file) and other config paths likebuild.target-dir(relative to cargo root). This is considered a known limitation and confusion that can be addressed separately and doesn't block stabilization.No other known limitations blocking stabilization.
History
.tomlfile extension restriction for-Zconfig-include#12298)Acknowledgments
Contributors to this feature:
@ehussfor initial implementation and design@weihanglofor extra syntax support and enhancement@rust-lang/cargoteam for the support, review and feedback