Avatar ·

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

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

Основной способ: папка src/bin/ и явное указание в Cargo.toml

Вы на правильном пути! В Rust/Cargo есть несколько способов определить несколько бинарников. Самый простой и рекомендуемый — использовать папку src/bin/. Каждый файл .rs внутри этой папки автоматически становится отдельным бинарником, имя которого соответствует имени файла (без расширения).

Ваша структура my_project/src/bin/log_parser.rs и my_project/src/bin/report_gen.rs — это корректный подход. Проблема может быть в том, что у вас остался src/main.rs. Если он существует, Cargo воспринимает его как основной бинарник проекта (с именем, равным имени пакета). Это не мешает другим бинарникам, но если вы хотите, чтобы cargo build собирал все бинарники, нужно убедиться, что в Cargo.toml нет конфликтующих настроек.

Вот правильная конфигурация Cargo.toml для вашего случая:

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

# Явно перечисляем все бинарники (опционально, но рекомендуется для больших проектов)
[[bin]]
name = "log_parser"
path = "src/bin/log_parser.rs"

[[bin]]
name = "report_gen"
path = "src/bin/report_gen.rs"

# Если вы хотите удалить src/main.rs и сделать log_parser основным, 
# просто удалите src/main.rs и переименуйте файл, или оставьте как есть

Теперь команды для сборки и запуска:

  • cargo build — соберёт все бинарники. Они появятся в target/debug/log_parser и target/debug/report_gen.
  • cargo run --bin log_parser — соберёт и запустит только log_parser.
  • cargo run --bin report_gen — аналогично для report_gen.
  • cargo build --bin log_parser — соберёт только указанный бинарник (ускоряет сборку при разработке одного из них).

Если вы хотите, чтобы при cargo run (без флага --bin) запускался какой-то конкретный бинарник по умолчанию, можно задать его в Cargo.toml с помощью default-run:

[package]
name = "my_project"
version = "0.1.0"
edition = "2021"
default-run = "log_parser"

[[bin]]
name = "log_parser"
path = "src/bin/log_parser.rs"

[[bin]]
name = "report_gen"
path = "src/bin/report_gen.rs"

Теперь cargo run без аргументов будет запускать log_parser.

Пример кода для бинарников

Вот как могут выглядеть ваши файлы:

src/bin/log_parser.rs:

fn main() {
    println!("Log parser started. Parsing logs...");
    // Здесь код парсинга
}

src/bin/report_gen.rs:

fn main() {
    println!("Report generator started. Generating report...");
    // Здесь код генерации отчёта
}

Оба бинарника могут использовать общие модули, если вы вынесете их в src/lib.rs (библиотечный крейт). Например:

// src/lib.rs
pub mod utils;
pub mod data_structures;

// src/bin/log_parser.rs
use my_project::utils;

fn main() {
    utils::do_something();
}

Не забудьте добавить pub mod utils; в lib.rs и создать соответствующие файлы.

Если вы не хотите использовать папку bin/, можно разместить бинарники прямо в src/ с разными именами, но тогда придётся явно указывать пути в Cargo.toml. Однако папка src/bin/ — это общепринятый стандарт, рекомендую придерживаться его.

<<>>

Альтернативный подход: workspace с несколькими крейтами

Если ваши программы сильно различаются и имеют разные зависимости, возможно, лучше использовать workspace (рабочее пространство). Это позволяет держать каждый бинарник в отдельной папке со своим Cargo.toml, но в рамках одного репозитория.

Пример структуры workspace:

my_project/
├── Cargo.toml          # workspace-файл
├── log_parser/
│   ├── Cargo.toml
│   └── src/main.rs
└── report_gen/
    ├── Cargo.toml
    └── src/main.rs

Главный Cargo.toml (в корне):

[workspace]
members = [
    "log_parser",
    "report_gen",
]

Теперь команды работают так же: cargo build --bin log_parser или cargo run -p report_gen (флаг -p — указание пакета).

Плюсы: каждый крейт имеет свои зависимости и версии, изолированная компиляция, проще тестировать по отдельности.

Минусы: сложнее переиспользовать общий код — придётся создавать отдельный библиотечный крейт и добавлять его как зависимость в оба бинарника. Для небольших проектов с общими структурами данных папка src/bin/ удобнее.

Выбирайте подход под свои задачи: если бинарники тесно связаны — используйте src/bin/; если это независимые программы — workspace.