如何防止与货物的间接特征依赖?

Fed*_*ico 5 dependencies rust rust-cargo

cargo当编译由多个包组成的 Rust 工作区时,当包的成功编译foo依赖于其依赖项启用的功能时,是否有办法出错?foo

\n

让我举一个具体的例子。使用下面描述的工作区cargo build会成功,但cargo build -p foo会出现编译错误,因为tokio中缺少功能foo/Cargo.toml

\n
error[E0432]: unresolved import `tokio::io::AsyncWriteExt`\n --> foo/src/lib.rs:1:5\n  |\n1 | use tokio::io::AsyncWriteExt;\n  |     ^^^^^^^^^^^-------------\n  |     |          |\n  |     |          help: a similar name exists in the module: `AsyncWrite`\n  |     no `AsyncWriteExt` in `io`\n\nFor more information about this error, try `rustc --explain E0432`.\nerror: could not compile `foo` due to previous error\n
Run Code Online (Sandbox Code Playgroud)\n

这不好!cargo build愉快地接受间接依赖的用法。也就是说,更改既不foo依赖项中也不在其依赖项中的代码(即io-util从 中删除该功能bar/Cargo.toml)可能会在 中引入编译错误foo。我想检测并防止这种情况,而不必每次都尝试单独编译每个包。

\n
\n

工作区结构:

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 lib.rs\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Cargo.toml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 main.rs\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Cargo.toml\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Cargo.toml\n
Run Code Online (Sandbox Code Playgroud)\n

./foo/src/lib.rs

\n
error[E0432]: unresolved import `tokio::io::AsyncWriteExt`\n --> foo/src/lib.rs:1:5\n  |\n1 | use tokio::io::AsyncWriteExt;\n  |     ^^^^^^^^^^^-------------\n  |     |          |\n  |     |          help: a similar name exists in the module: `AsyncWrite`\n  |     no `AsyncWriteExt` in `io`\n\nFor more information about this error, try `rustc --explain E0432`.\nerror: could not compile `foo` due to previous error\n
Run Code Online (Sandbox Code Playgroud)\n

./foo/Cargo.toml

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 foo\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 lib.rs\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Cargo.toml\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 bar\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 main.rs\n\xe2\x94\x82\xc2\xa0\xc2\xa0 \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Cargo.toml\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 Cargo.toml\n
Run Code Online (Sandbox Code Playgroud)\n

./bar/src/main.rs

\n
use tokio::io::AsyncWriteExt;\n\npub fn dummy(_: impl AsyncWriteExt) {\n    unimplemented!()\n}\n
Run Code Online (Sandbox Code Playgroud)\n

./bar/Cargo.toml

\n
[package]\nname = "foo"\nversion = "0.1.0"\nedition = "2021"\n\n[dependencies]\n"tokio" = "1.21.2"\n
Run Code Online (Sandbox Code Playgroud)\n

./Cargo.toml

\n
fn main() {\n    println!("Hello, world!");\n}\n
Run Code Online (Sandbox Code Playgroud)\n

And*_*sen 1

不幸的是,cargo build --workspace这还不够,因为它一次构建所有包成员,执行功能统一。

要单独构建工作区中的每个包,您可以使用子cargo-hack命令。

要安装子命令,请运行:

cargo install cargo-hack
Run Code Online (Sandbox Code Playgroud)

安装后,您可以运行以下命令来单独构建所有工作区包:

cargo hack build --workspace
Run Code Online (Sandbox Code Playgroud)

输出如您所料:

error[E0432]: unresolved import `tokio::io::AsyncWriteExt`
 --> foo/src/lib.rs:1:5
  |
1 | use tokio::io::AsyncWriteExt;
  |     ^^^^^^^^^^^-------------
  |     |          |
  |     |          help: a similar name exists in the module: `AsyncWrite`
  |     no `AsyncWriteExt` in `io`

For more information about this error, try `rustc --explain E0432`.
error: could not compile `foo` due to previous error
Run Code Online (Sandbox Code Playgroud)

这相当于单独构建每个包,但可以通过单个命令完成。有关更多详细信息,请参阅该标志的自述文件条目。--workspace