我想做一个Rust包,既包含可重用库(其中大部分程序是实现的),也包含使用它的可执行文件。
假设我没有混淆Rust模块系统中的任何语义,我的Cargo应该是什么?Toml文件长什么样?
我想做一个Rust包,既包含可重用库(其中大部分程序是实现的),也包含使用它的可执行文件。
假设我没有混淆Rust模块系统中的任何语义,我的Cargo应该是什么?Toml文件长什么样?
当前回答
简单的
创建一个src/main。Rs将被用作事实上的可执行文件。您不需要修改您的货物。Toml和此文件将被编译为与库同名的二进制文件。
项目内容:
% tree
.
├── Cargo.toml
└── src
├── lib.rs
└── main.rs
Cargo.toml
[package]
name = "example"
version = "0.1.0"
edition = "2018"
src / lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<dyn Error>> {
Ok(a + b)
}
src / main.rs
fn main() {
println!(
"I'm using the library: {:?}",
example::really_complicated_code(1, 2)
);
}
并执行它:
% cargo run -q
I'm using the library: Ok(3)
灵活的
如果您希望控制二进制文件的名称或有多个二进制文件,您可以在src/bin中创建多个二进制源文件,在src中创建其余的库源文件。你可以在我的项目中看到一个例子。您不需要修改您的货物。src/bin中的每个源文件都将被编译为同名的二进制文件。
项目内容:
% tree
.
├── Cargo.toml
└── src
├── bin
│ └── mybin.rs
└── lib.rs
Cargo.toml
[package]
name = "example"
version = "0.1.0"
edition = "2018"
src / lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<dyn Error>> {
Ok(a + b)
}
src / bin / mybin医院。
fn main() {
println!(
"I'm using the library: {:?}",
example::really_complicated_code(1, 2)
);
}
并执行它:
% cargo run --bin mybin -q
I'm using the library: Ok(3)
参见:
我如何指定哪个板条箱'货物运行'运行默认在一个货物工作空间的根?
其他回答
另一个解决方案是不要试图把这两件事塞进一个包里。对于带有友好可执行文件的稍微大一点的项目,我发现使用工作区非常好。
在这里,我创建了一个二进制项目,其中包括一个库,但有许多可能的方式来组织代码:
% tree the-binary
the-binary
├── Cargo.toml
├── src
│ └── main.rs
└── the-library
├── Cargo.toml
└── src
└── lib.rs
Cargo.toml
它使用[workspace]键,并依赖于库:
[package]
name = "the-binary"
version = "0.1.0"
edition = "2018"
[workspace]
[dependencies]
the-library = { path = "the-library" }
src / main.rs
fn main() {
println!(
"I'm using the library: {:?}",
the_library::really_complicated_code(1, 2)
);
}
图书馆/ Cargo.toml
[package]
name = "the-library"
version = "0.1.0"
edition = "2018"
图书馆/ src / lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<dyn Error>> {
Ok(a + b)
}
并执行它:
% cargo run -q
I'm using the library: Ok(3)
这个方案有两大好处:
二进制文件现在可以使用仅适用于它的依赖项。例如,您可以包含许多板条箱来改善用户体验,例如命令行解析器或终端格式化。这些都不会“感染”图书馆。 工作空间防止每个组件的冗余构建。如果我们同时在the-library和the-binary目录中运行cargo build,那么库将不会两次都被构建——它在两个项目之间共享。
Tok:tmp doug$ du -a
8 ./Cargo.toml
8 ./src/bin.rs
8 ./src/lib.rs
16 ./src
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"
src / lib.rs:
pub fn test() {
println!("Test");
}
src / bin.rs:
extern crate mylib; // not needed since Rust edition 2018
use mylib::test;
pub fn main() {
test();
}
你可以写上lib。Rs和main。Rs到资源文件夹一起。没有冲突,货物会建造这两个东西。
为了解决文档冲突,添加到你的Cargo.toml:
[[bin]]
name = "main"
doc = false
简单的
创建一个src/main。Rs将被用作事实上的可执行文件。您不需要修改您的货物。Toml和此文件将被编译为与库同名的二进制文件。
项目内容:
% tree
.
├── Cargo.toml
└── src
├── lib.rs
└── main.rs
Cargo.toml
[package]
name = "example"
version = "0.1.0"
edition = "2018"
src / lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<dyn Error>> {
Ok(a + b)
}
src / main.rs
fn main() {
println!(
"I'm using the library: {:?}",
example::really_complicated_code(1, 2)
);
}
并执行它:
% cargo run -q
I'm using the library: Ok(3)
灵活的
如果您希望控制二进制文件的名称或有多个二进制文件,您可以在src/bin中创建多个二进制源文件,在src中创建其余的库源文件。你可以在我的项目中看到一个例子。您不需要修改您的货物。src/bin中的每个源文件都将被编译为同名的二进制文件。
项目内容:
% tree
.
├── Cargo.toml
└── src
├── bin
│ └── mybin.rs
└── lib.rs
Cargo.toml
[package]
name = "example"
version = "0.1.0"
edition = "2018"
src / lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<dyn Error>> {
Ok(a + b)
}
src / bin / mybin医院。
fn main() {
println!(
"I'm using the library: {:?}",
example::really_complicated_code(1, 2)
);
}
并执行它:
% cargo run --bin mybin -q
I'm using the library: Ok(3)
参见:
我如何指定哪个板条箱'货物运行'运行默认在一个货物工作空间的根?