将二进制crate移至src/bin后出现导入解析失败问题
初始项目结构
. ├── Cargo.toml └── src ├── main.rs ├── generator.rs └── lib.rs
初始代码文件
lib.rs
pub mod generator
main.rs
use clap::{Parser, Subcommand}; use mypackage::generator;
此时项目可正常构建。
结构调整
将main.rs移动到src/bin目录下并重命名为check.rs,新的项目结构如下:
. ├── Cargo.toml └── src ├── bin │ └── check.rs ├── generator.rs └── lib.rs
构建报错
执行cargo build后出现以下编译错误:
error[E0432]: unresolved imports `mypackage::generator` --> src/bin/check.rs:5:5 | 5 | generator::Generator, | ^^^^^^^^^ could not find `generator` in `mypackage` error[E0432]: unresolved import `clap` --> src/bin/check.rs:3:5 | 3 | use clap::{Parser, Subcommand}; | ^^^^ use of undeclared crate or module `clap`
疑问
- 参考StackOverflow的回答,未修改Cargo.toml,为什么会出现这个问题?
- 为什么二进制crate无法解析Cargo.toml中已经声明的clap依赖?
项目的Cargo.toml内容
[package] name = "mypackage" version = "0.1.0" edition = "2021" [dependencies] clap = {version = "4.1.8", features = ["derive"], optional = true} dot = {version = "0.1.4", optional = true} enumset = "1.0.12" inkwell = {version = "0.1.1", features = ["llvm15-0"], optional = true} itertools = "0.10.5" lalrpop-util = "0.19.8" once_cell = "1.17.1" rayon = "1.7.0" regex = "1.7.1" snailquote = "0.3.1" strum = {version = "0.24.1", features = ["derive"]} tracing = "0.1.37" tracing-subscriber = {version = "0.3.16", features = ["env-filter"]} [build-dependencies] lalrpop = "0.19.9" [features] default = [] generate = [] bin = ["generate", "dep:clap"]
执行的构建命令为cargo build。
问题1:未修改Cargo.toml却出现导入错误的原因
原来的main.rs是包的默认二进制目标,它会自动继承包的特性配置。但把文件移到src/bin后,这个二进制文件变成了独立的目标,默认情况下只会启用default特性集合里的配置,而你的default = []是空的。
虽然当前generate特性是空的,但如果generator模块的代码是被#[cfg(feature = "generate")]这类特性开关限制的,那么默认构建时库不会编译这部分代码,自然就找不到mypackage::generator。
问题2:二进制crate无法解析clap的原因
你的clap依赖被标记为optional = true,并且只有在启用bin特性时才会被引入(bin = ["generate", "dep:clap"])。默认构建不会启用bin特性,所以Cargo不会把clap编译进项目,导致二进制目标找不到这个依赖。
解决办法
方法1:构建时显式指定特性
执行构建命令时加上特性参数:
cargo build --features bin
方法2:为二进制目标单独配置特性
修改Cargo.toml,给check这个二进制目标指定必须启用的特性:
[[bin]] name = "check" required-features = ["bin"]
这样每次构建这个二进制文件时,都会自动启用bin特性。
方法3:调整特性默认配置(不推荐,除非所有目标都需要)
如果希望所有目标默认都启用bin特性,可以修改features部分:
[features] default = ["bin"] generate = [] bin = ["generate", "dep:clap"]
方法4:移除generator的特性限制(如果不需要)
如果generator模块不需要依赖特性,直接去掉相关的#[cfg]标记,确保lib.rs里的pub mod generator始终可见,这样无论是否启用特性,库都会导出这个模块。
内容的提问来源于stack exchange,提问作者diviquery

