I am trying to develop a binary. I believe that a significant piece of its functionality is reusable and belongs in its own library. As a result, I intend to develop binary crate B and library crate L, where B has a dependency on L.
However, I'm not sure how to make the dependencies work out. For development, I need to have B depend on L with a path dependency, because L hasn't been pushed to crates.io yet. However, when I push them to crates.io they should be pushed as separate packages, and B's package should depend on L via a crates.io dependency.
How should I develop these crates?
What I have tried:
I put both crates into a workspace for local development, then used [patch.crates-io] in the workspace to rewrite B's dependency on L into a path dependency. This also has compile time benefits, and lets me run all the repository's tests simultaneously. However, if I try to set profile settings on B, I get a warning that I should set the profile settings in the workspace:
warning: profiles for the non root package will be ignored, specify profiles at the workspace root:
package: /home/jrvanwhy/gitree/gitree/Cargo.toml
workspace: /home/jrvanwhy/gitree/Cargo.toml
However, I want those profile settings to apply when I publish B, where the workspace won't be present, so I don't want to specify them in the workspace.
If you intend on them being separate crates, they must be separate packages (2 separate Cargo.toml manifests). However, you could simply add a [[bin]] section to your manifest and the package can be both a library and an executable.
You can set the package's profiles for when they are on crates.io, even if they are ignored. In the workspace it is possible to set override profiles per package.
An alternative here is to specify both a path and a version dependency. Cargo will automatically switch to the version one for publishing, while using the path when compiling locally.
Something like
[dependencies]
L = { version = "1.0", path = "./L" }
Thank you daboross, that's what I was looking for! I didn't realize that Cargo would accept that.
I removed the workspace and instead used a Cargo config to combine the target directories between B and L, which gives me part of the advantage of a workspace.
Out of curiosity, why remove the workspace too? I've found that they're generally well supported by tooling and IDEs, and don't have many downsides.
For situations like this, if you're OK with putting them both in subdirectories, having one workspace which just encompases all of them but isn't a crate itself should "just work", and won't require any maintenance (will target symlinking persist through cargo clean?)
One of us should probably be a bug report to Cargo for this incorrect warning! I wonder what the best way to handle that would be - since they should warn if the crate isn't published. Eh - either way, it's a problem.
The team discussed this a bit. We feel like it would probably be best if cargo publish would copy the profile from the workspace into the member package. Does that sound like it would resolve your use case?
I have definitely felt uneasy with that warning, since it cannot be silenced. However, I'm also a little uncomfortable with adding config and machinery for silencing it (just to avoid complexity).
If you have a github account, it would be ideal if you commented on the github issue. If not, I could also relay anything you say here to them.