https://github.com/hack-ink/cargo-featalign
Cargo features alignment tool.
https://github.com/hack-ink/cargo-featalign
cargo cli features lint workspace
Last synced: 21 days ago
JSON representation
Cargo features alignment tool.
- Host: GitHub
- URL: https://github.com/hack-ink/cargo-featalign
- Owner: hack-ink
- License: gpl-3.0
- Created: 2023-07-24T07:50:29.000Z (almost 3 years ago)
- Default Branch: main
- Last Pushed: 2025-11-17T13:44:06.000Z (5 months ago)
- Last Synced: 2025-12-28T22:41:51.937Z (4 months ago)
- Topics: cargo, cli, features, lint, workspace
- Language: Rust
- Homepage: https://crates.io/crates/cargo-featalign
- Size: 284 KB
- Stars: 11
- Watchers: 1
- Forks: 0
- Open Issues: 8
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Agents: AGENTS.md
Awesome Lists containing this project
README
# Cargo Featalign
### Cargo features alignment tool.
[](https://www.gnu.org/licenses/gpl-3.0)
[](https://github.com/hack-ink/cargo-featalign/actions/workflows/rust.yml)
[](https://github.com/hack-ink/cargo-featalign/actions/workflows/release.yml)
[](https://github.com/hack-ink/cargo-featalign/tags)
[](https://github.com/hack-ink/cargo-featalign)
[](https://github.com/hack-ink/cargo-featalign)
### Introduction
The original version of this project can be found at [`subalfred check features`](https://github.com/hack-ink/subalfred).
Upon further investigation, I have found that this tool is not only compatible with _Substrate_ projects but also works for general _Cargo_ projects, offering even more powerful features than before.
Now, `cargo-featalign` stands out with its enhanced functionality.
The `cargo-featalign` tool offers the following features:
- Checking for missing features
- Printing the dependency path
- Performing a dry run before overwriting
- Automatically aligning/fixing missing features
- Sorting alphabetically while aligning
### Installation
- From GitHub: [`github.com/hack-ink/cargo-featalign/releases/latest`](https://github.com/hack-ink/**cargo-featalign/releases/latest)
- From cargo-binstall: `cargo binstall cargo-featalign`
- From Cargo: `cargo install cargo-featalign`
### Usage
```sh
cargo featalign --help
```
```
Cargo features alignment tool.
Usage: cargo-featalign [OPTIONS] --features <[NAME]> [PATH]
Arguments:
[PATH]
Root `Cargo.toml`'s path.
If `Cargo.toml` is not provided, it will be searched for under the specified path.
[default: ./Cargo.toml]
Options:
--features <[NAME]>
Features to process
--thread
Number of threads to use.
The default value is based on the number of logical cores.
[default: 32]
--mode
Running mode.
Check: Prints the analysis result.
DryRun: Prints the resolved result without modifying the `Cargo.toml` file.
DryRun2: creates a `*.cargo-featalign.swap` file.
Overwrite: Overwrites the original `Cargo.toml` file.
[default: overwrite]
[possible values: check, dry-run, dry-run2, overwrite]
--indent-symbol
Use the given symbol for indentation
[default: tab]
[possible values: tab, whitespace]
--indent-size
The number of spaces used for indentation
[default: 4]
--workspace-only
Determines whether to process only workspace members
--default-std
Determines whether to check default features.
This option is useful when working in a no-std environment. This feature checks if you have set `default-features = false` while also having a `std = ["x/std"]` part to control it separately.
--depth
Depth of the dependency tree to process.
Use `-1` to process the entire tree.
!! Running with this flag under a large project, even with 128 threads configured, is incredibly challenging.
[default: 0]
--sort
Wether to sort the required features while aligning
--verbose
Verbose output
-h, --help
Print help (see a summary with '-h')
-V, --version
Print version
```
### Example
#### Preparation
```sh
cargo install cargo-featalign
git clone https://github.com/hack-ink/cargo-featalign.git
cd cargo-featalign
```
#### Only check the features of top-level workspace members
```sh
cargo featalign mock --features std,runtime-benchmarks,try-runtime --workspace-only --default-std --depth -1 --mode check | jq
```
```json
{
"mock-runtime 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock)": [
{
"id": "general-c 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/general/c)",
"alias": "",
"dependency-path": "/mock-runtime",
"problem": "default-features-enabled"
},
{
"id": "pallet-a 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/a)",
"alias": "pallet-a",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "pallet-b 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/b)",
"alias": "pallet-b",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["runtime-benchmarks"]
}
},
{
"id": "pallet-c 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/c)",
"alias": "pallet-c",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["try-runtime"]
}
},
{
"id": "pallet-d 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/d)",
"alias": "pallet-d",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["runtime-benchmarks", "std", "try-runtime"]
}
}
]
}
```
#### Check the features of workspace members recursively
```sh
cargo featalign mock --features std,runtime-benchmarks,try-runtime --workspace-only --default-std --depth -1 --mode check | jq
```
```json
{
"nested-a 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/a)": [
{
"id": "nested-d 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/d)",
"alias": "",
"dependency-path": "/mock-runtime/primitive-a/nested-a",
"problem": "default-features-enabled"
},
{
"id": "nested-b 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/b)",
"alias": "nested-b",
"dependency-path": "/mock-runtime/primitive-a/nested-a",
"problem": {
"missing-features": ["std"]
}
}
],
"nested-b 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/b)": [
{
"id": "nested-c 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/c)",
"alias": "nested-c",
"dependency-path": "/mock-runtime/primitive-a/nested-a/nested-b",
"problem": {
"missing-features": ["std"]
}
}
],
"mock-runtime 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock)": [
{
"id": "general-c 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/general/c)",
"alias": "",
"dependency-path": "/mock-runtime",
"problem": "default-features-enabled"
},
{
"id": "pallet-a 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/a)",
"alias": "pallet-a",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "pallet-b 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/b)",
"alias": "pallet-b",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["runtime-benchmarks"]
}
},
{
"id": "pallet-c 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/c)",
"alias": "pallet-c",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["try-runtime"]
}
},
{
"id": "pallet-d 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/pallet/d)",
"alias": "pallet-d",
"dependency-path": "/mock-runtime",
"problem": {
"missing-features": ["runtime-benchmarks", "std", "try-runtime"]
}
}
]
}
```
#### Check the features of all dependencies recursively
**!! Running this under a large project, even with 128 threads configured, is incredibly challenging.**
```sh
cargo featalign . --features std --depth -1 --mode check | jq
```
```json
{
"semver 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "serde 1.0.176 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "serde",
"dependency-path": "/cargo-featalign/cargo_metadata/semver",
"problem": {
"missing-features": ["std"]
}
}
],
"tracing-core 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "valuable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "valuable",
"dependency-path": "/cargo-featalign/color-eyre/color-spantrace/tracing-core",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "valuable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "valuable",
"dependency-path": "/cargo-featalign/color-eyre/tracing-error/tracing/tracing-core",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "valuable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "valuable",
"dependency-path": "/cargo-featalign/color-eyre/tracing-error/tracing-subscriber/tracing-core",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "valuable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "valuable",
"dependency-path": "/cargo-featalign/color-eyre/color-spantrace/tracing-error/tracing/tracing-core",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "valuable 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "valuable",
"dependency-path": "/cargo-featalign/color-eyre/color-spantrace/tracing-error/tracing-subscriber/tracing-core",
"problem": {
"missing-features": ["std"]
}
}
],
"backtrace 0.3.68 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "libc 0.2.147 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "libc",
"dependency-path": "/cargo-featalign/color-eyre/backtrace",
"problem": {
"missing-features": ["std"]
}
}
],
"rustix 0.38.4 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "libc 0.2.147 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "libc",
"dependency-path": "/cargo-featalign/clap/clap_builder/anstream/is-terminal/rustix",
"problem": {
"missing-features": ["std"]
}
}
],
"errno 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "libc 0.2.147 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "libc",
"dependency-path": "/cargo-featalign/clap/clap_builder/anstream/is-terminal/rustix/errno",
"problem": {
"missing-features": ["std"]
}
}
],
"time 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "libc 0.2.147 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "libc",
"dependency-path": "/cargo-featalign/vergen/time",
"problem": {
"missing-features": ["std"]
}
},
{
"id": "serde 1.0.176 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "serde",
"dependency-path": "/cargo-featalign/vergen/time",
"problem": {
"missing-features": ["std"]
}
}
],
"ahash 0.8.3 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "once_cell 1.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "once_cell",
"dependency-path": "/cargo-featalign/imara-diff/ahash",
"problem": {
"missing-features": ["std"]
}
}
],
"getrandom 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "libc 0.2.147 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "libc",
"dependency-path": "/cargo-featalign/imara-diff/ahash/getrandom",
"problem": {
"missing-features": ["std"]
}
}
],
"clap 4.3.19 (registry+https://github.com/rust-lang/crates.io-index)": [
{
"id": "once_cell 1.18.0 (registry+https://github.com/rust-lang/crates.io-index)",
"alias": "once_cell",
"dependency-path": "/cargo-featalign/clap",
"problem": {
"missing-features": ["std"]
}
}
]
}
```
#### Dry run of aligning features for workspace members
```sh
cargo featalign mock --features std,runtime-benchmarks,try-runtime --workspace-only --default-std --depth -1 --mode dry-run
```
```diff
nested-a 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/a)
@@ -17,4 +17,5 @@
default = ["std"]
std = [
"nested-d/std",
+ "nested-b/std",
]
nested-b 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/b)
@@ -14,4 +14,6 @@
[features]
default = ["std"]
-std = []
+std = [
+ "nested-c/std",
+]
mock-runtime 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock)
@@ -45,18 +45,24 @@
"pallet-c/std",
# "pallet-d/std",
"primitive-a/std",
+ "pallet-a/std",
+ "pallet-d/std",
]
runtime-benchmarks = [
"pallet-a/runtime-benchmarks",
# "pallet-b/runtime-benchmarks",
"pallet-c/runtime-benchmarks",
+ "pallet-b/runtime-benchmarks",
+ "pallet-d/runtime-benchmarks",
# "pallet-d/runtime-benchmarks",
]
try-runtime = [
"pallet-a/try-runtime",
"pallet-b/try-runtime",
+ "pallet-c/try-runtime",
+ "pallet-d/try-runtime",
# "pallet-c/try-runtime",
# "pallet-d/try-runtime",
]
```
#### Dry run V2 of aligning features for workspace members
```sh
cargo featalign mock --features std,runtime-benchmarks,try-runtime --workspace-only --default-std --depth -1 --mode dry-run2
```
```sh
diff mock/Cargo.toml mock/Cargo.toml.cargo-featalign.swap
```
#### Sorting
```sh
cargo featalign mock --features std,runtime-benchmarks,try-runtime --workspace-only --default-std --depth -1 --mode dry-run --sort
```
```diff
@@ -16,5 +16,6 @@
[features]
default = ["std"]
std = [
+ "nested-b/std",
"nested-d/std",
]
nested-b 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock/nested/b)
@@ -14,4 +14,6 @@
[features]
default = ["std"]
-std = []
+std = [
+ "nested-c/std",
+]
mock-runtime 0.0.0 (path+file:///root/code/hack-ink/cargo-featalign/mock)
@@ -48,24 +48,34 @@
"pallet-b/std",
"pallet-c/std",
# "pallet-d/std",
+ "pallet-a/std",
+ "pallet-d/std",
"primitive-a/std",
]
runtime-benchmarks = [
"pallet-a/runtime-benchmarks",
# "pallet-b/runtime-benchmarks",
+ "pallet-b/runtime-benchmarks",
"pallet-c/runtime-benchmarks",
+ "pallet-d/runtime-benchmarks",
# "pallet-d/runtime-benchmarks",
]
try-runtime = [
"pallet-a/try-runtime",
"pallet-b/try-runtime",
+ "pallet-c/try-runtime",
+ "pallet-d/try-runtime",
# "pallet-c/try-runtime",
# "pallet-d/try-runtime",
]
-empty = []
+empty = [
+ "primitive-b/empty",
+ "primitive-c/empty",
+ "primitive-d/empty",
+]
[workspace]
resolver = "2"
```
## Support Me
If you find this project helpful and would like to support its development, you can buy me a coffee!
Your support is greatly appreciated and motivates me to keep improving this project.
- **Fiat**
- [Ko-fi](https://ko-fi.com/hack_ink)
- [爱发电](https://afdian.com/a/hack_ink)
- **Crypto**
- **Bitcoin**
- `bc1pedlrf67ss52md29qqkzr2avma6ghyrt4jx9ecp9457qsl75x247sqcp43c`
- **Ethereum**
- `0x3e25247CfF03F99a7D83b28F207112234feE73a6`
- **Polkadot**
- `156HGo9setPcU2qhFMVWLkcmtCEGySLwNqa3DaEiYSWtte4Y`
Thank you for your support!
## Appreciation
We would like to extend our heartfelt gratitude to the following projects and contributors:
- The Rust community for their continuous support and development of the Rust ecosystem.
## Additional Acknowledgements
- TODO
### License
Licensed under [GPL-3.0](LICENSE).