Привет, Cargo!

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

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

Так как большая часть проектов использует Cargo, то остальная часть книги подразумевает, что вы также используете Cargo. Cargo устанавливается вместе с Rust при использовании официальных установщиков обсуждаемых в разделе "Установка 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 в существующем репозитории Git; вы можете изменить это поведение, используя cargo new --vcs=git.

Примечание: Git - это распространённая система контроля версий. Вы можете заставить 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 возможно узнать отдельно в Приложении 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.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 run,
  • можно собрать проект для проверки ошибок с помощью cargo check, не тратя время на кодогенерацию исполняемого файла,
  • 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 example.org/someproject
$ cd someproject
$ cargo build

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

Итоги

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

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

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