web-dev-qa-db-ja.com

Rustライブラリとバイナリの両方を含むパッケージ?

再利用可能なライブラリ(ほとんどのプログラムが実装されている)と、それを使用する実行可能ファイルの両方を含むRustパッケージを作成したいと思います。

Rustモジュールシステムのセマンティクスを混乱させていないと仮定すると、Cargo.tomlファイルはどのように見えますか?

119
Andrew Wagner
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();
}
136
Doug

バイナリソースをsrc/binに配置し、残りのソースをsrcに配置することもできます。 my project に例を見ることができます。 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)
}

src/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を作成することもできます。残念ながら、これはcargo docコマンドと競合します。

ライブラリとバイナリが同じ名前のパッケージをドキュメント化できません。ターゲットの名前を変更するか、ターゲットをdoc = falseとしてマークすることを検討してください

104
Shepmaster

別の解決策は、両方を1つのパッケージに詰め込もうとしないことです。フレンドリーな実行可能ファイルを使用する少し大きなプロジェクトの場合、 workspace を使用すると非常に良いことがわかりました。

内部にライブラリを含むバイナリプロジェクトを作成します。

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)

このスキームには2つの大きな利点があります。

  1. バイナリは、これにのみ適用される依存関係を使用できるようになりました。たとえば、コマンドラインパーサーや端末の書式設定など、ユーザーエクスペリエンスを向上させるために多数のクレートを含めることができます。これらのいずれもライブラリに「感染」しません。

  2. ワークスペースは、各コンポーネントの重複ビルドを防ぎます。 mylibrarycargo buildの両方のディレクトリでthe-binaryを実行すると、ライブラリは両方ともビルドされず、両方のプロジェクト間で共有されます。

22
Shepmaster

lib.rsmain.rsをsourcesフォルダーにまとめることができます。 競合はありませんそして貨物は両方を構築します。

ドキュメントの競合を解決するには、Cargo.tomlに追加します。

[[bin]]
name = "main"
doc = false
17
DenisKolodin