Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Kapitel 02: Einrichtung der Arbeitsumgebung und erstes Programm

Bevor Sie Ihren ersten Rust-Code schreiben können, müssen Sie die Werkzeuge installieren, die Sie für die Entwicklung benötigen. In diesem Kapitel richten wir Ihre Arbeitsumgebung ein und erstellen Ihr allererstes lauffähiges Rust-Programm mit dem Paketmanager cargo.

In diesem Kapitel bieten wir Ihnen drei verschiedene Perspektiven auf das Thema an. Wählen Sie die Sicht, die am besten zu Ihrem Hintergrund passt:

  • Für Anfänger: Konzentriert sich auf die grundlegende Installation, die Einrichtung von VS Code und das Schreiben eines ersten einfachen Zufallszahlen-Programms.
  • Für Profis: Richtet sich an erfahrene Entwickler und beleuchtet Cargo-Build-Pipelines, SemVer-Auflösung, Debug/Release-Profile und Workspace-Architekturen.
  • Hardware-Sicht: Analysiert die LLVM-Kompilierungsschritte, statische Linker-Prozesse, binäre Stripping-Optimierungen und Hardware-Entropiequellen.

Begleitvideo zu Kapitel 2: Einrichtung & Erstes Programm


Kapitel 02: Einrichtung & Erstes Programm (Sicht für Anfänger)

In diesem Kapitel richten wir Schritt für Schritt deine Arbeitsumgebung ein und schreiben dein erstes lauffähiges Programm. Keine Sorge, wir gehen jeden Schritt gemeinsam durch!

1. Lernziele

Du wirst in diesem Abschnitt:

  • Die Rust-Werkzeuge mit dem offiziellen Installationsprogramm rustup auf deinem Rechner einrichten.
  • Deinen Code-Editor (VS Code) installieren und mit dem schlauen Helfer rust-analyzer ausstatten.
  • Ein neues Projekt mit dem Werkzeug cargo erstellen.
  • Ein Zufallszahlen-Programm schreiben, das eine Zahl von 1 bis 10 würfelt.

2. Die Installation mit rustup

Um Rust auf deinem Computer zu installieren, nutzen wir das Programm rustup. Du kannst dir rustup wie einen App-Store vorstellen, der speziell für die Programmiersprache Rust da ist. Es installiert für dich:

  • Den Compiler (rustc): Das Programm, das deinen geschriebenen Text in die Sprache des Computers übersetzt.
  • Das Build-System (cargo): Dein Bauleiter, der deine Projekte verwaltet und fremden Code herunterlädt.

Installationsschritte:

  1. Öffne das Terminal (die Kommandozeile) deines Computers.
  2. Tippe unter Linux oder macOS folgenden Befehl ein und drücke Enter:
    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
    
  3. Das Installationsprogramm fragt dich nach Optionen. Drücke einfach die Eingabetaste (Enter), um die empfohlene Standardinstallation (“1”) auszuwählen.
  4. Sehr wichtig: Damit dein Terminal weiß, wo die neuen Werkzeuge liegen, musst du das Terminal entweder einmal schließen und neu öffnen oder folgenden Befehl eingeben:
    source $HOME/.cargo/env
    

Überprüfe die Installation, indem du nach der Version fragst:

rustc --version

Wenn dort etwas wie rustc 1.75.0 steht, war die Installation erfolgreich!


3. Der schlaue Editor: VS Code und rust-analyzer

Programmieren in einem normalen Texteditor ist mühsam, weil man Tippfehler erst bemerkt, wenn man das Programm startet. Wir richten uns deshalb einen Editor ein, der uns beim Tippen hilft.

  1. Lade dir Visual Studio Code (VS Code) herunter und installiere es.
  2. Öffne VS Code. Klicke links in der Seitenleiste auf das Symbol für Erweiterungen (das Symbol sieht aus wie vier Quadrate).
  3. Suche nach rust-analyzer und klicke auf Installieren.

Tip

Der rust-analyzer liest deinen Code im Hintergrund sekündlich mit. Er zeichnet rote Wellenlinien unter Fehler (wie vergessene Semikolons oder falsche Variablennamen) und gibt dir direkt Tipps, wie du sie behebst. Er ist dein persönlicher Programmier-Assistent!


4. Ein neues Projekt erstellen

In Rust erstellen wir Projekte nicht manuell, sondern lassen das unseren Bauleiter Cargo machen.

Tippe folgenden Befehl in dein Terminal:

cargo new wuerfelspiel --bin

Das Flag --bin (kurz für binary) sagt Cargo, dass wir ein eigenständiges Programm erstellen wollen, das man direkt ausführen kann.

Cargo legt einen neuen Ordner an. Darin findest du:

  • Cargo.toml: Die Einkaufs- und Einstellungsliste deines Projekts. Hier tragen wir später Zubehör ein.
  • src/main.rs: Die Textdatei, in die wir unseren Rust-Code schreiben.

5. Code-Evolution: Das Würfelspiel schreiben

Öffne den Ordner wuerfelspiel in VS Code und öffne die Datei src/main.rs. Lösche den Inhalt und schreibe stattdessen folgenden Code hinein:

use rand::Rng; // 1. Wir aktivieren das Zufalls-Werkzeug (Rng)

fn main() {
    // 2. Wir würfeln eine Zahl von 1 bis inklusive 10
    let gewuerfelte_zahl = rand::thread_rng().gen_range(1..=10);
    
    // 3. Wir geben die Zahl auf dem Bildschirm aus
    println!("Du hast eine {} gewürfelt!", gewuerfelte_zahl);
}

Der erste Startversuch

Wechsle in deinem Terminal in den Projektordner (cd wuerfelspiel) und starte das Programm mit:

cargo run

Du wirst sehen, dass der Compiler meckert: “failed to resolve: use of undeclared crate or module ‘rand’”. Warum? Wir haben zwar gesagt: “Nutze das Werkzeug ‘rand’”, aber in unserer Einkaufsliste (Cargo.toml) steht dieses Werkzeug noch gar nicht drin!

Die Zutat einkaufen

Füge das Paket rand zu deinem Projekt hinzu, indem du folgenden Befehl im Terminal ausführst:

cargo add rand

Dieser Befehl trägt das Paket automatisch in deine Cargo.toml ein. Wenn du das Programm jetzt erneut mit cargo run startest, lädt Cargo das Paket aus dem Internet herunter, baut es ein und führt dein Programm aus. Du wirst ein Ergebnis sehen wie: Du hast eine 6 gewürfelt!


6. Key Takeaways

  • rustup installiert und aktualisiert deine Rust-Werkzeuge.
  • Cargo ist dein Bauleiter: cargo new erstellt Projekte, cargo add fügt Pakete hinzu und cargo run startet das Programm.
  • Cargo.toml ist die Konfigurationsdatei für dein Projekt.
  • Der rust-analyzer zeigt dir Programmierfehler sofort im Editor an.

Kapitel 02: Einrichtung & Erstes Programm (Sicht für Profis)

Dieses Kapitel behandelt die Cargo-Build-Infrastruktur, Dependency-Management, semantische Versionierung und die Trennung von Entwicklungs- und Produktionsprofilen.

1. Lernziele

In diesem Abschnitt werden Sie:

  • Verstehen, wie Cargo reproduzierbare Builds über Lockfiles erzwingt.
  • Die Funktionsweise der semantischen Versionierung (SemVer) bei Cargo analysieren.
  • Die Konfiguration von Build-Profilen in der Cargo.toml beherrschen.
  • Die Strukturierung von Cargo-Workspaces kennenlernen.

2. Item 2: Nutze Cargo zur Gewährleistung reproduzierbarer Builds

In der professionellen Entwicklung ist es kritisch, dass ein Programm auf dem Rechner des Entwicklers, auf dem CI-Server und in der Produktionsumgebung exakt gleich gebaut wird. Cargo stellt dies durch zwei Dateien sicher:

  1. Cargo.toml (Deklarative Konfiguration): Hier spezifiziert der Entwickler die direkten Abhängigkeiten und deren Versionsbereiche (z. B. rand = "0.8.5").
  2. Cargo.lock (Konkreter Zustands-Pin): Diese Datei wird von Cargo automatisch generiert. Sie enthält die exakten Versionsnummern und kryptografischen Hashes aller installierten Abhängigkeiten und deren Unterabhängigkeiten.
graph LR
    A[Cargo.toml] --> B(Cargo Build)
    B --> C[Cargo.lock generieren/lesen]
    C --> D[Kryptografischer Abgleich der Crates]
    D --> E[Reproduzierbares Binär-Artefakt]

Important

Check-in-Regel: Checken Sie die Cargo.lock bei eigenständigen Anwendungen (Binaries) immer in Ihre Versionsverwaltung (Git) ein. Bei Bibliotheken (Libraries) wird die Cargo.lock traditionell ignoriert (.gitignore), da die Bibliothek flexibel mit den Versionen des Nutzers kompatibel sein muss.


3. Semantische Versionierung (SemVer) in Cargo

Cargo verwendet die semantische Versionierung (Major.Minor.Patch). Standardmäßig nutzt Cargo das Caret-Symbol (^) als Standard-Operator:

  • rand = "0.8.5" entspricht ^0.8.5 und erlaubt Updates auf 0.8.6 oder 0.8.9, blockiert aber 0.9.0.
  • Bei Versionen vor 1.0.0 (Pre-1.0) gilt eine Besonderheit: 0.8.5 erlaubt keine Updates auf 0.9.0, da Minor-Versionen vor 1.0 als Major-Updates (mit brechenden API-Änderungen) behandelt werden.

4. Build-Profile (Debug vs. Release)

Cargo unterscheidet grundlegend zwischen Entwicklungs- und Produktions-Builds. Dies wird über Profile in der Cargo.toml gesteuert:

[profile.dev]
opt-level = 0      # Keine Optimierungen, schneller Compile-Vorgang
debug = true       # Debug-Symbole im Binär-Artefakt enthalten

[profile.release]
opt-level = 3      # Maximale Optimierungen (Inlining, Loop Unrolling)
lto = true         # Link-Time Optimization über Crate-Grenzen hinweg
codegen-units = 1  # Reduziert Parallelisierung beim Kompilieren für bessere Optimierung
  • cargo build erzeugt ein unoptimiertes Artefakt in target/debug/.
  • cargo build --release erzeugt das hochoptimierte Produktions-Artefakt in target/release/.

5. Cargo-Workspaces für Multi-Crate-Architekturen

Bei größeren Projekten empfiehlt es sich, das System in mehrere eigenständige Crates aufzuteilen. Ein Cargo-Workspace ermöglicht die gemeinsame Nutzung eines einzigen target/-Ordners und einer globalen Cargo.lock:

# Haupt-Cargo.toml im Root-Verzeichnis
[workspace]
members = [
    "crates/cli",
    "crates/core",
    "crates/parser"
]

6. Key Takeaways (Architektur-Richtlinien)

  • Lockfiles: Committen Sie die Cargo.lock bei Binaries, um deterministische CI/CD-Pipelines zu sichern.
  • Profile Tuning: Optimieren Sie das release-Profil durch Aktivierung von LTO (Link-Time Optimization) in performance-kritischen Anwendungen.
  • Modularität: Strukturieren Sie wachsende Codebasen frühzeitig als Cargo-Workspaces.

Kapitel 02: Einrichtung & Erstes Programm (Hardware- & Systemsicht)

Dieses Kapitel analysiert die physikalischen Abläufe der Rust-Compilation, die Statik der Linker-Infrastruktur, die Funktionsweise von Hardware-Entropiequellen und Optimierungen der Binärgröße.

1. Lernziele

Sie werden in diesem Abschnitt:

  • Die Übersetzungsschritte von Rust-Sourcecode über LLVM IR zu nativem Maschinencode nachvollziehen.
  • Den Unterschied zwischen statischem und dynamischem Linken analysieren.
  • Verstehen, wie der Zufallszahlengenerator auf CPU-Instruktionen (RDRAND/RDSEED) zugreift.
  • Techniken zur Minimierung der Binärgröße (Stripping, Panic-Verhalten) anwenden.

2. Die Rust-Kompilierungspipeline (LLVM)

Der Rust-Compiler rustc übersetzt den Code nicht direkt in Maschinencode, sondern nutzt das LLVM-Compiler-Backend:

[Rust Quellcode] 
      │ (rustc Frontend)
      ▼
[HIR / MIR (Mid-level Intermediate Representation)]
      │ (Transkription zu LLVM)
      ▼
[LLVM IR (Plattformunabhängiger Zwischencode)]
      │ (LLVM Optimierungs-Passes)
      ▼
[Plattformspezifischer Maschinencode (x86_64, ARM, etc.)]
  • MIR (Mid-level IR): Hier führt Rust seine Typsicherheits- und Borrow-Checker-Prüfungen durch. Das MIR ist stark vereinfacht und ideal für Programmanalysen.
  • LLVM IR: LLVM führt die hardwarenahen Optimierungen durch (z. B. Vektorisierung, Loop-Transformationen und Inlining).

3. Statisches Linken vs. Dynamisches Linken

Wenn Sie ein Standard-Rust-Programm kompilieren, ist das resultierende Binär-Artefakt vergleichsweise groß (oft mehrere Megabytes für ein einfaches Programm).

Der Grund: Rust linkt standardmäßig statisch.

  • Statisch: Alle benötigten Standardbibliotheken (std) und externen Abhängigkeiten (wie das rand-Crate) werden direkt in das finale Executable hineinkopiert. Das Programm läuft auf dem Zielrechner ohne externe Abhängigkeiten (keine Fehlermeldungen über fehlende .so- oder .dll-Dateien).
  • Dynamisch: Bei C/C++ oder Sprachen, die auf Systembibliotheken vertrauen, verweist das Executable nur auf externe Bibliotheken im Betriebssystem. Fehlen diese auf dem Zielsystem, stürzt das Programm ab.

4. Hardware-Entropie unter der Haube

Wenn wir rand::thread_rng() aufrufen, greift Rust auf Betriebssystem-Schnittstellen zurück, die wiederum Hardware-Entropiequellen abfragen:

  • Linux: Zugriff auf /dev/urandom oder den Systemaufruf getrandom().
  • CPU-Instruktionen: Moderne Prozessoren bieten integrierte Zufallsgeneratoren, die auf thermischem Rauschen basieren. LLVM übersetzt die Zugriffe bei aktivierten CPU-Features direkt in native Instruktionen wie RDRAND (liest eine hardwaregenerierte Zufallszahl) oder RDSEED (erzeugt einen Seed für Software-Generatoren).

5. Binärgrößen-Optimierung auf Systemebene

Für Embedded-Systeme oder WebAssembly-Targets ist die Standard-Binärgröße oft zu hoch. Folgende Stellschrauben in der Cargo.toml reduzieren die Größe drastisch:

[profile.release]
strip = true       # Entfernt alle Debug-Symbole und Symboltabellen aus der Binärdatei
opt-level = "z"    # Optimiert primär auf Binärgröße, nicht auf Ausführungsgeschwindigkeit
panic = "abort"    # Deaktiviert das Stack-Unwinding. Reduziert den Fehlerbehandlungscode.
  • Strip: Entspricht dem manuellen Ausführen des System-Befehls strip target/release/wuerfelspiel.
  • Panic Abort: Im Fehlerfall stürzt das Programm sofort ab, anstatt den Stack geordnet abzubauen (Unwinding). Das spart viel Boilerplate-Code im Compiler-Ausgabe-Artefakt.

6. Key Takeaways (Systemebene)

  • LLVM IR ermöglicht es Rust, hochoptimierten Maschinencode für Dutzende von CPU-Architekturen zu generieren.
  • Statisches Linken erhöht die Binärgröße, garantiert aber die absolute Portabilität des Kompilats.
  • Hardware-Zufall wird über CPU-spezifische Opcodes (RDRAND) realisiert, die durch OS-Entropie-Abfragen geschützt sind.