Hello, Cargo!
Cargo — это система сборки и менеджер пакетов Rust. Большинство растацеанов управляют своими проектами именно через Cargo, потому что он берёт на себя массу рутины: собирает ваш код, а также скачивает и собирает библиотеки, которые нужны этому коду. (Библиотеки, которые нужны вашему коду, называют зависимостями.)
У простейших программ вроде той, что мы только что написали, зависимостей нет. Если бы мы собирали «Hello, world!» через Cargo, задействовалась бы только та его часть, что отвечает за сборку. Но когда программы станут сложнее, вы начнёте добавлять зависимости — и если проект с самого начала создан через Cargo, делать это будет гораздо проще.
Подавляющее большинство проектов на Rust используют Cargo, поэтому дальше в книге мы считаем, что и вы им пользуетесь. Если вы ставили Rust официальным установщиком, как описано в разделе «Установка», Cargo у вас уже есть. Если Rust установлен каким-то другим способом, проверьте, есть ли Cargo, такой командой:
$ cargo --version
Если появился номер версии — всё в порядке! Если же видите ошибку вроде
command not found, загляните в документацию к своему способу установки и
узнайте, как поставить Cargo отдельно.
Создание проекта с Cargo
Создадим новый проект с помощью Cargo и посмотрим, чем он отличается от нашего первого «Hello, world!». Вернитесь в папку projects (или туда, где вы решили хранить код) и в любой ОС выполните:
$ cargo new hello_cargo
$ cd hello_cargo
Первая команда создаёт новый проект с именем hello_cargo. Cargo создаёт его файлы в одноимённой папке.
Перейдите в папку hello_cargo и посмотрите, что в ней лежит. Cargo сгенерировал для нас два файла и одну папку: файл Cargo.toml и папку src с файлом main.rs внутри.
Кроме того, он инициализировал новый Git-репозиторий и создал файл
.gitignore. Если запустить cargo new внутри уже существующего
Git-репозитория, файлы Git создаваться не будут; это поведение можно
переопределить командой cargo new --vcs=git.
Примечание: Git — распространённая система контроля версий. С помощью флага
--vcs можно указать cargo new другую систему контроля версий или
отказаться от неё совсем. Все доступные варианты покажет
cargo new --help.
Откройте Cargo.toml в любимом редакторе. Он должен выглядеть примерно как в листинге 1-2.
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2024"
[dependencies]
cargo newФайл записан в формате TOML (Tom’s Obvious, Minimal Language — «очевидный минималистичный язык Тома»). В этом формате Cargo хранит настройки.
Первая строка, [package], — заголовок секции: следующие за ним строки
настраивают пакет. Когда мы будем добавлять в файл новую информацию, появятся
и другие секции.
Следующие три строки задают то, что нужно Cargo для компиляции программы: имя,
версию и редакцию Rust. О ключе edition мы поговорим в
приложении E.
Последняя строка, [dependencies], открывает секцию, где перечисляются
зависимости проекта. Пакеты кода в Rust называются крейтами (crates). Для
этого проекта другие крейты не нужны, а вот в первом проекте из главы 2 они
понадобятся — тогда мы этой секцией и воспользуемся.
Теперь откройте src/main.rs:
Файл: src/main.rs
fn main() {
println!("Hello, world!");
}
Cargo сгенерировал для вас программу «Hello, world!» — точно такую же, как мы написали в листинге 1-1! От нашего первого проекта этот отличается только двумя вещами: код лежит в папке src, а в корне проекта есть файл настроек Cargo.toml.
Cargo ожидает, что исходный код находится в папке src. Корневая папка проекта — для README, информации о лицензии, файлов настроек и всего прочего, что не относится к коду. Cargo помогает держать проект в порядке: у каждой вещи своё место, и каждая вещь на своём месте.
Если вы начали проект без Cargo, как мы с «Hello, world!», его можно
перевести на Cargo: перенесите код в папку src и создайте подходящий
Cargo.toml. Проще всего получить этот Cargo.toml командой cargo init — она
создаст его автоматически.
Сборка и запуск проекта Cargo
Посмотрим, что меняется, когда программу «Hello, world!» собирает и запускает Cargo! Находясь в папке hello_cargo, соберите проект командой:
$ cargo build
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 2.85 secs
Эта команда создаёт исполняемый файл не в текущей папке, а в target/debug/hello_cargo (в Windows — target\debug\hello_cargo.exe). По умолчанию сборка отладочная, поэтому Cargo кладёт бинарник в папку debug. Запустить его можно так:
$ ./target/debug/hello_cargo # или .\target\debug\hello_cargo.exe в Windows
Hello, world!
Если всё прошло хорошо, в терминале появится Hello, world!. При первом
запуске cargo build Cargo также создаёт в корне проекта новый файл —
Cargo.lock. В нём записаны точные версии зависимостей проекта. У нашего
проекта зависимостей нет, поэтому файл почти пустой. Править его вручную
никогда не понадобится: его содержимым управляет Cargo.
Мы собрали проект через cargo build и запустили через
./target/debug/hello_cargo. Но можно сделать и то и другое одной командой —
cargo run скомпилирует код и сразу запустит получившийся файл:
$ cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/hello_cargo`
Hello, world!
cargo run удобнее, чем помнить про cargo build и потом набирать полный путь
к бинарнику, поэтому большинство разработчиков пользуются именно ею.
Обратите внимание: на этот раз в выводе нет строки о том, что Cargo
компилирует hello_cargo. Cargo понял, что файлы не менялись, поэтому не стал
пересобирать проект, а просто запустил бинарник. Если бы вы изменили исходный
код, Cargo пересобрал бы проект перед запуском, и вывод был бы таким:
$ cargo run
Compiling hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.33 secs
Running `target/debug/hello_cargo`
Hello, world!
Есть у Cargo и команда cargo check. Она быстро проверяет, что код
компилируется, но исполняемый файл не создаёт:
$ cargo check
Checking hello_cargo v0.1.0 (file:///projects/hello_cargo)
Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
Зачем может понадобиться сборка без исполняемого файла? Дело в том, что
cargo check обычно работает намного быстрее cargo build — как раз потому,
что пропускает создание исполняемого файла. Если вы постоянно проверяете код,
пока его пишете, cargo check гораздо быстрее скажет, компилируется ли ещё ваш
проект! Поэтому многие растацеаны по ходу работы то и дело запускают
cargo check, а cargo build — только когда исполняемый файл действительно
нужен.
Подведём итог тому, что мы узнали о Cargo:
- Создать проект можно командой
cargo new. - Собрать проект — командой
cargo build. - Собрать и сразу запустить — командой
cargo run. - Проверить проект на ошибки, не создавая бинарник, — командой
cargo check. - Cargo складывает результат сборки не рядом с кодом, а в папку target/debug.
Ещё одно преимущество Cargo — его команды одинаковы в любой операционной системе. Поэтому дальше мы уже не будем давать отдельные инструкции для Linux и macOS и для Windows.
Сборка релиза
Когда проект наконец готов к выпуску, скомпилируйте его с оптимизациями
командой cargo build --release. Исполняемый файл окажется в target/release,
а не в target/debug. С оптимизациями программа работает быстрее, но
компилируется дольше. Поэтому профилей сборки два. Отладочный — для
разработки: код пересобирается часто, и сборка должна быть быстрой. Релизный —
для финальной версии, которую вы отдадите пользователям: её собирают редко, а
работать она должна как можно быстрее. Если вы замеряете время работы своего
кода, обязательно собирайте его через cargo build --release и измеряйте
исполняемый файл из target/release.
Опираемся на соглашения Cargo
В простых проектах Cargo не даёт заметного выигрыша по сравнению с голым
rustc, но чем сложнее программа, тем больше от него пользы. Как только в программе
становится несколько файлов или появляются зависимости, гораздо проще
доверить организацию сборки Cargo.
Хоть проект hello_cargo и простой, в нём уже задействована большая часть
настоящих инструментов, с которыми вы будете работать в Rust и дальше. По сути,
чтобы начать работу над любым существующим проектом, достаточно скачать код
через Git, перейти в папку проекта и собрать его:
$ git clone example.org/someproject
$ cd someproject
$ cargo build
Подробнее о Cargo читайте в его документации.
Итоги
Вы отлично начали путь в Rust! В этой главе вы научились:
- устанавливать последнюю стабильную версию Rust через
rustup; - обновлять Rust до новой версии;
- открывать локальную документацию;
- писать и запускать программу «Hello, world!» напрямую через
rustc; - создавать и запускать новый проект по соглашениям Cargo.
Самое время написать программу посерьёзнее, чтобы привыкнуть читать и писать код на Rust. Поэтому в главе 2 мы напишем игру «Угадай число». Если же вам хочется сначала разобраться, как в Rust устроены базовые понятия программирования, прочитайте главу 3, а потом вернитесь к главе 2.