Avatar ·

Как использовать локальный неопубликованный крейт (crate) в Rust?

Всем привет! Я новичок в Rust и пишу небольшой проект. У меня есть библиотека, которую я хочу использовать в основном приложении, но я не хочу публиковать её на crates.io, потому что она ещё сырая и нужна только для этого проекта. Вот структура моих файлов: ``` my_project/ ├── my_lib/ # мой локальный крейт │ ├── Cargo.toml │ └── src/ │ └── lib.rs └── my_app/ # основное приложение ├── Cargo.toml └── src/ └── main.rs ``` В `my_lib/Cargo.toml` написано: ```toml [package] name = "my_lib" version = "0.1.0" edition = "2021" ``` В `my_app/Cargo.toml` я пробовал добавить зависимость так: ```toml [dependencies] my_lib = { path = "../my_lib" } ``` Но когда я запускаю `cargo build` в папке `my_app`, получаю ошибку: ``` error: no matching package named `my_lib` found location searched: /path/to/my_lib required by package `my_app v0.1.0 (.../my_app)` ``` Я проверил, что путь правильный, и файлы существуют. Что я делаю не так? Может быть, нужно как-то иначе указывать путь или добавлять другие секции в Cargo.toml? Буду благодарен за подробное объяснение. <<>>

Правильный способ подключения локального крейта через путь

Ваша основная идея верна — использование path в Cargo.toml — это стандартный способ подключения локального неопубликованного крейта. Однако ошибка возникает из-за того, что Cargo не может найти крейт по указанному пути. Давайте разберёмся по шагам.

Шаг 1: Проверьте структуру папок

Убедитесь, что путь в path указан относительно файла Cargo.toml, который его содержит. В вашем случае ../my_lib означает «подняться на уровень выше и войти в папку my_lib». Если структура именно такая, как вы описали, путь корректен. Но часто начинающие путают относительные пути — попробуйте указать абсолютный путь для проверки:

[dependencies]
my_lib = { path = "/полный/путь/до/my_lib" }

Если это сработает, значит проблема именно в относительном пути. Рекомендую использовать относительные пути, но проверьте, что вы запускаете cargo build именно из папки my_app.

Шаг 2: Убедитесь, что крейт — библиотека

Ваш my_lib должен быть библиотекой (lib), а не исполняемым файлом (bin). В my_lib/Cargo.toml не должно быть секции [[bin]], а в src/lib.rs — функции main. Если вы случайно создали бинарный крейт, добавьте в Cargo.toml:

[lib]
name = "my_lib"
path = "src/lib.rs"

Или просто переименуйте src/main.rs в src/lib.rs.

Шаг 3: Правильная структура проекта (рекомендуемый способ)

Лучшая практика для Rust-проектов с локальными зависимостями — использовать workspace. Это позволяет управлять несколькими крейтами в одном репозитории. Создайте корневой Cargo.toml:

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

Теперь переместите папки my_lib и my_app внутрь корневой директории проекта. В my_app/Cargo.toml зависимость будет выглядеть так:

[dependencies]
my_lib = { path = "../my_lib" }  # относительно my_app

Или, если вы используете workspace, можно указать просто имя крейта, и Cargo сам найдёт его среди членов workspace:

[dependencies]
my_lib = { path = "../my_lib" }  # всё ещё работает, но можно и без path, если крейт опубликован

Шаг 4: Проверьте версию и имя крейта

Убедитесь, что в my_lib/Cargo.toml поле name совпадает с тем, что вы указываете в зависимости. Регистр важен: my_lib и My_Lib — разные имена. Также проверьте, что версия указана (хотя для локальных путей это не обязательно).

Полный пример рабочей конфигурации

my_lib/Cargo.toml:

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

[lib]
name = "my_lib"
path = "src/lib.rs"

my_lib/src/lib.rs:

pub fn greet(name: &str) -> String {
    format!("Hello, {}!", name)
}

my_app/Cargo.toml:

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

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

my_app/src/main.rs:

use my_lib::greet;

fn main() {
    println!("{}", greet("Rust developer"));
}

Что ещё стоит знать?

  • Отладка: Запустите cargo build -v (verbose), чтобы увидеть, какие пути ищет Cargo.
  • Кэш: Иногда помогает cargo clean и повторная сборка.
  • Git: Если вы используете git, не забудьте добавить Cargo.lock в репозиторий для воспроизводимости сборок.
  • Публикация: Когда крейт будет готов, вы сможете легко переключиться с path на версию из crates.io, просто заменив зависимость на my_lib = "0.1.0".

Надеюсь, это поможет! Если ошибка остаётся — проверьте права доступа к папке my_lib и убедитесь, что в ней есть Cargo.toml.

<<>>

Альтернативный подход: использование git-зависимости

Если вы не хотите использовать workspace или относительные пути (например, когда проект хранится в разных репозиториях), можно подключить локальный крейт через git. Для этого инициализируйте git-репозиторий в папке my_lib и сделайте хотя бы один коммит. Затем в my_app/Cargo.toml укажите:

[dependencies]
my_lib = { git = "file:///полный/путь/до/my_lib" }

Обратите внимание на file:// — это указывает Cargo на локальный git-репозиторий. Преимущество этого метода в том, что вы можете указывать конкретные ветки, теги или коммиты:

my_lib = { git = "file:///путь/до/my_lib", branch = "dev" }

Недостаток — нужно постоянно коммитить изменения в my_lib, чтобы они подтягивались в my_app. Для быстрой разработки это неудобно, но для изолированных проектов или CI/CD может быть полезно.

Также помните: если вы используете git-зависимость, Cargo будет клонировать репозиторий каждый раз при сборке, если не закеширует его. Для локальной разработки путь через path или workspace всё же предпочтительнее.