Avatar ·

Как собрать несколько бинарных файлов (исполняемых программ) в одном проекте Cargo?

Всем привет! Я только начал изучать Rust и использую Cargo для управления проектом. У меня есть одна программа, которая лежит в `src/main.rs`, и всё работает отлично. Но теперь мне нужно добавить в тот же проект несколько разных утилит: одну для обработки данных, другую для генерации отчётов, и третью — для запуска веб-сервера. Каждая из них должна компилироваться в отдельный исполняемый файл. Я попробовал просто создать несколько файлов `main.rs` в разных папках, но Cargo ругается. Потом я наткнулся на упоминание бинрей (binaries) в документации, но не понял, как это настроить. Мой текущий проект выглядит так: ``` my_project/ ├── Cargo.toml └── src/ └── main.rs ``` Я хочу получить что-то вроде: ``` my_project/ ├── Cargo.toml └── src/ ├── main.rs (первая программа) ├── report.rs (вторая программа) └── server.rs (третья программа) ``` Чтобы при сборке `cargo build` создавались три разных бинарника: `my_project`, `report` и `server`. Как правильно организовать структуру проекта и настроить `Cargo.toml`? Можно ли использовать общие модули для всех этих программ? Буду благодарен за пример кода и объяснение. <<>>

Решение: Использование секции [[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.