带有库和二进制文件的Rust包?

And*_*ner 132 rust rust-cargo

我想制作一个包含可重用库(实现大部分程序)的Rust包,以及使用它的可执行文件.

假设我没有混淆Rust模块系统中的任何语义,我的Cargo.toml文件应该是什么样的?

Dou*_*oug 152

Tok:tmp doug$ du -a

8   ./Cargo.toml
8   ./src/bin.rs
8   ./src/lib.rs
16  ./src
Run Code Online (Sandbox Code Playgroud)

Cargo.toml:

[package]
name = "mything"
version = "0.0.1"
authors = ["me <me@gmail.com>"]

[lib]
name = "mylib"
path = "src/lib.rs"

[[bin]]
name = "mybin"
path = "src/bin.rs"
Run Code Online (Sandbox Code Playgroud)

SRC/lib.rs:

pub fn test() {
    println!("Test");
}
Run Code Online (Sandbox Code Playgroud)

SRC/bin.rs:

extern crate mylib; // not needed since Rust edition 2018

use mylib::test;

pub fn main() {
    test();
}
Run Code Online (Sandbox Code Playgroud)

  • @CMCDragonkai这是toml格式规范[[x]]是一个反序列化的数组; 即.单个包可能会生成多个二进制文件,但只能生成一个库(因此[lib],而不是[[lib]]).您可以有多个bin部分.(我同意,这看起来很奇怪,但是toml总是一个有争议的选择). (24认同)
  • 你知道为什么`[[bin]]`是一个表数组吗?为什么要使用`[[bin]]`而不是`[bin]`?似乎没有任何关于此的文件. (20认同)
  • 当您使用Cargo时,这些选项是不必要的,因为Cargo将它们作为编译器标志传递.如果你运行`cargo build --verbose`,你会在`rustc`命令行中看到它们. (4认同)
  • 谢谢道格,我会试试的!那么 #![crate_name= ] 和 #![crate_type] 注释是可选的吗? (2认同)
  • 当我想要的只是 lib 时,有没有办法阻止它编译二进制文件?二进制文件具有额外的依赖项,我通过一个名为“二进制”的功能添加了这些依赖项,当我尝试在没有该功能的情况下编译它时,它无法构建。它抱怨它找不到 bin.rs 试图导入的板条箱。 (2认同)

She*_*ter 112

您也可以将二进制源src/bin和其他源放入其中src.您可以在我的项目中看到一个示例.您根本不需要修改Cargo.toml,每个源文件将被编译为同名的二进制文件.

然后将另一个答案的配置替换为:

$ tree
.
??? Cargo.toml
??? src
    ??? bin
    ?   ??? mybin.rs
    ??? lib.rs
Run Code Online (Sandbox Code Playgroud)

Cargo.toml

[package]
name = "example"
version = "0.0.1"
authors = ["An Devloper <an.devloper@example.com>"]
Run Code Online (Sandbox Code Playgroud)

SRC/lib.rs

use std::error::Error;

pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
    Ok(a + b)
}
Run Code Online (Sandbox Code Playgroud)

SRC /斌/ mybin.rs

extern crate example;

fn main() {
    println!("I'm using the library: {:?}", example::really_complicated_code(1, 2));
}
Run Code Online (Sandbox Code Playgroud)

并执行它:

$ cargo run --bin mybin
I'm using the library: Ok(3)
Run Code Online (Sandbox Code Playgroud)

此外,您可以创建一个src/main.rs将用作事实可执行文件的程序.不幸的是,这与cargo doc命令冲突:

无法记录库和二进制文件具有相同名称的包.考虑重命名一个或将目标标记为doc = false

  • 适合生锈的常规配置方法!两个答案在一起,你有一些非常方便和灵活. (10认同)
  • 在rust 2018之前不需要`extern crate example;`,您可以直接编写`use example :: really_complicated_code;`并使用该函数而无需命名范围 (2认同)

She*_*ter 26

另一种解决方案是实际上不尝试将两个东西塞进一个包中.对于具有友好可执行文件的稍大的项目,我发现使用工作区非常好

我们创建一个二进制项目,其中包含一个库:

the-binary
??? Cargo.lock
??? Cargo.toml
??? mylibrary
?   ??? Cargo.toml
?   ??? src
?       ??? lib.rs
??? src
    ??? main.rs
Run Code Online (Sandbox Code Playgroud)

Cargo.toml

这使用[workspace]密钥并依赖于库:

[package]
name = "the-binary"
version = "0.1.0"
authors = ["An Devloper <an.devloper@example.com>"]

[workspace]

[dependencies]
mylibrary = { path = "mylibrary" }
Run Code Online (Sandbox Code Playgroud)

SRC/main.rs

extern crate mylibrary;

fn main() {
    println!("I'm using the library: {:?}", mylibrary::really_complicated_code(1, 2));
}
Run Code Online (Sandbox Code Playgroud)

在MyLibrary/SRC/lib.rs

use std::error::Error;

pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
    Ok(a + b)
}
Run Code Online (Sandbox Code Playgroud)

并执行它:

$ cargo run
   Compiling mylibrary v0.1.0 (file:///private/tmp/the-binary/mylibrary)
   Compiling the-binary v0.1.0 (file:///private/tmp/the-binary)
    Finished dev [unoptimized + debuginfo] target(s) in 0.73 secs
     Running `target/debug/the-binary`
I'm using the library: Ok(3)
Run Code Online (Sandbox Code Playgroud)

这个方案有两大好处:

  1. 二进制文件现在可以使用仅适用于它的依赖项.例如,您可以包含许多包以改善用户体验,例如命令行解析器或终端格式.这些都不会"感染"图书馆.

  2. 工作空间可防止每个组件的冗余构建.如果我们cargo build同时在mylibrarythe-binary目录中运行,那么两次都不会构建库 - 它在两个项目之间共享.

  • @Jspies我能想到的最大的缺点是,有一些工具不完全知道如何处理工作空间.当与具有某种"项目"概念的现有工具交互时,它们处于一种奇怪的位置.我个人倾向于采用连续方法:我从`main.rs`中的所有内容开始,然后在它变大时将其分解为模块,最后在它稍微大一点时拆分为`src/bin`,然后转移到我开始大量重用核心逻辑时的工作空间. (3认同)
  • @Stein我想你想进行货运测试-全部 (3认同)
  • 这似乎是一个更好的方法。显然,这个问题已经过去好几年了,但人们仍然在为组织大型项目而苦苦挣扎。与上面选择的答案相比,使用工作区有什么缺点吗? (2认同)
  • @Shepmaster你能解释一下为什么你使用`[dependency]`而不是`members = ["the-library"]` (2认同)

Den*_*din 17

你可以把lib.rsmain.rs到sources文件夹在一起.没有冲突,货物将构建两件事.

要解决文档冲突,请添加到您的Cargo.toml:

[[bin]]
name = "main"
doc = false
Run Code Online (Sandbox Code Playgroud)

  • “ *此外,您还可以创建一个src / main.rs用作实际可执行文件*”。在另一个答案中,不是吗?并且文档冲突可以通过接受的答案解决,对吗?您可能需要澄清答案,以说明其独特之处。可以参考其他答案来建立它们。 (3认同)