Installation et outils#

Ce chapitre présente l’installation de Rust et l’écosystème d’outils qui l’accompagne. Contrairement à beaucoup de langages, Rust est distribué avec une chaîne d’outils complète et cohérente : gestionnaire de projet, formateur de code, analyseur statique. Cette uniformité est un choix de conception délibéré qui facilite la collaboration et garantit une expérience homogène.

Installation via rustup#

Définition 1 (rustup)

rustup est le gestionnaire officiel de la chaîne d’outils Rust. Il permet d’installer, de mettre à jour et de basculer entre différentes versions du compilateur. C’est le point d’entrée recommandé pour toute installation de Rust.

L’installation se fait en une seule commande, sur Linux et macOS :

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Cette commande télécharge et exécute le script d’installation de rustup. Par défaut, elle installe la version stable du compilateur, ainsi que l’ensemble des outils standard. Après installation, il faut recharger l’environnement du terminal :

source "$HOME/.cargo/env"

On vérifie ensuite que tout fonctionne :

rustc --version
cargo --version

Remarque 1

rustup permet d’installer plusieurs chaînes d’outils en parallèle : stable, beta et nightly. La version nightly donne accès aux fonctionnalités expérimentales du langage, mais ne doit pas être utilisée en production. On bascule entre les versions avec rustup default nightly ou rustup default stable.

La chaîne d’outils#

Rust fournit quatre outils fondamentaux, tous installés par rustup.

rustc#

rustc est le compilateur Rust. Il transforme le code source .rs en binaire exécutable. En pratique, on ne l’invoque presque jamais directement : on passe par Cargo, qui l’appelle en coulisses.

rustc main.rs     # compilation directe (rare en pratique)

Cargo#

Définition 2 (Cargo)

Cargo est le gestionnaire de projet et de dépendances de Rust. Il joue simultanément le rôle de système de build, de gestionnaire de paquets et de lanceur de tests. Tout projet Rust sérieux est un projet Cargo.

rustfmt#

rustfmt est le formateur de code officiel. Il reformate automatiquement le code source selon les conventions de style de la communauté Rust. Cela élimine les débats de formatage et garantit un style uniforme dans tout l’écosystème.

cargo fmt          # formate tout le projet

Clippy#

clippy est l’analyseur statique officiel (linter). Il détecte les erreurs idiomatiques, les inefficacités et les usages douteux. Ses suggestions sont pédagogiques et souvent accompagnées d’exemples de correction.

cargo clippy       # analyse statique du projet

Remarque 2

Il est recommandé d’exécuter cargo fmt et cargo clippy avant chaque commit. Beaucoup de projets les intègrent dans leur pipeline d’intégration continue (CI). Clippy est particulièrement utile pour les débutants : il enseigne les idiomes du langage au fil de l’eau.

Structure d’un projet Cargo#

Un projet Cargo suit une arborescence conventionnelle. Cette convention prime sur la configuration : Cargo sait où chercher les fichiers sans qu’on ait besoin de tout lui indiquer.

mon_projet/
├── Cargo.toml        # manifeste du projet
├── Cargo.lock        # verrou des dépendances (généré)
└── src/
    ├── main.rs       # point d'entrée d'un binaire
    └── lib.rs        # racine d'une bibliothèque

Définition 3 (Crate)

Une crate est l’unité de compilation de Rust. Il en existe deux types :

  • une crate binaire (src/main.rs) qui produit un exécutable ;

  • une crate bibliothèque (src/lib.rs) qui produit du code réutilisable.

Un projet Cargo peut contenir les deux simultanément.

Cargo.toml#

Le fichier Cargo.toml est le manifeste du projet. Il utilise le format TOML (Tom’s Obvious, Minimal Language) et contient les métadonnées du projet ainsi que ses dépendances.

Exemple 1

Voici un fichier Cargo.toml minimal :

```toml [package] name = « mon_projet » version = « 0.1.0 » edition = « 2021 »

[dependencies] serde = « 1.0 » rand = « 0.8 » ```

La section [package] décrit le projet. La section [dependencies] liste les bibliothèques externes, appelées crates, dont le projet dépend. Cargo les télécharge automatiquement depuis crates.io, le registre officiel.

src/main.rs#

Le fichier src/main.rs est le point d’entrée d’une crate binaire. Il doit contenir une fonction main :

Exemple 2

```rust fn main() { println!(« Bonjour, Rust ! »); } ```

src/lib.rs#

Le fichier src/lib.rs est la racine d’une crate bibliothèque. Il expose les modules et les fonctions publiques du projet. Il ne contient pas de fonction main.

Commandes Cargo essentielles#

Cargo centralise toutes les opérations courantes du développement. Voici les six commandes que l’on utilise quotidiennement.

cargo new#

Crée un nouveau projet avec l’arborescence standard :

cargo new mon_projet          # crée une crate binaire
cargo new ma_lib --lib        # crée une crate bibliothèque

cargo build#

Compile le projet et toutes ses dépendances :

cargo build                   # compilation en mode debug
cargo build --release         # compilation en mode release (optimisé)

cargo run#

Compile puis exécute le binaire en une seule commande :

cargo run                     # compile et exécute
cargo run --release           # compile en release et exécute

cargo check#

Vérifie que le code compile sans produire de binaire. C’est beaucoup plus rapide que cargo build et suffisant pour vérifier la correction du code pendant le développement :

cargo check

Remarque 3

cargo check est la commande que l’on exécute le plus souvent pendant le développement. Elle effectue toute l’analyse de types et la vérification du borrow checker sans la phase coûteuse de génération de code. C’est l’équivalent d’un bouton Vérifier dans un éditeur.

cargo test#

Exécute tous les tests du projet : tests unitaires, tests d’intégration et exemples de documentation :

cargo test                    # exécute tous les tests
cargo test nom_du_test        # exécute un test spécifique

cargo doc#

Génère la documentation HTML du projet et de ses dépendances à partir des commentaires de documentation (///) :

cargo doc --open              # génère et ouvre dans le navigateur

Exemple 3

Voici un résumé des commandes Cargo et de leur usage :

Commande

Action

cargo new

Créer un nouveau projet

cargo build

Compiler le projet

cargo run

Compiler et exécuter

cargo check

Vérifier sans compiler

cargo test

Exécuter les tests

cargo doc

Générer la documentation

cargo fmt

Formater le code

cargo clippy

Analyser le code (linter)

Modes de compilation#

Cargo distingue deux modes de compilation, appelés profils, qui correspondent à des compromis différents entre vitesse de compilation et performance du binaire.

Définition 4 (Profils de compilation)

Le profil debug (cargo build) compile rapidement mais sans optimisations. Il inclut les informations de débogage et les vérifications d’exécution (débordements arithmétiques, accès hors limites).

Le profil release (cargo build --release) active les optimisations du compilateur LLVM. Le binaire est plus lent à compiler mais beaucoup plus rapide à l’exécution.

La différence de performance entre les deux profils peut être considérable, parfois d’un facteur 10 à 100 pour du calcul intensif.

Exemple 4

On peut personnaliser les profils dans Cargo.toml :

[profile.dev]
opt-level = 1              # légère optimisation en debug

[profile.release]
lto = true                 # Link-Time Optimization

Le champ opt-level accepte les valeurs 0 (aucune optimisation) à 3 (optimisation maximale), ainsi que "s" et "z" pour optimiser la taille du binaire.

Remarque 4

Une erreur classique du débutant est de mesurer les performances en mode debug. Les benchmarks doivent toujours être exécutés avec --release. Un programme qui semble lent en debug peut être parfaitement performant en release.

Les éditions Rust#

Définition 5 (Édition)

Une édition Rust est un point de synchronisation qui permet d’introduire des changements non rétrocompatibles dans la syntaxe du langage. Les éditions existantes sont 2015, 2018, 2021 et 2024.

L’édition se déclare dans Cargo.toml via le champ edition. Chaque nouvelle édition est opt-in : un projet conserve son édition tant qu’on ne la change pas explicitement.

Le mécanisme des éditions est une solution élégante au problème de l’évolution du langage. Il permet d’introduire de nouveaux mots-clés (comme async en 2018) ou de modifier la sémantique de certaines constructions sans casser les projets existants.

Un point fondamental : des crates d’éditions différentes peuvent coexister dans le même projet. Le compilateur gère les différences en interne. Ainsi, une bibliothèque écrite en édition 2015 fonctionne parfaitement dans un projet en édition 2024.

Remarque 5

On utilise cargo fix --edition pour migrer automatiquement le code vers une nouvelle édition. La migration est généralement triviale car les changements entre éditions sont volontairement limités et bien documentés.

Introduction au REPL avec evcxr#

Définition 6 (evcxr)

evcxr (Evaluation Context for Rust) est un REPL (Read-Eval-Print Loop) et un noyau Jupyter pour Rust. Il permet d’exécuter du code Rust de manière interactive, sans avoir besoin de créer un projet Cargo complet ni d’écrire une fonction main.

L’installation se fait via Cargo :

cargo install evcxr_repl          # REPL en ligne de commande
cargo install evcxr_jupyter       # noyau Jupyter
evcxr_jupyter --install           # enregistrement du noyau

Dans un notebook Jupyter avec le noyau evcxr, on peut écrire du code Rust directement, sans la cérémonie habituelle. Les expressions sont évaluées et leur résultat est affiché automatiquement.

let x: i32 = 42;
let y: i32 = 13;
x + y
55

Le REPL gère les types, les variables et même les dépendances externes :

let message = String::from("Bonjour depuis evcxr !");
println!("{}", message);
Bonjour depuis evcxr !

On peut manipuler les structures de données standard :

let nombres: Vec<i32> = vec![1, 2, 3, 4, 5];
let somme: i32 = nombres.iter().sum();
println!("La somme de {:?} est {}", nombres, somme);
La somme de [1, 2, 3, 4, 5] est 15
let carres: Vec<i32> = (1..=5).map(|x| x * x).collect();
carres
[1, 4, 9, 16, 25]

Remarque 6

evcxr est l’outil que nous utiliserons tout au long de ce livre pour exécuter les exemples de code. Il présente quelques limitations par rapport à un projet Cargo classique (pas de multithreading, certaines fonctionnalités avancées indisponibles), mais il est parfaitement adapté à l’apprentissage et à l’expérimentation.

Exemple 5

Voici un exemple plus complet qui utilise une structure :

struct Point {
    x: f64,
    y: f64,
}

impl Point {
    fn distance(&self, autre: &Point) -> f64 {
        ((self.x - autre.x).powi(2) + (self.y - autre.y).powi(2)).sqrt()
    }
}

let a = Point { x: 0.0, y: 0.0 };
let b = Point { x: 3.0, y: 4.0 };
println!("Distance : {}", a.distance(&b));
Distance : 5

Ce code définit une structure Point avec une méthode distance. Nous reviendrons sur les structures et les implémentations dans les chapitres suivants

Ce chapitre a présenté l’installation de Rust et les outils qui forment son écosystème. La chaîne d’outils unifiée (rustup, Cargo, rustfmt, Clippy) est l’une des forces du langage : elle réduit la friction et permet de se concentrer sur le code. Dans le chapitre suivant, nous écrirons notre premier programme et explorerons les concepts fondamentaux du langage.