Pakete und Crates
Die ersten Teile des Modulsystems, die wir behandeln werden, sind Pakete und Crates.
Eine Crate (Kiste) ist die kleinste Menge an Code, die der Rust-Compiler zu
einem bestimmten Zeitpunkt berücksichtigt. Selbst wenn du rustc anstelle von
cargo ausführst und eine einzelne Quellcodedatei übergibst (wie wir es bereits
im Abschnitt „Grundlagen eines Rust-Programms“ in Kapitel 1 getan
haben), betrachtet der Compiler diese Datei als eine Crate. Crates können Module
enthalten, und die Module können in anderen Dateien definiert sein, die mit der
Crate kompiliert werden, wie wir in den nächsten Abschnitten sehen werden.
Es gibt zwei Arten von Crates: Binäre Crates und Bibliotheks-Crates. Binäre
Crates (binary crates) sind Programme, die du zu einer ausführbaren Datei
kompilieren und starten kannst, z.B. ein Befehlszeilenprogramm oder einen
Server. Diese müssen eine Funktion namens main haben, die definiert, was
passiert, wenn die ausführbare Datei läuft. Alle Crates, die wir bisher erstellt
haben, waren binäre Crates.
Bibliotheks-Crates (library crates) haben keine Funktion main und sie werden
nicht zu einer ausführbaren Datei kompiliert. Stattdessen definieren sie
Funktionalität, die für mehrere Projekte gemeinsam genutzt werden soll. Zum
Beispiel bietet die Crate rand, die wir in Kapitel 2 verwendet haben,
Funktionalität, die Zufallszahlen erzeugt. Wenn Rust-Entwickler „Crate“ sagen,
meinen sie meistens „Bibliotheks-Crates“, und sie verwenden „Crate“ austauschbar
mit dem allgemeinen Programmierkonzept einer „Bibliothek“.
Die Crate-Wurzel ist eine Quelldatei, von der der Rust-Compiler ausgeht und die das Wurzel-Modul deiner Crate bildet (Module werden in „Gültigkeitsbereich und Sichtbarkeit mit Modulen steuern“ ausführlich erklärt).
Ein Paket ist ein Bündel von einer oder mehreren Crates, die eine Reihe von Funktionalitäten bereitstellen. Ein Paket enthält eine Datei Cargo.toml, die beschreibt, wie diese Crates zu bauen sind. Cargo ist eigentlich ein Paket, das die binäre Crate für das Kommandozeilenwerkzeug enthält, das du zum Erstellen deines Codes verwendet hast. Das Cargo-Paket enthält auch eine Bibliotheks-Crate, von der die binäre Crate abhängt. Andere Projekte können von der Bibliotheks-Crate Cargo abhängen, um die gleiche Logik wie das Befehlszeilenwerkzeug Cargo zu verwenden.
Ein Paket kann beliebig viele binäre Crates enthalten, aber höchstens eine Bibliotheks-Crate. Ein Paket muss mindestens eine Crate enthalten, unabhängig davon, ob es sich um eine Bibliotheks-Crate oder eine binäre Crate handelt.
Lass uns durchgehen, was passiert, wenn wir ein Paket erstellen. Zuerst geben
wir den Befehl cargo new my-project ein:
$ cargo new my-project
Created binary (application) `my-project` package
$ ls my-project
Cargo.toml
src
$ ls my-project/src
main.rs
Nachdem wir cargo new my-project ausgeführt haben, verwenden wir ls, um zu
sehen, was Cargo erzeugt. Im Projektverzeichnis my-project gibt es eine Datei
Cargo.toml, die uns ein Paket gibt. Es gibt auch ein Verzeichnis src, das
main.rs enthält. Öffne Cargo.toml in deinem Texteditor und beachte, dass
src/main.rs nicht erwähnt wird. Cargo folgt der Konvention, dass src/main.rs
die Crate-Wurzel einer binären Crate mit dem gleichen Namen wie das Paket ist.
Ebenso weiß Cargo: Wenn das Paketverzeichnis src/lib.rs enthält, enthält das
Paket eine Bibliotheks-Crate mit dem gleichen Namen wie das Paket, und
src/lib.rs ist deren Crate-Wurzel. Cargo übergibt die Crate-Wurzeldateien an
rustc, um die Bibliothek oder Binärdatei zu bauen.
Hier haben wir ein Paket, das nur src/main.rs enthält, d.h. es enthält nur
eine binäre Crate mit dem Namen my-project. Wenn ein Paket src/main.rs und
src/lib.rs enthält, hat es zwei Crates: Eine binäre und eine Bibliothek, beide
mit dem gleichen Namen wie das Paket. Ein Paket kann mehrere binäre Crates
haben, indem es Dateien im Verzeichnis src/bin ablegt: Jede Datei ist dann
eine eigene binäre Crate.