backend / rust
Écosystème : cargo workspaces et publier une crate
Explication
Ce que vous allez apprendre
- Organiser un projet Rust en plusieurs crates réunis sous un workspace Cargo
- Cibler un membre précis du workspace pour compiler, tester ou exécuter
- Préparer les métadonnées obligatoires d'une crate destinée à être publiée
- Publier une crate sur crates.io avec
cargo publishen toute sécurité - Générer une documentation HTML exploitable avec
cargo doc
Dans quel contexte ?
Une startup qui développe une application backend en Rust se retrouve avec un seul énorme crate mélangeant la logique métier, l'API HTTP et un outil CLI d'administration interne. À chaque modification de l'API, tout le projet — y compris le CLI qui n'a rien à voir — doit être recompilé, et les tests unitaires de la logique métier se mélangent avec les tests d'intégration de l'API. Un workspace Cargo résout exactement ce problème en séparant ces responsabilités en crates indépendants qui partagent un seul Cargo.lock.
D'abord, comprendre ce qu'un workspace apporte
Un workspace regroupe plusieurs crates Rust sous un seul fichier Cargo.toml racine, qui ne contient pas de code lui-même mais liste les membres (core, api, cli par exemple). L'avantage principal : un seul Cargo.lock partagé garantit que tous les crates du workspace utilisent exactement les mêmes versions de leurs dépendances communes, évitant les incohérences de versions.
| Commande | Effet |
|---|---|
cargo build --workspace | Compile tous les membres du workspace |
cargo test -p core | Teste uniquement le crate core |
cargo run -p api | Lance uniquement le binaire api |
cargo doc --open | Génère et ouvre la documentation HTML de tous les crates |
Prérequis
Cette leçon suppose une bonne compréhension d'un Cargo.toml classique et de la notion de dépendance, vues en tout début de parcours.
Une fois le workspace en place, les dépendances entre crates deviennent locales
Un crate du workspace peut dépendre d'un autre simplement via un chemin relatif (core = { path = "../core" }), sans avoir besoin de le publier sur crates.io au préalable. C'est exactement ce qui permet à api et cli de partager la même logique métier définie dans core, sans duplication de code.
Il reste un problème à résoudre : comment partager du code avec la communauté
Quand une bibliothèque devient suffisamment générique et utile pour être réutilisée en dehors du projet, l'étape suivante est de la publier sur crates.io, le registre officiel de paquets Rust. Avant cela, un Cargo.toml de bibliothèque doit contenir des métadonnées obligatoires : description, license, et idéalement repository et keywords pour la découvrabilité.
Piège courant
cargo publish est irréversible pour un numéro de version donné : une fois publiée, une version ne peut jamais être supprimée ni republiée avec le même numéro (seul un cargo yank la marque comme déconseillée, sans la retirer complètement). Utilise systématiquement cargo publish --dry-run avant la publication réelle pour vérifier que tout est correct.
Enfin, documenter ce qu'on publie
Les commentaires de documentation (/// pour un élément, //! pour tout un module) ne sont pas de simples commentaires : cargo doc les transforme en documentation HTML navigable, et les blocs de code qu'ils contiennent (comme dans l'exemple additionner) sont même exécutés automatiquement comme des tests par cargo test — ce sont les doctests.
Bonne pratique
Écris toujours au moins un exemple # Examples dans la documentation d'une fonction publique. En plus d'aider les utilisateurs de ta crate, cet exemple sera vérifié à chaque cargo test, garantissant que ta documentation ne se périme jamais silencieusement.
Maintenant que tu sais organiser et publier du code Rust à l'échelle d'un écosystème, la dernière étape du parcours consiste à pousser Rust dans son domaine de prédilection historique : la programmation système bas niveau, sujet de la leçon finale.
Commandes & code
Écosystème : cargo workspaces et publier une crate
Organiser un projet multi-crates et partager du code réutilisable via crates.io.
# Cargo.toml a la racine : declare un workspace regroupant plusieurs crates
[workspace]
resolver = "2"
members = [
"core",
"api",
"cli",
]mon-workspace/
Cargo.toml <- workspace racine
Cargo.lock <- UN SEUL lockfile partage par tout le workspace
core/
Cargo.toml
src/lib.rs <- logique metier partagee
api/
Cargo.toml <- depend de core via chemin local
src/main.rs
cli/
Cargo.toml <- depend de core aussi
src/main.rs# api/Cargo.toml : dependance locale vers un autre crate du workspace
[package]
name = "api"
version = "0.1.0"
edition = "2021"
[dependencies]
core = { path = "../core" }
tokio = { version = "1", features = ["full"] }# Commandes utiles sur un workspace
cargo build --workspace # compile tous les membres
cargo test -p core # teste uniquement le crate "core"
cargo run -p api # lance uniquement le binaire "api"# Cargo.toml d'une bibliotheque destinee a etre publiee
[package]
name = "ma-super-lib"
version = "0.1.0"
edition = "2021"
description = "Une bibliotheque Rust qui fait X"
license = "MIT OR Apache-2.0"
repository = "https://github.com/user/ma-super-lib"
readme = "README.md"
keywords = ["exemple", "utilitaire"]
categories = ["algorithms"]# Publier une crate sur crates.io
cargo login <token> # authentification (token depuis crates.io)
cargo publish --dry-run # verification sans publication reelle
cargo publish # publication definitive, IRREVERSIBLE (versions ne peuvent etre supprimees)
# Versionner correctement (semver strict, verifie par cargo)
cargo set-version 0.2.0// Documenter une crate publiee : les doc-comments generent la doc via `cargo doc`
//! # Ma Super Lib
//!
//! Documentation du niveau crate (au tout debut de lib.rs)
/// Additionne deux nombres.
///
/// # Examples
/// ```
/// assert_eq!(ma_super_lib::additionner(2, 3), 5);
/// ```
pub fn additionner(a: i32, b: i32) -> i32 {
a + b
}cargo doc --open # genere et ouvre la documentation HTML localementRésumé
- Un workspace regroupe plusieurs crates sous un
Cargo.lockunique, avec des dépendances locales par chemin. cargo build/test/run -p <nom>cible un membre précis du workspace.cargo publishenvoie une crate sur crates.io — irréversible pour un numéro de version donné.- Les doc-comments (
///,//!) génèrent une documentation HTML et des doctests exécutables viacargo doc/cargo test.
Exercices pratiques
Mission : une publication précipitée et un workspace à réorganiser
Objectif : Réagir correctement à une crate publiée par erreur avec une faille, puis structurer un workspace multi-crates et anticiper les contraintes de publication d'un crate dépendant.
Contexte
Un développeur vient d'exécuter cargo publish sur ma-super-lib en version 0.1.0. Quelques minutes plus tard, il découvre une faille de sécurité dans le code qu'il vient de publier sur crates.io.
Séparément, son équipe travaille sur un projet mélangé dans un seul crate (logique métier, API HTTP, CLI d'admin) et veut le réorganiser en workspace avec trois membres : core, api et cli. À terme, elle envisage aussi de publier api séparément sur crates.io, alors que api dépend aujourd'hui de core uniquement via un chemin local (path = "../core").