是否可以让 cargo install 安装依赖的 cdylib dll

is it possible to make cargo install installing dependent cdylib dlls

我在 windows 并且

一个 Rust cdylib

[package]
name = "test1dll"
[lib]
crate-type = ["cdylib"]

和依赖于该 dll 的 Rust 二进制文件

[package]
name = "test1"
[dependencies]
test1dll = { path = "..." }

并且正在寻找制作方法

cargo install

同时安装 test1.exetest1dll.dll,或者,如果无法使用 cargo,则可以使用不太复杂的替代方法。

该库需要是一个 dll,这样我才能 LoadLibrary 它。静态库将不起作用。

我可以在 target/*/deps 目录中看到二进制文件和 dll,但是 cargo install 只安装了可执行文件。

运行 cargo install 来自dll项目本身给出了一个

error: no packages found with binaries or examples.

documentation

匹配

This command manages Cargo's local set of installed binary crates. Only packages which have executable [[bin]] or [[example]] targets can be installed

但是因为在 windows 上部署一个二进制文件和一个 dll 是一个有用的场景,Rust 甚至提供了将 cdylib 目标编译成 dll 的可能性,我想知道是否有办法用 cargo 来做到这一点。不幸的是,我是 Rust 的新手,可能使用了错误的关键字进行搜索。

我认为 this 可能接近,但明确排除了运行时:

Note that cargo only supplies these dependencies when building your crate. If your program or library requires artifacts at runtime, you will still need to handle that yourself by some other means.

要么是我用错了,要么cdylib-plugin对安装dll也没有帮助。

Rust 旨在编译为单个程序,这是 C++ 用户反对 Rust 的论点之一。 Rust 二进制文件要大得多,因为所有库都是静态 linked 而不是动态 linked。是否有特定原因需要动态 link 而不是静态 link?

target/*/deps 文件夹包含静态linked 到您的二进制文件的已编译库。

用 cargo 安装 dll 和 exe 确实是不可能的。但是可以将 dll 二进制流作为 blob 添加到 exe 并在第一个 运行 上重新创建 dll。 有两个缺点:

  1. cargo uninstall 不会卸载 dll
  2. 在构建过程中使用子包创建dll时,无法发布包because

Regardless of whether exclude or include is specified, the following files are always excluded: Any sub-packages will be skipped (any subdirectory that contains a Cargo.toml file).

这可以通过在主包 build.rs 期间创建子包的 Cargo.toml 来解决。货物会抱怨

error: failed to verify package tarball Caused by: Source directory was modified by build.rs during cargo publish. Build scripts should not modify anything outside of OUT_DIR.

但也暗示

To proceed despite this, pass the --no-verify flag.

所以这很好。

基本流程是这样的:

  1. 创建一个定义 cdylib 的子包
  2. 在主包中创建一个build.rs,其中
  • 为子包调用 cargo build

:

std::process::Command::new("cargo")
    .stdout(std::process::Stdio::inherit())
    .current_dir(sub_package_dir)
    .arg("build")
    .arg("--release")
    .arg("-vv")
    .status()
    .unwrap();
  • 然后动态创建一个包含 dll 字节流的 Rust 源和一个访问它的函数

:

let dll_src_str = format!(
    "const DLL_BIN: &[u8] = include_bytes!(r\"{}\");
    pub fn dll_bin() -> &'static [u8] {{ DLL_BIN }}",
    dll_path);
let mut dll_src_file =
    std::fs::File::create(dll_src_path).unwrap();
use std::io::prelude::*;
let write_ok = dll_src_file.write_all(dll_src_str.as_bytes());

build.rs 执行完毕后,构建过程将查找并编译创建的附加源。

  1. 在程序执行期间创建 dll 文件

:

pub fn create_dll() -> std::io::Result<()> {
    let dll_bytes = dll_contents::dll_bytes();
    let mut dll_file = std::fs::File::create(dll_path).unwrap();
    use std::io::prelude::*;
    return dll_file.write_all(dll_bytes);
}