Как подключить локальный Rust-крейт (crate) до публикации: пошаговое руководство

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение: почему локальный крейт — это не роскошь, а необходимость

Представьте: вы пишете на Rust библиотеку для парсинга конфигурационных файлов. Она ещё сырая, не готова к публикации на crates.io, но вы уже хотите протестировать её в реальном проекте — веб-сервере на Actix или CLI-утилите. Что делать? Копировать код? Создавать монорепозиторий? Нет, в Rust для этого есть элегантное решение — локальный unpublished crate.

Вопрос "How to use a local unpublished crate?" собрал тысячи просмотров на Stack Overflow. Это не случайно: каждый Rust-разработчик рано или поздно сталкивается с необходимостью подключить свой же крейт, который ещё не вышел в свет. В этой статье мы разберём все способы — от простого указания пути до работы с Git-зависимостями и workspaces. Поехали!

Что такое unpublished crate и зачем он нужен?

Unpublished crate (неопубликованный крейт) — это Rust-пакет, который существует только на вашем локальном диске или в приватном репозитории. Он не загружен на crates.io и не доступен другим разработчикам (если только вы не дадите им доступ к файлам).

Типичные сценарии использования:

  • Разработка библиотеки параллельно с основным проектом
  • Рефакторинг: вы выделяете часть кода в отдельный крейт
  • Приватные корпоративные библиотеки, которые нельзя публиковать
  • Тестирование зависимостей перед публикацией

Главное преимущество — вы получаете полный контроль над кодом и можете мгновенно вносить изменения, не ожидая публикации на crates.io.

Способ 1: Path dependency — самый простой и быстрый

Это базовый метод, который подходит, когда оба проекта (зависимость и зависимый) находятся на вашем компьютере.

Структура проекта

Допустим, у вас есть следующая структура папок:

my_project/
├── my_lib/          # unpublished crate
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
└── my_app/          # основной проект
    ├── Cargo.toml
    └── src/
        └── main.rs

Шаг 1: Создаём библиотеку my_lib

Внутри my_lib/Cargo.toml:

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

[dependencies]

В my_lib/src/lib.rs напишем простую функцию:

pub fn greet(name: &str) -> String {
    format!("Привет, {}! Это локальный крейт.", name)
}

Шаг 2: Подключаем my_lib в my_app через path

В my_app/Cargo.toml добавляем секцию [dependencies]:

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

[dependencies]
my_lib = { path = "../my_lib" }

Обратите внимание: путь указывается относительно файла Cargo.toml основного проекта. Если библиотека лежит в другой директории, укажите абсолютный или относительный путь.

Шаг 3: Используем крейт в коде

В my_app/src/main.rs:

use my_lib::greet;

fn main() {
    let message = greet("Алексей");
    println!("{}", message);
}

Запускаем: cargo run — и видим вывод: "Привет, Алексей! Это локальный крейт."

Важно! Любые изменения в my_lib будут автоматически подхватываться при следующей сборке my_app. Не нужно ничего переустанавливать или обновлять версии.

Способ 2: Git-зависимости — для командной работы

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

Настройка

Предположим, ваш unpublished крейт my_lib находится в репозитории https://github.com/yourname/my_lib.git. В my_app/Cargo.toml пишем:

[dependencies]
my_lib = { git = "https://github.com/yourname/my_lib.git", branch = "main" }

Можно указать конкретный коммит или тег:

my_lib = { git = "https://github.com/yourname/my_lib.git", rev = "a1b2c3d4" }
my_lib = { git = "https://github.com/yourname/my_lib.git", tag = "v0.1.0-alpha" }

Cargo клонирует репозиторий в кеш и использует его как зависимость. При каждом обновлении (cargo update) он будет проверять новые коммиты.

Для приватных репозиториев используйте SSH:

my_lib = { git = "git@github.com:yourname/my_lib.git" }

Не забудьте настроить SSH-ключи на своей машине!

Способ 3: Workspace — когда проекты живут вместе

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

Создаём workspace

В корневой директории создаём Cargo.toml (без секции [package]):

[workspace]
members = [
    "my_lib",
    "my_app",
]

Структура будет такой:

my_workspace/
├── Cargo.toml          # workspace root
├── my_lib/
│   ├── Cargo.toml
│   └── src/
│       └── lib.rs
└── my_app/
    ├── Cargo.toml
    └── src/
        └── main.rs

Внутри my_app/Cargo.toml зависимость указываем как обычно через path, но теперь путь короче:

[dependencies]
my_lib = { path = "../my_lib" }

Теперь команда cargo build из корня workspace соберёт сразу оба крейта. Workspace гарантирует, что все зависимости будут разрешены единообразно, и вы можете запускать тесты для всей пачки одним махом: cargo test --workspace.

Частые ошибки и как их избежать

  • Ошибка: "package `my_lib` is not a workspace member" — если вы используете workspace, но забыли

Блоги

Рекомендаций по книгам