Search code examples
rustrust-cargorust-crates

Publish only the binary crate of a workspace


I have a project in the form of a Rust workspace with a dozen of crates, including only one binary crate, that I want to publish on crates.io.

I'd like to not publish the library crates that are only here as an attempt to separate concerns and shorten build times, so they are not really thought to be reused outside of my project, but right now I'm struggling to get the result I want and just publish the binary crate.

For now my main attempt has been to add this to the workspace's Cargo.toml :

[[bin]]
name = "my_project_binary_name"
path = "my_project_binary_name/src/main.rs"

But what I get this error message from cargo publish --dry-run from the root of my workspace :

error: couldn't read my_project_binary_name/src/main.rs: No such file or directory (os error 2)
error: could not compile `my_project_binary_name` (bin "my_project_binary_name") due to previous error

Although obviously, the file exists.

I also tried, on top of that, to add the following to the Cargo.toml of my binary crate :

[[bin]]
name = "my_project_binary_name"
path = "src/main.rs"

And call cargo publish like following : ❯ cargo publish --dry-run --verbose --allow-dirty -p my_project_binary_name

But I get the following error message :

error: failed to prepare local package for uploading

Caused by:
  no matching package named `abstract_frontend` found
  location searched: registry `crates-io`

Where "abstract_frontend" is one of the library crates of my workspace. I'm afraid I'm missing how to tell cargo to look locally, even though in my binary crate's Manifest, the dependency is explicitly defined through a relative path.

Am I missing something or is what I want to do infeasible ?


Solution

  • Ok so after studying this a bit more and reading the comment of kmdreko, it seems that what I want to do is actually impossible.

    Registries actually store something quite close to the source code if I'm not mistaken, and thus need to have a stored reference to every dependency of a crate that is going to be published.

    So, I proceeded like following :

    1. I added a [workspace.package] section to my root Cargo.toml to mutualize as much metadata as possible between crates
    2. After that, in each crate, I added <metadata_name>.workspace = true for each metadata defined in root Cargo.toml, to explicitly state that they are inherited from root manifest.
    3. I renamed every directory containing a crate with some prefix/suffix to make it explicit that it's part of a greater project, and added a description to make it clear that people probably cannot do anything good with it. (not really proud of this tbh)
    4. I went into every Cargo.toml file to replace the way I define dependencies, going from : toto = { path = "../toto" } to toto = {package = "prefix_toto", path = "../prefix_toto", version = "0.1.0" } so that it works both when building locally or through cargo, without having to rename everything in my source code.
    5. Define the dependency tree between my crates (cargo tree helps here, but there's probably a better tool in the wild), and upload them in the appropriate order. (Knowing that crates.io does not like too much when you upload too many crates too fast, it'll ask you to wait an hour after half a dozen of uploads)

    The lesson here is : Workspaces are great, but its probably not what you want to use to structure your project if you intend to upload it on crates.io, except if you're really making very generic bricks that could really be reused by other people. Sometimes one big crate makes your life a bit easier.