Comment construire plusieurs binaires avec Cargo sans perdre en performance ?
\n\nAvez-vous déjà été confronté à une situation où votre projet Rust s’agrandit au point qu’un seul fichier binaire ne suffit plus ? Peut-être écrivez-vous un utilitaire CLI qui doit avoir des exécutables séparés pour différentes tâches : un pour l’analyse de données, un autre pour la génération de rapports, un troisième pour l’interaction avec une API. Ou vous créez une application serveur où vous devez séparer la surveillance, le traitement des requêtes et les tâches en arrière-plan.
\n\nLa question "How can I build multiple binaries with Cargo?" est l’une des plus populaires sur Stack Overflow parmi les développeurs Rust. Et ce n’est pas un hasard. Lorsqu’un projet dépasse le simple "Hello, World!", savoir organiser correctement la construction de plusieurs binaires devient une compétence cruciale. Mais comment faire sans perdre en performance ? Comment éviter de se noyer dans la duplication de code et de ralentir la compilation ?
\n\nDans cet article, nous ne répondrons pas simplement à cette question — nous montrerons comment transformer la construction de plusieurs binaires d’un casse-tête en un puissant outil d’optimisation. Vous découvrirez les meilleures pratiques, la performance et même les astuces secrètes de Cargo utilisées par les développeurs Rust expérimentés.
\n\nPourquoi plusieurs binaires ? Le problème d’un seul fichier exécutable
\n\nImaginez : vous avez écrit une excellente bibliothèque pour travailler avec des données. Puis vous avez ajouté une interface CLI. Puis un serveur web. Puis un planificateur de tâches. Tout dans un seul projet. Résultat ? Un monolithe qui :
\n\n- \n
- Compile éternellement, même si vous ne modifiez qu’une seule ligne dans le CLI. \n
- Nécessite un redémarrage complet de l’application lors de la mise à jour d’un seul composant. \n
- Est difficile à tester et à déployer. \n
La solution — diviser le projet en plusieurs binaires. Mais comment faire correctement en Rust ?
\n\nLes bases : Cargo.toml et la section [[bin]]
\n\nLa méthode la plus simple est de déclarer plusieurs cibles binaires dans votre Cargo.toml. Analysons un exemple de base.
// Cargo.toml\n[package]\nname = "my_project"\nversion = "0.1.0"\nedition = "2021"\n\n[[bin]]\nname = "analyzer"\npath = "src/bin/analyzer.rs"\n\n[[bin]]\nname = "reporter"\npath = "src/bin/reporter.rs"\n\n[[bin]]\nname = "server"\npath = "src/bin/server.rs"\n\n[dependencies]\nserde = { version = "1.0", features = ["derive"] }\ntokio = { version = "1", features = ["full"] }\n\n\nMaintenant, dans le dossier src/bin/, vous avez trois fichiers : analyzer.rs, reporter.rs et server.rs. Chacun d’eux est un binaire complet avec sa propre fonction main().
Pour tout construire d’un coup :
\ncargo build --release\n\nOu un binaire spécifique :
\ncargo build --release --bin analyzer\n\nSimple ? Oui. Mais c’est là que se cache le piège. Si vous n’optimisez pas la construction, chaque binaire sera compilé à nouveau, même s’ils utilisent les mêmes dépendances. Et c’est un chemin direct vers une perte de performance.
\n\nOptimisation des performances de construction : les profils Cargo
\n\nLe secret d’une construction efficace de plusieurs binaires réside dans les profils Cargo. C’est un outil puissant qui permet de configurer les paramètres de compilation pour différents scénarios.
\n\nProfils de base : dev et release
\n\nPar défaut, Cargo utilise deux profils : dev (pour le développement) et release (pour la production). Mais vous pouvez créer vos propres profils ou modifier ceux qui existent.
// Cargo.toml\n[profile.release]\nopt-level = 3 # Optimisation maximale du code\nlto = "fat" # Link-Time Optimization (fusion de toutes les crates)\ncodegen-units = 1 # Un seul thread codegen pour une meilleure optimisation\nstrip = true # Suppression des informations de débogage\n\n\nCes paramètres sont particulièrement importants pour les binaires qui doivent fonctionner rapidement. Mais il y a un détail : plus l’optimisation est agressive