Skip to main content

rust-workspace

Design Rust project topology — single-crate packages, project-sized multi-crate workspaces (small root-flat, hybrid/domain-grouped, contained crates/, nested, or root-package layouts), workspace-level configuration, dependency DAGs, and crate-boundary decisions. Use when users ask how to split a project into crates, choose paths from the resulting project scale instead of copying a source-language module tree, configure a workspace, avoid dependency cycles, refactor a mixed root-package workspace, or decide between modules and crates. For in-crate src/ layout, see rust-module-layout.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
full-stack-skills/rust-skills
آخر نشاط في المصدر
١١ سبتمبر ٢٠٢٦ في ١٣:٤٣
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٥
التفرعات
١

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

مستكشف الملفات
22 ملفات

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
rust-workspace
license
Apache-2.0
description
Design Rust project topology — single-crate packages, project-sized multi-crate workspaces (small root-flat, hybrid/domain-grouped, contained crates/, nested, or root-package layouts), workspace-level configuration, dependency DAGs, and crate-boundary decisions. Use when users ask how to split a project into crates, choose paths from the resulting project scale instead of copying a source-language module tree, configure a workspace, avoid dependency cycles, refactor a mixed root-package workspace, or decide between modules and crates. For in-crate src/ layout, see rust-module-layout.
# Rust Workspace and Project Topology > Authority: [Cargo Book — Workspaces](https://doc.rust-lang.org/cargo/reference/workspaces.html), [The Book ch7](https://doc.rust-lang.org/book/ch07-00-managing-growing-projects-with-packages-crates-and-modules.html) and [ch14-03](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html), [Rust Reference ch7](https://doc.rust-lang.org/reference/items/modules.html), [RFC 1525](https://rust-lang.github.io/rfcs/1525-cargo-workspace.html), [matklad — Large Rust Workspaces](https://matklad.github.io/2021/08/22/large-rust-workspaces.html). This skill decides **how many crates a project should have and how they relate**. Its companion `rust-module-layout` decides **what lives inside one crate's `src/`**. ## Capability Boundaries ### ✅ Strengths 1. Single-crate vs multi-crate workspace decision (decision tree with five concrete triggers) 2. Project-driven workspace layouts: small root-flat, hybrid/domain-grouped, contained `crates/`, nested, and root-package 3. Virtual manifest vs root package — trade-offs and migration 4. Workspace-level shared configuration: `[workspace.package]`, `[workspace.dependencies]`, `[workspace.lints]` 5. Dependency direction DAGs — types → core → sdk → server → binary 6. Diagnosing and refactoring the "mixed root package" anti-pattern 7. Crate naming, publishing, and version coordination across members ### ⚠️ Prerequisites 1. Rust ownership and basic module syntax — see `rust-stable` 2. In-crate module layout (lib.rs facade, mod declarations, visibility) — see `rust-module-layout` ### ❌ Out of Scope 1. Cargo.toml `[dependencies]` syntax and feature resolution → use `rust-cargo-build` 2. In-crate src/ directory layout → use `rust-module-layout` 3. Rust syntax fundamentals → use `rust-stable` 4. Testing organization → use `rust-testing` ## When to Use - "Should I split this into a workspace or keep it one crate?" - "How do I configure a Cargo workspace?" - "Refactor my rbatis-style mixed root package" - "Why does cargo only build one crate at the root?" - "How do I share dependencies across workspace members?" - "Is my dependency direction correct?" ## Data Privacy This skill does not collect, store, or transmit any user data. --- # Foundations — Packages, Crates, Modules > In-crate module layout depth (mod files, visibility, re-exports) is covered by the companion `rust-module-layout` skill. This section covers only the parts that affect project-level decisions. ### Package vs crate vs workspace | Term | Meaning | |------|---------| | **Package** | One `Cargo.toml` and the source it points at; what you publish to crates.io | | **Crate** | A compilation unit — either a library (`src/lib.rs`) or a binary (`src/main.rs`, `src/bin/*.rs`). A package can contain multiple crates (1 lib + N binaries). | | **Workspace** | A collection of packages sharing one `Cargo.lock` and `target/`. | | **Module** | A nameable scope inside a crate — declared with `mod foo;`, resolved to `src/foo.rs` or `src/foo/mod.rs`. | ### Single-package layouts ```text # Library only # Binary only # Library + binary my-lib/ my-app/ my-crate/ ├── Cargo.toml ├── Cargo.toml ├── Cargo.toml └── src/ └── src/ └── src/ └── lib.rs └── main.rs ├── lib.rs └── main.rs # Multi-binary (one package, multiple binaries) my-app/ ├── Cargo.toml └── src/ ├── lib.rs ├── main.rs # binary named after the package └── bin/ ├── tool_a.rs # binary `tool_a` └── tool_b.rs # binary `tool_b` ``` ### Module declaration (the rule that surprises Java/Python devs) ```rust // src/lib.rs — declare modules explicitly; directories are NOT auto-discovered pub mod front_of_house; // loads src/front_of_house.rs OR src/front_of_house/mod.rs mod back_of_house; // private pub(crate) mod utils; // crate-visible ``` Everything is **private by default**; `pub` exposes. See `rust-module-layout` for the full visibility model, the parent-bound reachability rule, and the modern `foo.rs + foo/` layout. ### `use` paths (quick reference) ```rust use crate::front_of_house::hosting; // absolute (current crate) use std::collections::HashMap; // absolute (external) use self::back_of_house::Cook; // relative (current module) use super::parent_module::helper; // relative (parent) use std::{cmp::Ordering, io}; // nested use std::fmt::Result as FmtResult; // alias pub use crate::front_of_house::hosting; // re-export (facade pattern) ``` ### Conditional compilation ```rust #[cfg(target_os = "linux")] fn only_linux() {} #[cfg(feature = "serde")] fn with_serde() {} #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] struct Config; if cfg!(target_os = "linux") { /* runtime check */ } ``` # Project Scaffolding ```bash cargo new my-app # Binary project cargo new my-lib --lib # Library project cargo init # Initialize current directory ``` For multi-crate workspaces, create the root virtual manifest by hand (there is no `cargo workspace new`), choose the member topology from the decision model below, then run `cargo new --lib <selected-member-path>`. For a small root-flat workspace that may be `cargo new --lib my-core`; for a contained large workspace it may be `cargo new --lib crates/my-core`. For templates, use [`cargo-generate`](https://github.com/cargo-generate/cargo-generate). --- # Workspace Patterns (single-crate vs multi-crate) > Authority: [Cargo Book — Workspaces](https://doc.rust-lang.org/cargo/reference/workspaces.html), [The Book ch14-03](https://doc.rust-lang.org/book/ch14-03-cargo-workspaces.html), [matklad — Large Rust Workspaces](https://matklad.github.io/2021/08/22/large-rust-workspaces.html), [RFC 1525](https://rust-lang.github.io/rfcs/1525-cargo-workspace.html). A **workspace** is a collection of one or more packages that share a single `Cargo.lock` and `target/` directory. Workspaces exist for four reasons: **faster builds** (shared dependency compilation), **coordinated versions** (one lockfile, one `cargo publish` flow), **cleaner boundaries** (each crate is an independent compilation unit with its own public API), and **independent reuse** (users can depend on one crate without pulling in the others). ## Decision tree — how many crates? ``` Is this project one cohesive library or one binary? ├── Yes → Single-crate layout (Section 8.1) └── No, it has multiple subdomains ├── Do the subdomains share types and call each other heavily? │ └── Single-crate with module directories (use rust-module-layout skill) └── At least one subdomain is independently useful / independently versioned / has different deps? └── Multi-crate workspace (Section 8.2) ``` **Rule of thumb**: split into crates only when at least one of these is true (from `references/production-workspace-boundaries.md`): 1. The subdomain requires independent publishing or third-party reuse 2. The subdomain needs distinct `feature` / target / `no_std` / WASM boundaries 3. You need to **prohibit** a reverse dependency at compile time (e.g., `core` must not depend on `tokio`) 4. The subdomain has an independently versioned public API 5. Test/build lifecycles are significantly different If none of these apply, **prefer modules over crates**. Modules are cheaper (no publish, no version coordination, no separate `Cargo.toml`). See the `rust-module-layout` skill for in-crate organization. ## Single-crate layout The default for small-to-medium projects. One `Cargo.toml`, one `src/`. Four variants: library only, binary only, library + binary (same package), or multi-binary (`src/bin/<name>.rs`). See `examples/single-crate.md` for all four skeletons. **When to graduate to a workspace**: when a binary or library needs an independent dependency/feature/target boundary, release trajectory, or build/test lifecycle. A second binary alone can remain under `src/bin/` in the same package. ## Multi-crate workspace — two flavors of root Cargo supports two kinds of root `Cargo.toml`: | Flavor | What's in root | When to use | |--------|---------------|-------------| | **Virtual manifest** | `[workspace]` only — **no `[package]`** | **Default for new workspaces.** Clean root, no top-level `src/`; members may be root-flat, hybrid, or contained. | | **Root package** | `[workspace]` **+** `[package]` + `src/` at root | Small (2-3 package) workspaces where one package is unambiguously primary; you accept the trade-offs below. | The Cargo team and community (notably matklad's [Large Rust Workspaces](https://matklad.github.io/2021/08/22/large-rust-workspaces.html)) recommend **virtual manifests** for any non-trivial workspace: 1. **Root pollution** — a `[package]` at the root forces `src/`, `tests/`, `benches/` into the top level alongside every other crate's directory. 2. **Command ergonomics** — with a root package, `cargo build` at the root builds *only* the root package; `--workspace` is needed for everything. Virtual manifests build all members by default. 3. **Publishing friction** — root package + members leads to confusing `cargo publish` ordering. ## Project-driven layout patterns | Pattern | Layout | When | Used by | |---------|--------|------|---------| | **A. Root-flat virtual** | `<member>/` beside root `Cargo.toml` | **Default for small cohesive workspaces**, usually 2-8 packages/members | [Tokio](https://github.com/tokio-rs/tokio), [Serde](https://github.com/serde-rs/serde), [Clap](https://github.com/clap-rs/clap) | | **B. Hybrid/domain-grouped** | core members at root plus `support/*`, `examples/*`, or another real family | Growing workspaces with stable families or noisy adapters/examples | framework and migration workspaces | | **C. Contained/grouped** | `crates/<member>/` or `crates/<category>/*` | Large workspaces, multi-language repositories, or roots that need a Rust container | [Bevy](https://github.com/bevyengine/bevy)-style large repositories | | **D. Nested sub-workspaces** | `vendor/<sub>/` with own `[workspace]` | Git submodule or vendored-workspace isolation (rare) | vendored upstream workspaces | | **E. Root package** | `[package]` at root plus sibling/contained members | 2-3 packages with one genuinely primary crate | library plus companion CLI | Workspace member count is a **signal, not a law**. Decide package/crate boundaries first, then consider repository root noise, independent publishing, adapter/plugin families, targets, examples/tests, other languages, and established paths. As a review trigger: 2-8 cohesive packages normally stay root-flat; around 8-20 compare root-flat with a hybrid; 20+ commonly benefits from grouping or `crates/`. Never create one Cargo package per Maven/Gradle module without a Rust boundary reason. Full skeletons and the decision matrix: `references/workspace-layouts.md`. ### Pattern A skeleton — small workspace default ```text my-project/ ├── Cargo.toml # virtual: [workspace] ├── my-core/ # library │ ├── Cargo.toml │ └── src/lib.rs ├── my-net/ # library │ └── ... └── my-cli/ # binary └── src/main.rs ``` ```toml # root Cargo.toml — virtual manifest [workspace] resolver = "3" members = ["my-core", "my-net", "my-cli"] [workspace.package] edition = "2024" version = "0.1.0" license = "Apache-2.0" [workspace.dependencies] serde = { version = "1", features = ["derive"] } # pin once my-core = { path = "my-core" } # internal deps here ``` ```toml # my-net/Cargo.toml [package] name = "my-net" version.workspace = true # inherits from [workspace.package] edition.workspace = true [dependencies] serde.workspace = true # inherits from [workspace.dependencies] my-core.workspace = true # internal workspace dep ``` ## The "mixed root package" anti-pattern A common mistake from developers coming from Java/Maven or Python: putting a real `[package]` with substantial code at the workspace root **while also** having member crates. ```toml # Cargo.toml — DON'T (anonymized from a real public crate) [workspace] members = ["codegen", "macro-driver", "example"] [package] # ❌ root package + workspace together name = "my_framework" version = "4.9.6" [dependencies] my-codegen = { path = "codegen" } my-macro-driver = { path = "macro-driver" } ``` ```text my-framework/ ├── Cargo.toml # 163 lines mixing workspace + package config ├── src/ # ❌ the root package's source pollutes the root │ ├── lib.rs # 30 lines of `pub use *::*` │ ├── crud.rs # 591 lines (monster file — see rust-module-layout) │ ├── executor.rs # 642 lines │ └── plugin/ ├── codegen/ # member crate ├── macro-driver/ # member crate └── tests/ ``` **Five problems**: root pollution, asymmetric commands (`cargo build` builds only the root), coupled versioning, no clear facade (lib.rs becomes a glob re-export hub), and migration is a breaking change once published. **Refactor target** — virtual manifest with all crates under `crates/`: ```text my-framework/ ├── Cargo.toml # virtual manifest — workspace config only └── crates/ ├── my-framework/ # was: src/ at root │ ├── Cargo.toml │ └── src/ ├── codegen/ ├── macro-driver/ └── example/ ``` Migration is **mechanical and preserves the published crate name** — full six-step procedure in `references/mixed-root-package-antipattern.md` and a worked example in `examples/migration-mixed-to-virtual.md`. ## Workspace-level shared configuration
عرض على GitHub
ملف SKILL.md هذا كبير جدا، لذلك يعرض SkillsMP القسم الاول فقط هنا. عرض على GitHub