How to include README as crate doc in a cargo workspace

Environment

  • Rust toolchain: 1.93.0

Project Structure

.
├── README.md
├── Cargo.toml          # workspace root, members = ["crates/toml-scaffold"]
└── crates
    └── toml-scaffold
        ├── Cargo.toml
        └── src
            └── lib.rs  # contains: #![doc = include_str!("../../../README.md")]

Problem

When publishing the crate, cargo publish fails with the following error:

 --> src/lib.rs:1:10
  |
1 | #![doc = include_str!("../../../README.md")]
  |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
help: there is a file with the same name in a different directory
  |
1 | #![doc = include_str!("../../../../README.md")]
  |                              ++++++

Expected Behavior

The path ../../../README.md should be correct based on the folder structure:

  • From crates/toml-scaffold/src/lib.rs../../../README.md correctly points to the workspace root

Actual Behavior

  • Using ../../../README.md: Works with rust-analyzer but fails during cargo publish
  • Using ../../../../README.md (as suggested): Causes rust-analyzer errors but might work for publishing

Question

How can I resolve this path discrepancy so that the same path works for both local development (rust-analyzer) and crate publishing?

1 Like

All files that are used by a package must be within the directory of that package.

One possible solution is to use a symlink. If you do this, then when publishing, Cargo will replace the symlink with a file, producing a working package. However, doing this means you can only publish on Unix systems, if that matters to you.

├── README.md
├── Cargo.toml
└── crates
    └── toml-scaffold
        ├── README.md   # → ../../README.md
        ├── Cargo.toml
        └── src
            └── lib.rs  # contains: #![doc = include_str!("../README.md")]

However, my personal recommendation is that you should not be doing the include_str! at all; the two texts should be different.

  • The README.md, which is displayed prominently in crates.io, should focus on explaining when the library is useful, and also meta-information like its license and development status.
  • The crate root documentation, which is displayed prominently in rustdoc, should focus on explaining how to use the library, and should have intra-doc links to the key items of the crate while it does so. You can’t make README.md have working intra-doc links.
4 Likes

You sort of can, as I learned from https://linebender.org/blog/doc-include: the trick is to add [`MyStruct`]: MyStruct and whatnot before #![doc = include_str!("[path]/README.md")] in the crate root, and include [`MyStruct`]: https://docs.rs/[...]/struct.MyStruct.html in the readme itself.

As for the texts' different purposes, I don't usually have crate root documentation long enough that it would be too long/complicated for the crates.io blurb, so I default to using the include_str! stuff. Though, I think I'll end up splitting the README.md and crate root docs for one of the libraries I'm working on rn.

1 Like