Contactez-nous

Créer et gérer un projet avec Cargo

Apprenez à créer et gérer vos projets Rust avec Cargo. Découvrez l'initialisation, le fichier Cargo.toml, les dépendances et la structure standard des projets pour un développement optimisé.

Initialiser un projet Rust : la distinction entre `cargo new` et `cargo init`

Démarrer un nouveau projet en Rust est une expérience simplifiée grâce à Cargo, l'outil de gestion de projet et de build intégré. Comprendre les commandes d'initialisation est la première étape pour structurer correctement votre travail. Cargo offre deux commandes principales à cet effet : `cargo new` et `cargo init`, chacune répondant à des scénarios d'utilisation spécifiques. Maîtriser leur distinction vous permettra de commencer vos développements sur des bases saines et organisées.

La commande `cargo new nom_du_projet` est la plus couramment utilisée pour démarrer un projet à partir de zéro. Lorsque vous l'exécutez, Cargo accomplit plusieurs actions pour vous : il crée un nouveau répertoire portant le nom de votre projet, initialise un dépôt Git à l'intérieur (si Git est installé sur votre système), et génère une structure de base comprenant un fichier `Cargo.toml` préconfiguré et un répertoire `src` contenant un fichier `main.rs` avec un programme "Hello, world!". Par défaut, `cargo new` crée un projet de type binaire (exécutable). Si vous souhaitez créer une bibliothèque (crate), vous utiliserez l'option `--lib` : `cargo new nom_de_la_bibliotheque --lib`. Dans ce cas, un fichier `src/lib.rs` sera généré à la place de `src/main.rs`.

A l'inverse, `cargo init` est conçue pour initialiser un projet Cargo au sein d'un répertoire existant. Imaginez que vous avez déjà un répertoire contenant, par exemple, des fichiers de configuration ou des notes, et que vous décidez d'y intégrer un projet Rust. En vous plaçant dans ce répertoire et en exécutant `cargo init`, Cargo y ajoutera le fichier `Cargo.toml` et le répertoire `src` avec `main.rs` (ou `src/lib.rs` si vous utilisez `cargo init --lib`), sans créer de nouveau dossier englobant. Cette commande est donc parfaite pour transformer un dossier existant en un projet Rust structuré, ou si vous avez une gestion de version déjà en place et que vous souhaitez y intégrer Rust.

En résumé, la principale différence réside dans la création du répertoire : `cargo new` le crée pour vous, tandis que `cargo init` opère dans le répertoire courant. Voici un exemple pour illustrer `cargo new` :

$ cargo new mon_application
     Created binary (application) `mon_application` package
$ cd mon_application
$ ls
Cargo.toml  src

Et pour `cargo init` dans un répertoire préalablement créé :

$ mkdir ma_bibliotheque_existante
$ cd ma_bibliotheque_existante
$ cargo init --lib
     Created library `ma_bibliotheque_existante` package
$ ls
Cargo.toml  src

Choisir entre `cargo new` et `cargo init` dépend donc entièrement de votre point de départ. Pour un projet frais, `cargo new` est votre allié. Pour intégrer Rust à une structure existante, `cargo init` est l'outil adéquat. Cette flexibilité initiale offerte par Cargo témoigne de sa conception pensée pour s'adapter aux divers flux de travail des développeurs.

Le fichier `Cargo.toml` : le manifeste central de votre projet et de ses dépendances

Au coeur de chaque projet Rust géré par Cargo se trouve le fichier `Cargo.toml`. Ce fichier, dont le nom est une contraction de "Tom's Obvious, Minimal Language" pour le format TOML, sert de manifeste. Il contient toutes les métadonnées nécessaires à Cargo pour compiler votre projet, gérer ses dépendances et bien plus encore. Comprendre sa structure et son rôle est fondamental pour tout développeur Rust, car c'est ici que vous définirez l'identité et les besoins de votre application ou bibliothèque.

Le fichier `Cargo.toml` est divisé en sections, identifiables par des en-têtes entre crochets (par exemple, `[package]`). La section `[package]` est obligatoire et décrit les caractéristiques essentielles de votre crate. Elle inclut typiquement :

  • `name`: Le nom de votre crate (paquet). Ce nom sera utilisé sur `crates.io` si vous publiez votre crate.
  • `version`: La version de votre crate, suivant le versionnage sémantique (SemVer).
  • `authors`: Une liste des auteurs de la crate. Bien que toujours supporté, il est souvent remplacé ou complété par les informations du dépôt Git.
  • `edition`: Spécifie l'édition de Rust à utiliser pour compiler la crate (par exemple, `"2021"`). Les éditions permettent d'introduire des changements non rétrocompatibles de manière contrôlée.

Voici un exemple minimal de la section `[package]` :

[package]
name = "mon_projet_rust"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

L'une des fonctionnalités les plus puissantes de Cargo est la gestion des dépendances, configurée dans la section `[dependencies]`. C'est ici que vous déclarez les crates externes (bibliothèques) dont votre projet a besoin. Pour ajouter une dépendance, vous spécifiez son nom (tel qu'il apparaît sur `crates.io`) et la version souhaitée. Par exemple, pour utiliser la populaire crate `rand` pour la génération de nombres aléatoires :

[dependencies]
rand = "0.8.5"

Cargo supporte différentes manières de spécifier les versions, permettant un contrôle fin sur les mises à jour. L'utilisation du caret `^` (implicite si seule la version est donnée comme ci-dessus, équivalent à `^0.8.5`) permet les mises à jour compatibles. D'autres sections comme `[dev-dependencies]` pour les dépendances de test, ou `[build-dependencies]` pour les scripts de build, peuvent également être présentes. Le `Cargo.toml` est donc bien plus qu'un simple fichier de configuration ; c'est le chef d'orchestre de votre projet Rust, assurant sa cohérence et sa capacité à interagir avec l'écosystème Rust.

Lorsque vous exécutez des commandes comme `cargo build` ou `cargo run`, Cargo lit ce fichier, résout les versions des dépendances, les télécharge si nécessaire (depuis `crates.io` par défaut), et les compile avec votre code. Une bonne compréhension de ce manifeste est donc synonyme d'une gestion de projet sereine et efficace.

Structure typique d'un projet Rust : `src/main.rs`, `src/lib.rs` et l'organisation des sources

Cargo n'impose pas seulement une manière de gérer les dépendances, il établit également des conventions claires pour l'organisation des fichiers sources d'un projet Rust. Cette standardisation facilite grandement la navigation dans le code, la collaboration entre développeurs et la compréhension de nouveaux projets. Une fois votre projet initialisé avec `cargo new` ou `cargo init`, vous observerez une structure de répertoires et de fichiers bien définie.

A la racine de votre projet, vous trouverez toujours le fichier `Cargo.toml` que nous venons d'explorer. A côté de lui, Cargo crée un répertoire `src`. C'est dans ce répertoire que résidera l'ensemble de votre code source Rust. Le fichier d'entrée principal de votre code dépendra du type de projet :

  • Pour un projet binaire (une application exécutable), le point d'entrée conventionnel est `src/main.rs`. Ce fichier doit contenir une fonction `main`, qui sera la première fonction exécutée au lancement de votre programme. Un `main.rs` minimal ressemblerait à ceci :
    fn main() {
        println!("Bonjour, le monde !");
    }
  • Pour un projet de bibliothèque (une crate destinée à être utilisée par d'autres projets), le point d'entrée est `src/lib.rs`. Ce fichier contient le code de votre bibliothèque. Les fonctions, structures, et autres éléments que vous souhaitez rendre accessibles depuis l'extérieur de votre crate devront être marqués avec le mot-clé `pub`. Voici un exemple simple de `src/lib.rs` :
    /// Ajoute deux nombres entiers.
    pub fn additionner(gauche: usize, droite: usize) -> usize {
        gauche + droite
    }

Il est important de noter qu'un même paquet Cargo peut contenir à la fois une bibliothèque et plusieurs binaires. Si votre projet contient un `src/lib.rs`, il sera compilé comme une bibliothèque. Vous pouvez également ajouter des exécutables supplémentaires en plaçant des fichiers Rust dans un répertoire `src/bin/`. Chaque fichier dans `src/bin/` sera compilé comme un exécutable distinct, ayant sa propre fonction `main`.

Outre le répertoire `src` et le `Cargo.toml`, vous remarquerez après la première compilation l'apparition d'un fichier `Cargo.lock` et d'un répertoire `target`. Le fichier `Cargo.lock` enregistre les versions exactes de toutes les dépendances utilisées pour une compilation donnée. Cela garantit des builds reproductibles : si quelqu'un d'autre clone votre projet et le compile, Cargo utilisera les versions spécifiées dans `Cargo.lock`, assurant que tout le monde travaille avec le même environnement de dépendances. Le répertoire `target` contient tous les artéfacts de compilation (fichiers objets, binaires finaux, documentation, etc.). Il est généralement ajouté au fichier `.gitignore` de votre projet, car son contenu est généré et peut être volumineux.

Cette structure standardisée est un des atouts de l'écosystème Rust. Elle permet aux développeurs de se familiariser rapidement avec la base de code de n'importe quel projet Rust et contribue à maintenir un haut niveau d'organisation et de maintenabilité. En comprenant et en respectant ces conventions, vous vous intégrez harmonieusement dans la communauté Rust et facilitez la vie de vos futurs collaborateurs (et la vôtre !).