Как собрать несколько бинарных файлов (исполняемых программ) в одном проекте Cargo?
Решение: Использование секции [[bin]] в Cargo.toml
Cargo поддерживает создание нескольких бинарных файлов из одного проекта. Для этого нужно определить каждую исполняемую программу в секции [[bin]] файла Cargo.toml. Каждый бинарник указывает на свой исходный файл или точку входа.
Вот правильная структура проекта для вашего случая:
my_project/
├── Cargo.toml
└── src/
├── main.rs # Первая программа (по умолчанию)
├── bin/
│ ├── report.rs # Вторая программа
│ └── server.rs # Третья программа
└── lib.rs # Общий модуль (опционально)
Настройка Cargo.toml
В Cargo.toml нужно явно указать все бинарные цели. Если файлы лежат в src/bin/, Cargo может найти их автоматически, но лучше задать явно для контроля:
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
[[bin]]
name = "my_project"
path = "src/main.rs"
[[bin]]
name = "report"
path = "src/bin/report.rs"
[[bin]]
name = "server"
path = "src/bin/server.rs"
Если вы используете папку src/bin/ и имена файлов совпадают с желаемыми именами бинарников, можно упростить — Cargo сам найдёт все .rs файлы в этой папке и создаст для каждого бинарник с соответствующим именем. Тогда Cargo.toml может выглядеть так:
[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
# Автоматическое обнаружение бинарников в src/bin/
# (никаких дополнительных секций [[bin]] не нужно)
Пример содержимого файлов
src/main.rs — основная программа:
fn main() {
println!("Запуск основной программы my_project");
// Здесь может быть вызов общих функций из lib.rs
}
src/bin/report.rs — генератор отчётов:
fn main() {
println!("Генерация отчёта...");
// Общие функции можно импортировать через use my_project::...
}
src/bin/server.rs — веб-сервер:
fn main() {
println!("Запуск веб-сервера на порту 8080");
// Импорт общих модулей
}
Общие модули (lib.rs)
Чтобы использовать общий код между всеми бинарниками, добавьте файл src/lib.rs с функциями и структурами. Например:
// src/lib.rs
pub fn common_function() {
println!("Общая функция, доступная всем бинарникам");
}
Тогда в любом бинарнике вы сможете написать:
use my_project::common_function;
fn main() {
common_function();
}
Сборка и запуск
cargo build— соберёт все бинарники сразу.cargo run --bin my_project— запустит основную программу.cargo run --bin report— запустит генератор отчётов.cargo run --bin server— запустит веб-сервер.cargo build --bin report— соберёт только один указанный бинарник.
Готовые бинарники будут лежать в target/debug/ (или target/release/ после cargo build --release) с именами, соответствующими указанным в [[bin]].
Важные замечания
- Каждый бинарник должен иметь свою функцию
fn main(). - Имена бинарников должны быть уникальными в рамках проекта.
- Если вы не укажете
path, Cargo будет искать файлsrc/bin/<name>.rs. - Для сложных проектов используйте
lib.rsдля общей логики, чтобы избежать дублирования кода.
Альтернативный подход: workspace (рабочее пространство)
Если ваши программы становятся большими и слабо связанными, лучше использовать Cargo workspace. Это позволяет разбить проект на несколько независимых крейтов (crates), каждый со своим Cargo.toml, но с общими зависимостями и одной папкой target.
Структура будет такой:
my_workspace/
├── Cargo.toml # workspace-файл
├── my_project/
│ ├── Cargo.toml
│ └── src/main.rs
├── report/
│ ├── Cargo.toml
│ └── src/main.rs
└── server/
├── Cargo.toml
└── src/main.rs
В корневом Cargo.toml пишем:
[workspace]
members = [
"my_project",
"report",
"server",
]
Теперь каждый подпроект — это отдельный крейт со своими зависимостями. Вы можете запускать их по отдельности: cargo run -p report. Workspace удобен, когда программы имеют разные наборы зависимостей или когда вы хотите публиковать их отдельно на crates.io. Однако для небольших утилит, которые делят много общего кода, проще использовать первый подход с [[bin]] и lib.rs.