如何让Cargo自动将编译的Rust DLL输出到指定路径?
自动将Rust编译的DLL输出到plugins目录的配置方法
方法一:给每个DLL crate添加Build脚本
这是最直接的实现方式,通过每个插件crate的build.rs脚本,在编译完成后自动将DLL文件复制到指定的plugins目录。
步骤1:配置DLL crate的Cargo.toml
如果你的插件是动态链接库(cdylib),确保在Cargo.toml中指定编译类型:
[package] name = "my_plugin" version = "0.1.0" edition = "2021" [lib] crate-type = ["cdylib"] # 编译为动态链接库格式
如果是可执行类型的DLL(bin crate),只需保证src/main.rs存在即可,无需额外配置crate-type。
步骤2:编写build.rs脚本
在每个插件crate的根目录创建build.rs文件,写入以下逻辑:
use glob::glob; use std::env; use std::fs; use std::path::Path; fn main() { // 获取当前crate名称与编译模式(debug/release) let crate_name = env::var("CARGO_PKG_NAME").expect("无法获取crate名称"); let profile = env::var("PROFILE").expect("无法获取编译模式"); // 匹配编译后的DLL文件路径(兼容bin和cdylib产物格式) let dll_pattern = format!("target/{profile}/deps/{crate_name}*.dll"); let mut dll_paths = glob(&dll_pattern) .expect("匹配DLL路径失败") .filter_map(Result::ok); if let Some(src_dll) = dll_paths.next() { // 定位工作区根目录下的plugins文件夹 let workspace_root = Path::new(env::var("CARGO_MANIFEST_DIR").unwrap()) .ancestors() .nth(1) // 假设插件crate在工作区子目录(如crates/my_plugin),向上跳转一级到工作区根 .expect("无法找到工作区根目录"); let dest_dir = workspace_root.join("plugins"); // 自动创建目标目录(不存在时) fs::create_dir_all(&dest_dir).expect("创建plugins目录失败"); // 复制DLL到目标目录,使用crate名称作为文件名(去除编译自动生成的哈希后缀) let dest_dll = dest_dir.join(format!("{crate_name}.dll")); fs::copy(&src_dll, &dest_dll).expect("复制DLL到plugins目录失败"); // 告诉Cargo:当源DLL文件变化时重新执行build脚本 println!("cargo:rerun-if-changed={}", src_dll.display()); } }
步骤3:添加build依赖
在插件crate的Cargo.toml中添加glob依赖,用于匹配DLL文件路径:
[build-dependencies] glob = "0.3"
方法二:工作区级别脚本统一处理
如果有大量插件crate,可以编写一个单独的工具crate,在工作区编译完成后批量复制所有DLL到plugins目录。
步骤1:创建工具crate
在工作区中新建copy_plugins crate,配置为可执行类型:
[package] name = "copy_plugins" version = "0.1.0" edition = "2021" [dependencies] glob = "0.3"
步骤2:编写批量复制逻辑
在src/main.rs中写入以下代码:
use glob::glob; use std::fs; use std::path::Path; fn main() { // 替换为你实际的插件crate名称列表 let plugin_crates = ["plugin_a", "plugin_b", "plugin_c"]; let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string()); let workspace_root = std::env::current_dir().unwrap(); let dest_dir = workspace_root.join("plugins"); fs::create_dir_all(&dest_dir).unwrap(); for crate_name in plugin_crates { let pattern = format!("target/{profile}/deps/{crate_name}*.dll"); let mut dll_paths = glob(&pattern).unwrap().filter_map(Result::ok); if let Some(src_dll) = dll_paths.next() { let dest_dll = dest_dir.join(format!("{crate_name}.dll")); fs::copy(&src_dll, &dest_dll).unwrap(); println!("已复制 {} 到plugins目录", crate_name); } } }
步骤3:编译后自动执行工具
可以将编译和复制命令合并为脚本,避免手动执行:
- Windows批处理(
build.bat):
cargo build --workspace cargo run -p copy_plugins
- Linux/macOS shell脚本(
build.sh):
cargo build --workspace && cargo run -p copy_plugins
注意事项
- 如果插件crate直接在工作区根目录,需修改
build.rs中ancestors().nth(1)为nth(0),或直接使用CARGO_MANIFEST_DIR作为工作区根路径。 - 编译Release版本时,只需执行
cargo build --workspace --release,脚本会自动读取release模式的产物路径。 - 跨平台适配:若需支持Linux(
.so)或macOS(.dylib),只需修改脚本中的文件扩展名匹配规则。
内容的提问来源于stack exchange,提问作者Bruno Massa
相关产品推荐
相关产品推荐

