$ sudo teach|
    $ sudo teach|
    IT school
  • Telegram
  • Партнёрам
  • Все курсы
$ sudo teach IT
OOO "SALEPROFIT"Контакты и реквизитыIT-Park Logo

Школа

  • Блог
  • Проверить сертификат

Сотрудничество

  • Стать учителем
  • Партнёрская программа
  • О проекте

Право

  • Оферта
  • Политика конфиденциальности

© 2023–2026 $ sudo teach IT™. All Rights Reserved. Public user contributions licensed under CC BY-SA 4.0 license with attribution required
TelegramGitHubYouTube
ГлавнаяБлогСистемы сборки для новичков: как быстро понять Cargo, зависимостии и feature flags

Системы сборки для новичков: как быстро понять Cargo, зависимостии и feature flags

$ sudo teach IT
·22 июля 2026 г.·11 мин·58
Системы сборки для новичков: как быстро понять Cargo, зависимостии и feature flags

Разберём логику feature flags, workspace и воспроизводимость сборок на практике. Покажем, как читать ошибки Cargo и не утонуть в конфигурациях.

Содержание
Почему новички «тонут» именно в конфигурациях CargoБазовая модель Cargo: граф зависимостей и манифестыЧто такое Cargo.toml на самом делеРоль Cargo.lock: воспроизводимость и «почему на другой машине иначе»Feature flags: как Cargo «сводит» наборы включенийБазовая механика feature flagsFeature flags в зависимостях: включения распространяютсяЧто делает default и чем опасно «всё включить»Workspace: как устроено «собрать всё» и почему команды иногда ведут себя неожиданноworkspace как способ централизовать конфигурациюКак workspace влияет на сборку и тестыВоспроизводимость в workspace: lock-файл общий или нетКак читать ошибки Cargo: быстрые паттерны и точные действияОшибка про версию: «кандидаты не найдены» или конфликты semverОшибка про feature: «package … does not have these features»Ошибка из-за lock-файла при CI: --locked и несоответствияПрактика: как собрать проект с контролем feature flags и workspaceСценарий 1: вы управляете features в своём crateСценарий 2: вы контролируете features у зависимостиВоспроизводимость сборок: меньше сюрпризов в реальной жизниФиксируйте версии (и обновляйте осознанно)Контролируйте feature matrixТипичные ошибки начинающих (и как их избежать)Ошибка 1: «workspace собирается как я ожидаю» — но нетОшибка 2: «Я выключил feature командой, но поведение не изменилось»Ошибка 3: «Разные машины собирают по-разному»Ошибка 4: «Я не понимаю, откуда берётся зависимость»Упорядоченный путь новичка: как быстро разобраться без хаосаЗаключение

В мире Rust почти всё начинается с Cargo: менеджера пакетов, системы сборки и инструмента для публикации. Для новичка Cargo может выглядеть как «магия»: то зависимости подтягиваются сами, то появляются feature’ы, то workspace внезапно меняет поведение сборки. На практике проблема обычно не в Rust, а в том, что новичок не выстроил ментальную модель: как Cargo выбирает зависимости, как он комбинирует feature’ы, почему сборка на одной машине отличается от другой.

Ниже — практический разбор логики сборки в Cargo, понятный на старте: как работают workspace, dependencies, feature flags, и как добиться воспроизводимости. Отдельно — как читать типичные ошибки Cargo и не утонуть в конфигурациях. В конце упомяну курс Cargo – для начинающих! как один из способов закрепить материал, если хочется систематизации.


Почему новички «тонут» именно в конфигурациях Cargo

Cargo кажется простым: cargo build, cargo test, cargo run. Но стоит зайти глубже, появляются термины:

  • зависимости (dependencies, dev-dependencies, build-dependencies);
  • версии и разрешения (Cargo.lock, semver);
  • feature flags (включаем/выключаем куски кода);
  • workspace (много пакетов в одном репозитории);
  • флаги сборки (--features, --all-features, --no-default-features);
  • профили и target’ы (profile.*, --release, cross-compilation).

У проблемы две причины:

  1. Cargo — декларативный инструмент. Вы описываете намерение (какие зависимости и какие feature’ы), а Cargo оптимизирует что именно собрать.
  2. Сборка зависит от графа. Feature’ы «текут» вверх и вниз по дереву зависимостей, и итоговое множество feature’ов — результат объединения требований всех участников.

В этой статье мы построим модель, которая помогает предсказуемо понимать поведение Cargo без угадывания.


Базовая модель Cargo: граф зависимостей и манифесты

Что такое Cargo.toml на самом деле

Cargo.toml — это не только список зависимостей. Это декларация:

  • имя пакета и его версия;
  • какие зависимости нужны и с какими feature’ами;
  • какие feature’ы определены у вашего пакета;
  • как устроены workspace-компоновки;
  • профили сборки (в том числе опции оптимизаций и отладочной информации).

У новичка часто одна мысль: «Cargo просто скачивает зависимости». Реальность: Cargo строит граф модулей сборки из:

  • вашего пакета (package);
  • ваших feature’ов ([features]);
  • зависимостей и их feature’ов (указываются в Cargo.toml ваших зависимостей);
  • workspace-структуры (если вы собираете не один пакет, а набор).

Роль Cargo.lock: воспроизводимость и «почему на другой машине иначе»

Главный маркер воспроизводимости — файл Cargo.lock.

  • Для приложений (bin) обычно коммитят Cargo.lock в репозиторий.
  • Для библиотек (lib) часто не коммитят, чтобы потребитель сам выбирал набор версий по своим constraints.

Что важно понять:
Cargo.lock фиксирует конкретные версии зависимостей и тем самым стабилизирует поведение сборки. Если Cargo.lock отсутствует (или не используется), Cargo будет резолвить версии заново, и вы можете получить другую комбинацию зависимостей.

Мини-проверка воспроизводимости:

code
# На машине разработчика
cargo build

# На другой машине (или в CI) с одинаковым репозиторием и lock-файлом
cargo build --locked

Флаг --locked заставляет Cargo использовать только версии, записанные в Cargo.lock. Если граф зависимостей уже изменился, Cargo сообщит об ошибке — это ровно то, что нужно для воспроизводимых сборок.

Типичная ошибка, с которой сталкиваются новички:

the lock file ... needs to be updated, but --locked was passed

Это не «сломалось». Это сигнал: либо нужно обновить lock-файл (и затем закоммитить), либо вы пытаетесь собрать с несовпадающим состоянием зависимостей.


Feature flags: как Cargo «сводит» наборы включений

Базовая механика feature flags

Feature flag в Cargo — это способ включать/выключать части функциональности на уровне зависимостей и вашего кода.

У вас может быть так:

code
[features]
default = ["serde"]
serde = ["dep:serde"]

В коде вы обычно используете cfg атрибуты:

code
#[cfg(feature = "serde")]
use serde::{Serialize, Deserialize};

#[cfg(feature = "serde")]
#[derive(Serialize, Deserialize)]
pub struct Payload {
    pub value: String,
}

Но ключевое: feature’ы влияют на зависимости. В примере serde feature включает dep:serde — то есть включает саму зависимость.

Feature flags в зависимостях: включения распространяются

Самый частый источник путаницы: вы включили feature у своей зависимости — а теперь эффект проявился «в другом месте», потому что feature’ы агрегируются по графу.

Например, вы у себя включаете зависимость с feature’ами:

code
[dependencies]
my-lib = { version = "1.2", features = ["fast-mode"] }

Если my-lib внутри использует fast-mode и при этом включает другие feature’ы своих зависимостей — Cargo всё учтёт. В результате итоговый набор возможностей может стать шире, чем вы ожидали.

Правило мышления: итоговый граф feature’ов — объединение требований.
Если где-то в дереве включили feature X, то он будет включён в сборке, даже если другая часть считала, что он выключен.

Что делает default и чем опасно «всё включить»

По умолчанию Cargo включает default feature’ы зависимостей. Это удобно, но в сложных проектах приводит к «непонятному» поведению: вы добавили зависимость — и вместе с ней включились десятки функций и дополнительные зависимости.

Сигнал к дисциплине:

  • для воспроизводимости и управляемости — явно контролируйте feature’ы;
  • для диагностики — временно отключайте defaults.

Примеры команд:

code
# Включить только то, что вы явно указали
cargo build --no-default-features --features "serde"

# Для библиотеки (или диагностики) включить все default + дополнительные
cargo build --all-features

Подводный камень: --all-features часто включает несовместимые комбинации (разные ветки кода, несовпадающие ожидания). Поэтому как инструмент диагностики — да, как «нормальная сборка» для CI — не всегда.


Workspace: как устроено «собрать всё» и почему команды иногда ведут себя неожиданно

workspace как способ централизовать конфигурацию

workspace используется, чтобы объединить несколько пакетов в одном репозитории: библиотеки, примеры, интеграционные тесты, сервисы. При этом у каждого пакета остаётся свой Cargo.toml.

Пример корневого Cargo.toml workspace:

code
[workspace]
members = [
  "crates/core",
  "crates/api",
  "crates/cli",
]
resolver = "2"

resolver = "2" — важная настройка, которая относится к разрешению feature’ов в зависимости. Она меняет поведение агрегации в некоторых сценариях, и в современных проектах её обычно включают, чтобы получить ожидаемую модель.

Как workspace влияет на сборку и тесты

Команда cargo build из корня workspace может:

  • собрать пакет(ы) по умолчанию;
  • либо потребовать явно указать -p.

Новичок часто запускает cargo build в корне и считает, что собирается «всё». На практике Cargo по умолчанию может выбрать конкретный пакет, если workspace устроен иначе (например, если в корне есть свой package, а не только [workspace]).

Лучший способ не гадать:

  • используйте cargo metadata для анализа;
  • явно указывайте пакет: -p crate_name.

Например:

code
cargo test -p api
cargo build -p cli --release

Воспроизводимость в workspace: lock-файл общий или нет

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

Но в сложных проектах люди умудряются иметь несколько lock-файлов (например, если по ошибке запускают Cargo в разных директориях с разными root’ами). Тогда воспроизводимость ломается.

Практическая дисциплина:

  • всегда запускайте команды из корня workspace;
  • явно проверяйте, где лежит Cargo.lock.

Как читать ошибки Cargo: быстрые паттерны и точные действия

Ошибка про версию: «кандидаты не найдены» или конфликты semver

Типовые сообщения:

  • «failed to select a version for …»
  • «versions that meet the requirements … were found, but … conflicts»

Логика: у вас конфликт ограничений версий между разными участниками графа. Решение обычно одно из:

  1. ослабить constraints (например, с =1.2.3 на ^1.2);
  2. выровнять версионные требования между зависимостями;
  3. использовать [patch.crates-io] или [replace] (в продвинутых кейсах).

Новичку сложно сразу понять, кто именно задаёт конфликт. В таких случаях помогает смотреть на дерево резолва, но часто достаточно cargo tree.

code
cargo tree -i some-crate

Параметр -i показывает «кто зависит от указанного», а -p можно использовать для прицельного анализа.

Ошибка про feature: «package … does not have these features»

Это классика. Например, вы написали:

code
[dependencies]
some-lib = { version = "1.0", features = ["unknown-feature"] }

Cargo честно говорит, что такого feature нет. Причины:

  • feature переименовали;
  • feature отключён из-за версии;
  • feature является частью другого имени (иногда у crate могут быть похожие флаги).

Что делать:

  1. проверить документацию конкретной версии crate (а не README «последней» ветки);
  2. посмотреть Cargo.toml зависимого пакета (в локальном кеше или через источники);
  3. временно собрать с cargo update -p some-lib (только если вам действительно нужна новая версия).

Ошибка из-за lock-файла при CI: --locked и несоответствия

Если в CI вы запускаете сборку с --locked, а разработчик не закоммитил обновлённый Cargo.lock, вы получите ошибку, похожую на:

Cargo.lock needs to be updated but --locked was passed

Решение: обновить lock в локальной среде тем же способом, что в CI (обычно cargo build --release или cargo test), затем закоммитить Cargo.lock.

Важно: lock обновляется из-за изменения constraints или feature’ов. Частая причина: вы включили новый feature, а lock не обновили.


Практика: как собрать проект с контролем feature flags и workspace

Сценарий 1: вы управляете features в своём crate

Допустим, вы делаете библиотеку core с optional-функциональностью.

crates/core/Cargo.toml:

code
[package]
name = "core"
version = "0.1.0"
edition = "2021"

[features]
default = ["logging"]
logging = []
serde-support = ["dep:serde"]

[dependencies]
serde = { version = "1", optional = true }

Код:

code
#[cfg(feature = "logging")]
pub fn log_event() {
    // ...
}

Сборка из workspace-корня:

code
cargo build -p core --no-default-features
cargo build -p core --features serde-support

Если тесты требуют serde-support, включите feature при запуске тестов:

code
cargo test -p core --features serde-support

Сценарий 2: вы контролируете features у зависимости

crates/api/Cargo.toml:

code
[dependencies]
core = { path = "../core" }
my-http = { version = "0.9", features = ["compression"] }

Теперь ваше API автоматически соберёт с сжатие. Но если вы хотите отключить compression на уровне всего проекта, вам потребуется не только --no-default-features, а ещё «переопределить» зависимость так, чтобы её feature’ы были отключены. Cargo не всегда умеет «обнулить» feature у зависимости командой на верхнем уровне; нужно явно указывать зависимость в вашем Cargo.toml с нужными feature’ами.

Отсюда правило: управление feature’ами зависимостей лучше делать явно в манифесте верхнего уровня, а не надеяться на флаги командной строки.


Воспроизводимость сборок: меньше сюрпризов в реальной жизни

Фиксируйте версии (и обновляйте осознанно)

  1. Коммитите Cargo.lock для приложений.
  2. Используйте --locked в CI, чтобы ошибки проявлялись сразу.
  3. Обновляйте зависимости централизованно и внятно: через cargo update.

Пример дисциплины CI:

code
cargo test --locked

Если вы обновили версию зависимостей, вы ожидаете изменение lock-файла — значит, CI должен пройти после коммита.

Контролируйте feature matrix

Частая «мина»: вы тестируете проект в одном наборе feature’ов (например, по умолчанию), а в проде включаете другой. Cargo позволит вам собрать с разными feature комбинациями, но CI обычно это не покрывает.

Практический минимум:

  • тест по умолчанию (cargo test);
  • тест без default feature’ов (cargo test --no-default-features);
  • тест с ключевым feature’ом(ами) (например, --features serde-support).

Для больших проектов матрица растёт экспоненциально, но на старте важно закрыть хотя бы главные ветки.


Типичные ошибки начинающих (и как их избежать)

Ошибка 1: «workspace собирается как я ожидаю» — но нет

Решение: всегда смотрите, какой пакет(ы) выбран. Используйте:

code
cargo metadata --format-version 1 --no-deps

и/или запускайте с -p.

Ошибка 2: «Я выключил feature командой, но поведение не изменилось»

Причина почти всегда в том, что feature включён другой частью графа. Как проверить:

  • используйте cargo tree -f (в зависимости от версии Cargo и флагов);
  • смотрите feature selection через cargo build -vv (подробный вывод иногда помогает увидеть, что именно Cargo решает).

Ошибка 3: «Разные машины собирают по-разному»

Причина: либо нет lock-файла, либо он не используется, либо различаются флаги (--features, --no-default-features, target’ы). Минимальный ответ — реплицируйте команды и фиксируйте lock.

Ошибка 4: «Я не понимаю, откуда берётся зависимость»

Проверьте:

code
cargo tree -i <crate_name>

И попробуйте найти в выводе, кто является источником. Обычно там находится конкретная зависимость, у которой включили feature или изменили constraints.


Упорядоченный путь новичка: как быстро разобраться без хаоса

Если вам нужно «быстро понять» Cargo именно как систему, а не как набор команд, полезен такой порядок:

  1. Осознайте различие между приложением и библиотекой: lock-файл, публикация, ответственность за версии.
  2. Научитесь читать манифесты: dependencies, optional, features, default.
  3. Понять feature propagation: итог — объединение требований графа.
  4. Workspace как контейнер: научитесь явно указывать -p и не предполагать «собирается всё».
  5. Воспроизводимость: --locked и зафиксированная матрица features.
  6. Ошибки — как диагноз: --locked → mismatch lock; unknown-feature → несоответствие имён/версий; version conflicts → semver constraints и граф резолва.

И если вы хотите структурировать это обучение, довести до автоматизма работу с feature flags и видеть типовые паттерны на практике, хороший способ — курс Cargo – для начинающих!. Он обычно полезен тем, кому не хватает именно системного подхода и упражнений, а не «разрозненных советов».


Заключение

Cargo — не просто инструмент сборки, а система принятия решений: резолв зависимостей, агрегация feature flags и организация workspace-команд. Новички часто «тонут» не из-за сложности Rust, а из-за отсутствия модели: где именно решается включение features, почему lock-файл влияет на воспроизводимость, и почему workspace может выбирать пакеты иначе, чем ожидается.

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

  • Фиксируйте зависимости через Cargo.lock и используйте --locked.
  • Управляйте feature flags явно и проверяйте, что итоговый набор соответствует ожиданиям.
  • В workspace не полагайтесь на догадки — используйте -p

Войдите, чтобы поставить лайк и оставить комментарий.

Автор

$ sudo teach IT

Cargo – для начинающих!

Курс по теме

Cargo – для начинающих!

С нуля до уверенной работы с Rust-проектами. Подходит для начинающих и тех, кто уже пишет на Rust. Разберитесь с Cargo раз и навсегда — и перестаньте копировать команды вслепую.

Бесплатно
Открыть курс

Продолжите обучение

Все курсы
Python – для начинающих!

Python – для начинающих!

С нуля до профессионального уровня. Подходит для всех. Учитесь каждый день и овладейте самым популярным языком программирования.

Перейти к курсу
Простыми словами о защищенном соединении

Простыми словами о защищенном соединении

Базовый курс для обычных людей: что такое защищённое соединение, как оно устроено, что оно умеет и чего не умеет, как выбрать сервис и настроить его на своих устройствах.

Перейти к курсу
Ботостроение Telegram

Ботостроение Telegram

Лёгкий, быстрый и доступный способ познакомиться с миром ботостроения в Telegram. Видео, конспекты, практика и помощь – всё у нас на курсе.

Перейти к курсу
Сервис, который не падает - как построить безопасную зашифрованную сеть

Сервис, который не падает - как построить безопасную зашифрованную сеть

Практический курс по безопасности сети: как собрать собственный сервис защищённого доступа - от пустого сервера до подписки с автовыбором - и, что важнее, как потом не уронить его своими руками.

Перейти к курсу

Другие статьи

Cargo для продакшена: workspaces, фичи и стратегия версий зависимостей
cargo

Cargo для продакшена: workspaces, фичи и стратегия версий зависимостей

Разберём, как организовать Rust workspace, управлять optional features, фиксировать версии библиотек и уменьшать “дрейф” зависимостей при командной разработке и CI.

18 сентября 2026 г.
1000
FastAPI для новичков: как организовать структуру проекта, чтобы не писать всё в одном файле
fastapi

FastAPI для новичков: как организовать структуру проекта, чтобы не писать всё в одном файле

Разложим приложение на роуты, сервисы и слой моделей, настроим зависимости и обработчики ошибок. Цель — база для дальнейшего роста без будущего “рефакторинга на боль”.

26 июля 2026 г.
640
Создание Telegram бота в 2026 легко и просто! Полный курсы!
создание

Создание Telegram бота в 2026 легко и просто! Полный курсы!

19 июня 2026 г.
1431
Как выбрать, куда идти в IT: веб, боты, данные — без хаоса
выбрать

Как выбрать, куда идти в IT: веб, боты, данные — без хаоса

Разберём самые понятные направления для новичка (веб, боты, аналитика/данные) и чем они отличаются по шагам обучения. В конце вы получите простой план, как проверить, что вам подходит, и какой стартовый путь выбрать.

5 октября 2026 г.
580
Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть
путь

Путь от README до демо: как собрать портфолио разработчика, чтобы его хотели смотреть

Разберём структуру репозитория, как упаковать проект в понятную историю (проблема → решение → запуск → метрики качества) и какие артефакты повышают доверие: скринкасты, архитектурная схема, чек-лист продакшн-готовности.

17 сентября 2026 г.
1070
Как понять, какой язык программирования учить первым: простой тест и выбор
понять

Как понять, какой язык программирования учить первым: простой тест и выбор

Помогу новичку выбрать первый язык без стресса: объясню варианты по целям (веб, боты, анализ данных), что учить в первую очередь и как не потратить месяцы впустую. В конце — краткий план старта на ближайшие недели.

2 октября 2026 г.
630

Комментарии

Станьте первым в обсуждении

Поделитесь мнением о статье или задайте вопрос автору

Содержание

Почему новички «тонут» именно в конфигурациях CargoБазовая модель Cargo: граф зависимостей и манифестыЧто такое Cargo.toml на самом делеРоль Cargo.lock: воспроизводимость и «почему на другой машине иначе»Feature flags: как Cargo «сводит» наборы включенийБазовая механика feature flagsFeature flags в зависимостях: включения распространяютсяЧто делает default и чем опасно «всё включить»Workspace: как устроено «собрать всё» и почему команды иногда ведут себя неожиданноworkspace как способ централизовать конфигурациюКак workspace влияет на сборку и тестыВоспроизводимость в workspace: lock-файл общий или нетКак читать ошибки Cargo: быстрые паттерны и точные действияОшибка про версию: «кандидаты не найдены» или конфликты semverОшибка про feature: «package … does not have these features»Ошибка из-за lock-файла при CI: --locked и несоответствияПрактика: как собрать проект с контролем feature flags и workspaceСценарий 1: вы управляете features в своём crateСценарий 2: вы контролируете features у зависимостиВоспроизводимость сборок: меньше сюрпризов в реальной жизниФиксируйте версии (и обновляйте осознанно)Контролируйте feature matrixТипичные ошибки начинающих (и как их избежать)Ошибка 1: «workspace собирается как я ожидаю» — но нетОшибка 2: «Я выключил feature командой, но поведение не изменилось»Ошибка 3: «Разные машины собирают по-разному»Ошибка 4: «Я не понимаю, откуда берётся зависимость»Упорядоченный путь новичка: как быстро разобраться без хаосаЗаключение