right, it's NOT part of the project, so it makes sense to NOT adding it as a workspace member.
this is just an opinion, but I think it does.
my use for a workspace is to share the build artifacts under a single target
directory, and that all dependency are managed by a single Cargo.lock
file, and their features are unified across all crates.
if I don't need these features, I don't usually put multiple packages into a single cargo workspace. I might still have multiple packages in a mono repo, but they don't need to be managed by cargo.
for example, since I use vscode to write rust code, occasionally I need to add additional folders to a vscode workspace, when there's no single top level "main" crate. rust-analyzer has no problem with such setup, I just use the rust-analyzer.linkedProjects
setting.
I have no problem with "loose" crate at all, but I don't think it's best fit for cargo workspaces. and by the fact you don't add it as a workspace member, I assume would think the same?
sadly, I don't think there is, at least not in a way as you described.
the thing is, cargo run
has this --manifest-path
option, but if the manifest file is in a subdirectory of the root workspace, and it was not a member of the workspace, then cargo will give the error.
your method is to make the package itself a workspace, the alternative is to exclude the subdirectory explicitly in the workspace manifest, both of which need to make changes to some Cargo.toml
.
another alternative is to use multiple workspace. but currently, cargo does have the limitation that workspace requires the members to be within a hierarchy of the root "Cargo.toml` manifest, (e.g. I cannot use "../../crates/foo" for a workspace member), making it tricky to create (overlapping) workspaces, but I did manage to come up with a hacky workaround (sort of):
# root directory Cargo.toml
[workspace]
members = ["crates/*"] # these are the "core" packages
exclude = ["ext"] # these are "loose" packages
# ext/Cargo.toml: this is optional
# a workspace to group all the "loose" packages
[workspace]
members = ["*"]
exclude = ["target/"] # exclude `target` from wildcard
# crates/foo/Cargo.tom: a "core" package with a library crate
[package]
name = "foo"
[lib]
path = "src/lib.rs"
# ext/bar/Cargo.toml: a "loose" package, with binary crates and more
[package]
name = "bar"
[[bin]]
name = "bar"
path = "src/main.rs"
# can use `path` dependencies just fine,
# they have nothing to do with workspace membership
[dependencies.foo]
path = "../../crates/foo"
I imagine this could work for some scenarios, but it is a ugly hack, and I don't like it at all.
project1 $ cargo run
error: a bin target must be available for `cargo run`
project1 $ cargo run --bin bar
error: no bin target named `bar`
project1 $ cargo run --manifest-path ext/Cargo.toml
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `ext/target/debug/bar`
Hello, world!
project1 $ cd ext
project1/ext $ cargo run
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/bar`
Hello, world!
note, it is OK for a package to be members of multiple wokspaces, that what I meant by "overlapping", e.g.:
# root directory Cargo.toml
[workspace]
members = ["crates/*", "ext/baz"] # explicitly add "ext/baz" although `ext` is excluded
exclude = ["ext"]
# ext/Cargo.toml
[workspace]
members = ["bar", "baz"]
P.S.
this trick is adapted from some C++ projects, where there can be multiple "project" or "build" files (e.g. .sln
or .vcproj
for msbuild, CMakeLists.txt
for cmake, etc) for the same codebase. basically, I "abuse" the project files as a build preset or profile, the setup typically has a structure similar to:
── project_root_directory/
├── include/
├── src/
├── lib/
├── msvc/
│ ├── winxp.vcproj
│ ├── nolibpnet.vcproj
│ └── wepoll.vcproj
├── cmake/
│ ├── smoke/CMakeLists.txt
│ ├── staging/CMakeLists.txt
│ └── wepoll/CMakeLists.txt
└── meson/...