ITADN

[bug] Rust toolchain `scaffold_docker` leaves an empty src/main.rs in library crates, breaking the build with E0601

#2631OpenYassineElbouchaibi 创建于 2026-07-20
**Describe the bug** The Rust toolchain plugin's `scaffold_docker` unconditionally writes an **empty** `src/main.rs` (and `src/lib.rs`) into every project during the `Configs` scaffold phase. For a **library-only** crate (has `src/lib.rs`, no `src/main.rs`, no explicit `[[bin]]`), this empty `src/main.rs` is never removed by the `Sources` phase — that overlay copies real files but does not prune skeleton files with no real counterpart. In the build stage, cargo's default binary auto-discovery (`autobins`) then picks up the stray empty `src/main.rs` as a binary target with no `fn main` and fails: ``` error[E0601]: `main` function not found in crate `my_lib` = note: consider adding a `main` function to `packages/my-lib/src/main.rs` error: could not compile `my-lib` (bin "my-lib") due to 1 previous error ``` The referenced `src/main.rs` does not exist in the repository — it is created only inside the build by the scaffold step. This is easy to miss because a plain host-side `cargo build` (no stub present) passes; it only surfaces through the docker scaffold flow. > **Verified with moon 2.4.2.** `moon docker scaffold my-app` writes a 0-byte > `.moon/docker/configs/packages/my-lib/src/main.rs`; the `sources` skeleton contains only the real > `lib.rs`. A `docker build` (which overlays `configs` then `sources`) leaves the empty `main.rs` in > place, and `moon run my-app:build` fails with `error[E0601]` / `could not compile my-lib (bin "my-lib")`. > > One subtlety: the failure only occurs when something actually **compiles `my-lib`'s targets** (the > phantom `bin`) — a whole-workspace `cargo build`, `cargo build --package my-lib` / `moon run my-lib:build`, > or an app build whose task depends on the library build (as the attached repro wires it). A scoped > `cargo build --package my-app` builds only my-lib's *library* target and does **not** surface the bug. The offending code is in `github.com/moonrepo/plugins`, `toolchains/rust/src/tier1.rs` (`rust_toolchain` v1.0.6, the version moon 2.4.2 resolves; still present on `master`): ```rust // Cargo requires either `lib.rs` or `main.rs` during // the workspace/configs phase, which isn't copied till the // sources phase. Because scaffolding may attempt to run // Cargo commands, it will fail without these files! if input.phase == ScaffoldDockerPhase::Configs && input.project.is_some() { let lib_file = input.output_dir.join("src/lib.rs"); let main_file = input.output_dir.join("src/main.rs"); fs::write_file(&lib_file, "")?; // empty fs::write_file(&main_file, "")?; // empty — no `fn main` ... } ``` **Steps to reproduce** A minimal moon workspace with two reproduction paths: **https://github.com/YassineElbouchaibi/moon-rust-scaffold-repro** (downloadable zip: https://github.com/YassineElbouchaibi/moon-rust-scaffold-repro/releases/download/v1.0.1/moon-rust-scaffold-repro.zip). The workspace: ``` Cargo.toml # [workspace] members = apps/my-app, packages/my-lib apps/my-app/ # binary crate (has src/main.rs), depends on my-lib packages/my-lib/ # library-only: src/lib.rs, NO src/main.rs, no [[bin]] ``` Cargo-only (no docker/moon needed) — run `./reproduce.sh`, or by hand: 1. `cargo build --package my-lib` → passes (library-only crate, no stub). 2. Write an empty `packages/my-lib/src/main.rs` (exactly what the plugin does in the Configs phase): `: > packages/my-lib/src/main.rs` 3. `cargo build --package my-lib` → fails with `error[E0601]: main function not found`. 4. Add `autobins = false` under `[package]` in `packages/my-lib/Cargo.toml` → builds again. Full docker flow (equivalent, via moon) — `docker build -f Dockerfile .`: 1. `moon docker scaffold my-app` — Configs phase writes the empty `src/main.rs` (and `src/lib.rs`) into `.moon/docker/configs/packages/my-lib/src/`. 2. `COPY --from=skeleton /app/.moon/docker/configs .` then `moon docker setup`. 3. `COPY --from=skeleton /app/.moon/docker/sources .` — overlays real sources (my-lib's real `lib.rs`); the empty `main.rs` from the configs skeleton is not pruned. 4. `moon run my-app:build` — its `deps: ['my-lib:build']` compiles my-lib's targets (including the phantom `bin`) and fails with the same E0601. **Expected behavior** After the `Sources` phase, each crate should contain exactly the files that exist in the repository. A library-only crate should not carry a phantom `src/main.rs`, and the build should compile it as a pure library. **Screenshots** N/A — error output included above. **Environment** - moon: 2.4.2 - Rust toolchain plugin: `rust_toolchain` v1.0.6 (resolved by moon 2.4.2) - Affected crate type: Rust `layer: library`, library-only (`src/lib.rs`, no `src/main.rs`, no `[[bin]]`) **Additional context** Root cause: the empty `src/main.rs` placeholder written in the `Configs` phase is not pruned by the `Sources` phase, and cargo's `autobins` treats it as a phantom binary target with no `fn main`. Suggested fixes (any one resolves it): 1. Only scaffold the placeholder matching the crate's real target(s) (e.g. `src/lib.rs` for a library) instead of unconditionally writing both `lib.rs` and `main.rs`. 2. Have the `Sources` phase prune skeleton placeholders that have no real source counterpart, so each crate ends up byte-identical to the repo tree. 3. If both must be written during `Configs`, make the placeholder `main.rs` compilable (`fn main() {}`) — though 1 or 2 are preferable, since a leaked phantom binary target is surprising regardless of whether it compiles. Current workaround: set `autobins = false` on each library crate's `[package]` (explicit `[[bin]]` targets still build). This treats the symptom rather than the scaffold behavior. Note: the fix likely belongs in `github.com/moonrepo/plugins` (`toolchains/rust`), since that is where the placeholder is written; filing here as the plugins repo has no separate issue tracker/template.
2 条评论