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


190

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

Rustモジュールシステムのセマンティクスを混同していないとすると、Cargo.tomlファイルはどのようになりますか?

回答:


205
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();
}

2
ダグに感謝します、私はそれを試します!#![crate_name =]と#![crate_type]の注釈はオプションですか?
Andrew Wagner

4
Cargoを使用する場合、これらのオプションはCargoがコンパイラフラグとして渡すため不要です。を実行cargo build --verboseすると、rustcコマンドラインに表示されます。
Vladimir Matveev 2014年

33
なぜ[[bin]]テーブルの配列なのか知っていますか?なぜ使用[[bin]]していませんか[bin]?これに関するドキュメントはないようです。
CMCDragonkai 2015

40
@CMCDragonkaiこれは、toml形式の仕様です[[x]]は、逆シリアル化された配列です。すなわち。単一のクレートで複数のバイナリを生成できますが、ライブラリは1つだけです(したがって、[[lib]]ではなく[lib])。複数のbinセクションを持つことができます。(私は同意します、これは奇妙に見えますが、tomlは常に論争の的になる選択でした)。
ダグ

1
libだけが必要なときにバイナリがコンパイルされないようにする方法はありますか?バイナリには、「バイナリ」と呼ばれる機能を介して追加する依存関係があり、その機能なしでコンパイルしようとすると、ビルドに失敗します。bin.rsがインポートしようとしているクレートが見つからないというメッセージが表示されます。
Person93

150

また、バイナリソースを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 <an.devloper@example.com>"]

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; // Optional in Rust 2018

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


13
rustのconvention-over-configurationアプローチとうまく適合します!両方が一緒に答えると、いくつかの便利さと柔軟性があります。
空飛ぶ羊

9
extern crate example;rust 2018の時点では必要ありません。use example::really_complicated_code;スコープに名前を付けなくても、関数を直接記述して使用できます
sassman

47

別の解決策は、両方を1つのパッケージに詰め込もうとしないことです。やや大規模なプロジェクトでフレンドリーな実行可能ファイルがある場合、ワークスペースを使用すると非常に便利です

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

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 <an.devloper@example.com>"]

[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. ワークスペースは、各コンポーネントの冗長なビルドを防ぎます。とディレクトリのcargo build両方で実行する場合、ライブラリは両方ともビルドされず、両方のプロジェクト間で共有されます。mylibrarythe-binary


これはもっと良い方法のようです。質問されてから数年が経ったことは明らかですが、人々は依然として大規模プロジェクトの組織化に苦労しています。上記で選択した回答と比較してワークスペースを使用することの欠点はありますか?
Jspies

4
@Jspies頭に浮かぶ最大の欠点は、ワークスペースの扱い方が完全にわからないツールがあることです。なんらかの「プロジェクト」コンセプトを持つ既存のツールとやり取りするとき、彼らは一種の奇妙な場所にいます。私は個人的には連続的なアプローチをとる傾向があります。まずはすべてをから始め、main.rsそれが大きくなるにつれてモジュールに分割し、最後にsrc/bin少しだけ大きくなるように分割し、コアロジックを大きく再利用し始めたらワークスペースに移動します。
シェプマスター2018年

おかげで私はそれにスピンを与えます。私の現在のプロジェクトには、プロジェクトの一部として開発されたが外部で使用されるいくつかのライブラリがあります。
Jspies

ビルドして正常に動作しますがcargo test、lib.rsの単体テストを無視するようです
Stein

3
@スタイン私はあなたが望むと思うcargo test --all
シェプマスター

18

あなたは置くことができますlib.rsし、main.rsソースが一緒にフォルダに移動します。衝突はなく、貨物は両方のものを構築します。

documentaionの競合を解決するには、Cargo.toml以下を追加します。

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

3
これは、「追加で、事実上の実行可能ファイルとして使用されるsrc / main.rsを作成することもできます。」他の答えでは、いいえ?そして、ドキュメントの矛盾は、受け入れられた答えによって解決されますよね?これがユニークな理由を示すために、回答を明確にする必要がある場合があります。他の回答を参考にして、それらに基づいて作成してもかまいません。
Shepmaster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.