You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:17:53