Пакет ржавчины с библиотекой и двоичным?
Я хотел бы сделать пакет Rust, содержащий как многократно используемую библиотеку (где большая часть программы реализована), так и исполняемый файл, который его использует.
Предполагая, что я не путал какую-либо семантику в модульной системе Rust, должен ли выглядеть файл Cargo.toml
?
Ответы
Ответ 1
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 <[email protected]>"]
[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();
}
Ответ 2
Вы также можете просто поместить двоичные источники в src/bin
а остальные источники - в src
. Вы можете увидеть пример в моем проекте. Вам вообще не нужно изменять ваш Cargo.toml
, и каждый исходный файл будет скомпилирован в двоичный файл с тем же именем.
Затем конфигурация других ответов заменяется на:
$ tree
.
├── Cargo.toml
└── src
├── bin
│ └── mybin.rs
└── lib.rs
Cargo.toml
[package]
name = "example"
version = "0.0.1"
authors = ["An Devloper <[email protected]>"]
SRC/lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
Ok(a + b)
}
ЦСИ /bin/mybin.rs
extern crate example;
fn main() {
println!("I'm using the library: {:?}", example::really_complicated_code(1, 2));
}
И выполнить это:
$ cargo run --bin mybin
I'm using the library: Ok(3)
Кроме того, вы можете просто создать src/main.rs
который будет использоваться в качестве исполняемого файла defacto. К сожалению, это конфликтует с командой cargo doc
:
Невозможно задокументировать пакет, в котором библиотека и двоичный файл имеют одинаковые имена. Подумайте о переименовании или пометке цели как doc = false
Ответ 3
Альтернативное решение - на самом деле не пытаться собрать обе вещи в один пакет. Для проектов немного больших размеров с дружественным исполняемым файлом я нахожу очень полезным использовать рабочее пространство
Мы создаем бинарный проект, который включает в себя библиотеку:
the-binary
├── Cargo.lock
├── Cargo.toml
├── mylibrary
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
└── src
└── main.rs
Cargo.toml
Это использует ключ [workspace]
и зависит от библиотеки:
[package]
name = "the-binary"
version = "0.1.0"
authors = ["An Devloper <[email protected]>"]
[workspace]
[dependencies]
mylibrary = { path = "mylibrary" }
SRC/main.rs
extern crate mylibrary;
fn main() {
println!("I'm using the library: {:?}", mylibrary::really_complicated_code(1, 2));
}
MyLibrary/SRC/lib.rs
use std::error::Error;
pub fn really_complicated_code(a: u8, b: u8) -> Result<u8, Box<Error>> {
Ok(a + b)
}
И выполнить это:
$ 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)
У этой схемы есть два больших преимущества:
-
Двоичный файл теперь может использовать зависимости, которые применяются только к нему. Например, вы можете включить множество ящиков для улучшения взаимодействия с пользователем, таких как анализаторы командной строки или форматирование терминала. Ни один из них не "заразит" библиотеку.
-
Рабочая область предотвращает избыточные сборки каждого компонента. Если мы запустим cargo build
как в mylibrary
и the-binary
каталоге, библиотека не будет собрана оба раза - она будет разделена между обоими проектами.
Ответ 4
Вы можете поместить lib.rs
и main.rs
в папку источников вместе. Нет конфликта, и груз будет строить обе вещи.
Чтобы разрешить конфликт documentaion, добавьте в свой Cargo.toml
:
[[bin]]
name = "main"
doc = false