Привет, Cargo!

Cargo является системой сборки и менеджером пакетов в Rust. Большая часть разработчиков используют данный инструмент для управления проектами, потому что Cargo выполняет множество задач для вас. Такие как сборка кода, загрузка библиотек зависимостей и сборка этих библиотек. (Мы называем библиотеками то, что необходимо вашему коду как зависимость (dependencies).)

Простейшие Rust программы, вроде той что мы уже написали, не имеют зависимостей. Если мы собрали “Hello, world!” проект с помощью Cargo, то сборка использовала только часть возможностей Cargo, тех которая делает только сборку кода. По мере того, как вы будете писать более сложные программы на Rust, вы будете добавлять зависимости. А если вы создадите проект с помощью Cargo, то такое добавление будет проще выполнить.

Так как большая часть проектов использует Cargo, то остальная часть книги подразумевает, что вы также используете Cargo. Cargo устанавливается вместе с Rust при использовании официальных установщиков в разделе “Установка Rust”. Если вы установили Rust другим способом, то проверьте есть ли установленный Cargo, введя команду в терминале:

$ cargo --version

Если команда выдала номер версии, то он у вас стоит! Если вы видите ошибку, вроде "команда не найдена" 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 внутри. Он также создал новый Git репозиторий с файлом .gitignore.

Заметьте: Git является общей системой контроля версий (version control system). Можно изменить cargo new на использование другой системы контроля версий или вообще без неё используя флаг --vcs. Запустите команду cargo new --help чтобы увидеть доступные опции.

Откройте файл Cargo.toml в любом текстовом редакторе. Он должен выглядеть как код в листинге 1-2.

Название файла: Cargo.toml

[package]
name = "hello_cargo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"

[dependencies]

Листинг 1-2: Содержимое файла Cargo.toml сгенерированное командой cargo new

Это файл в формате TOML (Tom’s Obvious, Minimal Language), который является форматом конфигураций Cargo.

Первая строка, [package], является заголовочным разделом, который указывает что следующие указания настраивают пакет. По мере добавления больше информации в данный файл, будет добавляться больше разделов.

Следующие четыре строки указывают конфигурационную информацию, которая нужна Cargo для компиляции программы: имя (name), версия (version), кто написал и используемую редакцию (edition) Rust. Cargo получает ваше имя и эл.адрес (email) из окружения вашей ОС, так что если информация не корректна, исправьте эти данные и сохраните файл. Мы поговорим про редакцию edition Rust в Приложении E.

Последняя строка, [dependencies] является началом секции для списка любых зависимостей вашего проекта. В Rust, это внешние пакеты кода, на которые ссылаются ключевым словом crate. Нам не нужны никакие зависимости в данном проекте, но мы будем использовать их в первом проекте главы 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 проекта

Посмотрим, в чем разница при сборке и запуске программы “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), а не в текущей директории проекта. Можно запустит исполняемый файл командой:

$ ./target/debug/hello_cargo # or .\target\debug\hello_cargo.exe on 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 компилировал 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 build или cargo check.
  • Можно одновременно собирать и запускать проект одной командой, используя cargo run.
  • Cargo не сохраняет результаты сборки в директорию с исходным кодом, а сохраняет их в отдельный каталог target/debug.

Дополнительным преимуществом использования Cargo является то, что его команды одинаковые не зависимо от операционной системы в которой вы работаете. С этой точки зрения, мы больше не будем предоставлять отдельные инструкции для Linux, macOS или Windows.

Сборка финальной версии (Release)

Когда проект наконец готов к релизу, можно использовать команду cargo build --release для его компиляции с оптимизацией. Данная команда создаёт исполняемый файл в папке target/release в отличии от папки target/debug. Оптимизации делают так, что Rust код работает быстрее, но их включение увеличивает время компиляции. По этой причине есть два отдельных профиля: один для разработки, когда нужно пересобирать быстро и часто, другой для сборки финальной программы, которую будете отдавать пользователям, которая готова к работе и будет выполняться максимально быстро. Если вы замеряете время выполнения вашего кода, убедитесь выполнить cargo build --release и протестировать исполняемый файл в папке target/release.

Cargo как конвенция

Для простых проектов Cargo не даёт большой пользы по сравнению с использованием rustc, но он докажет свою пользу как только ваши программы станут более запутанными. С помощью Cargo гораздо проще координировать сборку на сложных проектах, скомбинированных из множества внешних библиотек (crates).

Не смотря на то, что проект hello_cargo простой, теперь он использует большую часть реального инструментария, который вы будете использовать остальную часть вашей Rust карьеры. В реальности, чтобы работать над любыми существующими проектами, можно использовать следующие команды для получения кода с помощью Git, перехода в проектный каталог и сборку:

$ git clone someurl.com/someproject
$ cd someproject
$ cargo build

Для более детальной информации про Cargo, загляните в его документацию.

Итоги

Теперь вы готовы начать своё Rust путешествие! В данной главе вы изучили как:

  • Установить последнюю стабильную версию Rust используя rustup
  • Обновить Rust до последней версии
  • Открыть локально установленную документацию
  • Написать и запустить программу типа "Hello, world!" используя напрямую компилятор rustc
  • Создать и запустить новый проект, используя конвенции и команды Cargo

Пришло время для создания более содержательной программы, чтобы привыкнуть к чтению и написанию кода на Rust. В главе 2 мы создадим программу для угадывания числа. Если вы хотите начать с изучения общих концепций программирования в Rust, загляните в главу 3, а затем вернитесь к главе 2.