Hello, Cargo!
Cargo — это система сборки и менеджер пакетов языка Rust. Многие программисты на Rust используют его для управления своими проектами, поскольку Cargo принимает на себя большое количество забот, таких как сборка вашего кода, загрузка необходимых вашему коду библиотек и их же сборка. (Мы будем называть библиотеки, необходимые вашему коду, зависимостями.)
Простейшие программы на Rust (вроде той, что мы написали), не имеют никаких зависимостей. Если бы мы использовали Cargo для сборки нашего проекта "Hello, world!", он использовал бы лишь тот функционал Cargo, который отвечает за сборку кода. По мере того, как вы будете писать всё более сложные программы на Rust, вы начнёте использовать зависимости; так что если вы будете во всех своих проектах использовать Cargo с самого начала, вам будет легче добавлять зависимости.
Поскольку подавляющее большинство проектов на Rust использует Cargo, оставшаяся часть этой книги будет предполагать его использование и вами. Cargo поставляется вместе с Rust, если вы используете официальный метод установки, описанный в разделе "Установка". Если вы устанавливали Rust иными средствами, вы можете проверить, установлен ли у вас Cargo, введя эту команду:
$ cargo --version
Если вы видите номер версии, то Cargo у вас есть! Если же видите ошибку, вроде command not found
, обратитесь к документации вашего метода установки, чтобы узнать, как отдельно установить Cargo.
Создание проекта через Cargo
Создадим новый проект через Cargo и посмотрим, чем он будет отличаться от проекта "Hello, world!", написанного нами ранее. Перейдите в директорию projects (или туда, куда вы решили сохранять свой код) и выполните (независимо от вашей операционной системы) эти команды:
$ cargo new hello_cargo
$ cd hello_cargo
Первая команда создаёт новую директорию и проект под названием hello_cargo. Мы назвали проект hello_cargo, так что Cargo создал его файлы в директории с таким же названием.
Перейдите в директорию hello_cargo и посмотрите список файлов. Вы увидите, что Cargo также сгенерировал два файла и одну директорию: файл Cargo.toml и директорию src с файлом main.rs внутри.
Cargo также инициализировал новый Git-репозиторий и создал файл .gitignore. Файлы Git не будут генерироваться, если вы выполните cargo new
в уже существующем репозитории. Впрочем, вы можете переписать это поведение, используя cargo new --vcs=git
.
Примечание: По умолчанию, в качестве системы версионирования используется Git. Вы изменить
cargo new
и использовать другую систему версионирования (version control system) или вовсе отказаться от использования системы версионирования, используя флаг--vcs
. Выполнитеcargo new --help
, чтобы увидеть доступные варианты.
Откройте файл Cargo.toml в вашем текстовом редакторе. Он должен выглядеть как код в Листинге 1-2.
[package]
name = "hello_cargo"
version = "0.1.0"
edition = "2021"
[dependencies]
Этот файл использует формат 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! Вообще, вся разница между нашим проектом и проектом, созданным Cargo, состоит лишь в том, что Cargo поместил код в директории src и создал конфигурационный файл Cargo.toml в корневой директории проекта.
Cargo ожидает, что ваши исходные файлы будут находиться в директории src. Корневая директория проекта предназначена лишь для файлов README, информации о лицензиях, конфигурационных файлов и всего прочего, что не относится к непосредственно коду. Использование Cargo поможет вам организовывать свои проекты. С ним для всего найдётся место, и всё разместится на своих местах.
Если вы создали свой проект без Cargo (например, как мы ранее сделали с проектом "Hello, world!"), вы можете преобразовать его в проект, использующий Cargo. Переместите код проекта в директорию src и создайте правильный файл 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 (или target\debug\hello_cargo.exe на Windows), а не корневой директории проекта. Поскольку по умолчанию используется сборка в режиме отладки (debug), Cargo положил бинарный файл в директорию под названием debug. Вы можете запустить исполняемый файл, написав в консоли:
$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on Windows
Hello, world!
Если всё хорошо, вы увидите Hello, world!
в терминале. Запуск cargo build
в первый раз приводит к появлению нового файла в директории проекта: 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 run
.
Отметим, что в этот раз мы не увидели сообщений 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
позволит без больших трат времени убеждаться, что проект всё ещё компилируется! Поэтому, многие программисты на Rust периодически запускают cargo check
по мере работы над программой. А cargo build
применяется тогда, когда программа готова к использованию.
Повторим то, что мы узнали о Cargo:
- Мы можем создавать проекты, используя
cargo new
. - Мы можем собирать проекты, используя
cargo build
. - Мы можем собирать и запускать проекты одной командой
cargo run
. - Мы можем проверить код на ошибки компиляции, не создавая исполняемый файл, используя
cargo check
. - Cargo сохраняет результаты сборки не в корневую директорию проекта, а в директорию target/debug.
Дополнительным преимуществом использования Cargo является то, что его команды будут одинаковы для любых операционных систем. Так что с этого моменты мы более не будем предоставлять инструкции, специфичные для Linux и macOS или Windows.
Создание релизной версии
Когда ваш проект наконец-то готов в релизу, вы можете использовать cargo build --release
, чтобы собрать его с оптимизациями. Эта команда создаст исполняемый файл не в target/debug, а в target/release. Оптимизации делают ваш код на Rust более быстрым, но их включение также увеличивает время компиляции. Поэтому есть два профиля компиляции: один для разработки, когда вы хотите быстро и часто пересобирать проект; и другой, для сборки окончательной версии программы, которая будет распространяться среди конечных пользователей и которая потому должна работать предельно быстро. Если вы замеряете быстродействие своего кода, не забудьте собрать его через 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.