Как установить rust на rust

Обновлено: 03.07.2024

Пробуем ручками

Ну что же, напоследок осталось написать простенькую программку, типа этого:

И начать её компилировать, только показывая все внутренности. Для начала есть замечательная опция компилятора, которая работает на любой версии:

Значит, запуская компиляцию следующим образом:

Мы получаем на выходе мириады различных форматов, включая сгенерированный ассемблеровский код, байткод и IR для LLVM, и даже челвоеко-читаемый MIR.

А если у вас есть nightly компилятор, то вы можете запустить

И полюбоваться вашим HIR, в то время как

Даст вам возможность посмотреть на то, как выглядит AST.

Словарь

Далее по тексту я буду разбрасываться следующими терминами без удержи. Если вы знаете что это всё значит - хорошо. Если нет, убедитесь что подтянули свои знания, перед тем как заныривать.

LLVM - система компиляции которая состоит из компилятора и набора инструментов, позволяющая создавать фронт-энд для любого языка и компилировать его на множество различных платформ.

AST - (abstract syntax tree) древовидная репрезентация семантической структуры исходного кода. Каждый узел обычно показывает конструкцию, встречающуюся в коде.

IR (intermediate representation) - Структура данных, обычно используемая в кишках компилятора или виртуальной машины, для представления исходного кода программы. Такую структуру обычно оптимизируют и перегоняют в конечный код.

HIR (High Level IR) - IR высокого уровня. Это основная репрезентация кода, используемая в rust. Фактически это представление AST, которым компилятору удобно пользоваться.

MIR (Mid Level IR) - Это репрезентация HIR, которая намного ближе к LLVMIR.

LLVMIR (Language Independent IR) - фактически это высокоуровневый ассемблер, который не привязан к определённому языку или системе. Такой код удобно оптимизировать и после он передаётся компилятору.

Крейт, crate - Это то, что будет скомпилировано либо в библиотеку или бинарник. На выходе будет одна библиотека или бинарник, вне зависимости от того, сколько файлов входят в крейт.

ICE (Internal compiler error), ошибка компилятора.

Дальнейший текст подразумевает, что вы умеете программировать. Можно и не на rust.

▍ Пишем программу

Ну что же, теперь мы умеем создавать программу на rust, которая может тянуть WinAPI. Дело за малым — создать окно, понакидать в него что-то, что будет представлять тайлы в нашей игре, и написать логику.

Ну что же, давайте создадим окно и понакидаем в него всякого разного.

Для начала, давайте обновим build.rs и добавим кое-какие функции, которые нам понадобятся.


После этого заменим импорты и код Main на следующий метод:


Здесь мы вызываем GetModuleHandleA. Эта функция возвращает нам называние модуля в котором мы работаем. Каждое окно должно быть привязано к определённому модулю. В данном случае это будет название нашего бинарного файла.

После этого создаём структуру WNDCLASSA и заполняем её параметрами, с которыми наше окно будет запускаться.

Далее, мы регистрируем этот класс.

После чего мы запускаем это окно, вызывая CreateWindowExW.

Компилируем и пробуем всё это запустить.

На экране нет ничего. Более того, если мы попробуем перекомпилировать проект, то у нас всё рухнет и ругнётся на линкер с ошибкой, что конечный бинарный файл для записи недоступен.

Идём в диспетчер задач и видим там, что наша программа безбожно висит.

Сколько раз вам приходилось видеть вот такое?


Именно поэтому наша программа превратилась в программу-невидимку.

Первым делом добавляем после CreateWindowExW следующий код


А в описании структуры WNDCLASSA заменим:

Теперь давайте запустим и проверим всё это.

Ура! Наконец-то! У нас есть окно!


Только не пытайтесь его закрыть. У вас всё рухнет. Окно закроется, а программа останется висеть в памяти. И не пытайтесь изменять размер этого окна. Если вдруг чего, вы увидите чёрные прямоугольники, вместо контента.

Обновляем код и получаем:


При закрытии окна мы выходим из программы, а при изменении размера мы его перерисовываем. Теперь окно не будет виснуть, и вы можете запустить и закрыть программу.

Проверяем. Бинарник размером в 160 килобайт, занимает 1 мегабайт оперативной памяти.

Проверяем знания:

▍ Написание программы

Итак, мы закончили с подготовкой. Что делать теперь? Теперь всё просто. Здесь можно брать документацию Windows API и искать то, что нам интересно.

Первое — функция main теперь должна возвращать windows::Result<()>. В данном случае мы будем возвращать пустой кортеж, но так как мы находимся в Windows, мы можем вернуть очень много вариантов значений. Для тех, кому это может понадобиться, Result принимает error, подробности здесь.


Второе — все вызовы самих Windows API должны производиться через директиву unsafe.

Я видел множество каких-то непонятный священных войн по поводу того, что использование директивы unsafe должно быть запрещено законом. Если честно, я никогда не понимал из-за чего происходят подобные войны. Давайте посмотрим на официальную документацию. Здесь нам ясно и чётко рассказывают, что в использовании unsafe нет ничего дьявольского, и оно разрешено Женевской конвенцией. Вам просто необходимо знать, что да как использовать.

Ок. Лезем дальше. Давайте откроем документацию Microsoft и найдём в ней MessageBoxA.

У нас есть четыре параметра, которые нам надо передать этой функции.

  • hWnd — дескриптор основного окна, в котором будет показано уведомление. Так как MessageBoxA — это модальное окно, то выполнение команд в основном окне заблокируется, пока будет активно уведомление. Так как у нас нет никакого окна, то сюда можно смело передавать NULL.
  • lpText/lpCaption — указатель типа Long на строку, строки, которые будут показывать в заголовке и теле окна.
  • uType — набор констант, которые зададут поведение, тип кнопок и иконок в этом MessageBox


Как вы видите, нам не пришлось изобретать велосипед, и пытаться создавать тип NULL, которого не существует в Rust, да и передача строк не требует шести преобразований их в разные форматы. Поэтому нам не нужно извращаться и писать что-то типа:


Всё достаточно цивильно.

Так, давайте подключим наши биндинги, соберём программу и посмотрим, как она работает. Конечный результат выглядит вот так:


Замечательно! Повсюду кракозябры, как в 1999 году. Что делать? Разбираемся и понимаем, что MessageBoxA работает c ANSI строками, в то время как MessageBoxW работает с Unicode (Wide strings). Собственно говоря, эта нотация сохранилась во всех Windows API. Я не знаю причин не использовать W версии функций. Но, будьте аккуратны, большое количество писателей мануалов на английском языке не понимают разницы, и вы увидите загруженность A версиями функций, в то время как вам необходимо использовать W версии этих функций.

Заменяем всё в lib.rs и main.rs. Пробуем ещё раз.


При весе в 164 килобайт на диске, программа занимает 940 килобайт оперативной памяти. И при этом работает с Windows API. Достаточно скромно. Лучше, чем ассемблер с кривыми биндингами, который работает только в консоли.

Итак, давайте пройдёмся по основным моментам этой главы:

  1. Вызов WinAPI это всегда unsafe вызов.
  2. fn main должна возвращать результат, понятный Windows.
  3. Вы знаете где и как найти документацию по Windows API и можете использовать их в вашей программе. (Все данные о WinAPI можно достать здесь, а данные о функциях, спортированных в rust находятся здесь.

Шаг пятый: rustc-expand

В результате работы парсера мы получаем наш самый великий и могучий AST.

Всё это создаётся огромным макросом astfragments! в \compiler\rustcexpand\src\expand.rs

AST используется для дальнейшей генерации кода и приведения его в нужный вид. Про это можно писать отдельную книгу. Но мы пока удовольствуемся там, что AST можно разобрать до HIR.

Постскриптум

А почему бинарник такой-то большой? Ну, на этот вопрос можно ответить легко. Залезаем вашим любимым дебаггером в .pdb файл и смотрим на указатели функций, которые тянутся в наш бинарник. Их много. Подсистема работы со строками, макросами и памятью. Плюс система ввода-вывода. Что, считаете что 150 килобайт - слишком много?

Быстро настройте среду разработки Rust и напишите небольшое приложение!

Создание нового проекта

Давайте напишем небольшое приложение с нашим новым окружением разработчика. Чтобы начать, мы используем Cargo для создания нового проекта. Запустите в вашем терминале:

cargo new hello-rust

Эта команда создаст новую директорию, зовущуюся hello-rust со следующими файлами:

Cargo.toml - это файл манифеста. Здесь хранятся метаданные вашего проекта, такие как описание.

В файле src/main.rs вы пишете код приложения.

cargo new создал для нас проект "Hello, world!". Для запуска этой программы мы перейдём в директорию, которая была создана, и запустим в терминале:

Вы должны увидеть следующее:

Шаг шестой: rustc-middle

Куда ты завёл нас? Не видно ни зги! Простите, ребята, не варят мозги. Вернее, мозг начинает вариться. Сложность процесса увеличивается настолько, что просто читая коды дальше ходить страшно. Ладно, обратимся к инструкции для разработчиков - смотрим. Видим что после того как у нас появился AST мы можем заняться приведением его в приличный вид. Вернее, в HIR.

Этим как раз и занимается rustc-middle. Вернее, не только этим. Залезаем в исходники и видим что тут у нас есть HIR, MIR и Types.

Что же происходит в реальности? Ну, для начала мы начинаем обработку AST. Этим, кстати занимается ещё один модуль, rust_ast_lowering . Смотрим туда и находим достаточно длинный файл, в котором и происходит преобразование каждого элемента AST в HIR.

Здесь весь синтаксический сахар растворяется в чае и перестаёт быть сахаром. Так моя любимая for node in data превращается в

А вот здесь, как раз, всеми любимый оператор ? первращается в Try::into_result :

С HIR теперь можно работать…

Напоследок

Понятно? Ну и хорошо.

Узнать больше!

Установить Rust

Вы можете попробовать Rust онлайн в Rust Playground без установки чего-либо на ваш компьютер.

Rustup: Установщик Rust и инструмент для управления версиями

Основным способом установки Rust, который используют люди, является Rustup - инструмент для установки и управления версиями Rust.

Кажется у вас запущена macOS, Linux или другая Unix-подобная ОС. Для загрузки Rustup и установки Rust, запустите следующее в вашем терминале и следуйте инструкциям на экране.

Похоже, вы работаете под управлением Windows. Чтобы начать использовать Rust, загрузите установщик, затем запустите программу и следуйте инструкциям на экране. Возможно, Вам потребуется установитьVisual Studio C++ Build tools при появлении соответствующего запроса. Если вы не работаете в Windows, смотрите "другие методы установки".

Windows Subsystem for Linux

Если вы используете Windows Subsystem for Linux, для установки Rust запустите следующее в вашем терминале и затем следуйте инструкциям на экране.

Rust запускается на Windows, Linux, macOS, FreeBSD и NetBSD. Если вы используете одну из этих платформ и видите это, то пожалуйста, сообщите о проблеме и следующих значениях:

Если вы используете Unix, то для установки Rust
запустите в терминале следующую команду и следуйте инструкциям на экране.

Если у вас запущен Windows,
скачайте и запустите rustup‑init.exe и затем следуйте инструкциям на экране.

Если у вас запущен Windows,
скачайте и запустите rustup‑init.exe, а затем следуйте инструкциям на экране.

Обновлён ли Rust?

Rust обновляется достаточно часто. Если вы устанавливали Rustup некоторое время назад, есть вероятность что версия Rust устарела. Получите актуальную версию Rust, запустив команду rustup update .

Cargo: Менеджер пакетов и инструмент сборки для Rust

При установке через Rustup, вы получаете последнюю стабильную версию пакетного менеджера и средства сборки Rust, известного, как Cargo. Cargo делает многие вещи:

  • собирает ваш проект с cargo build
  • запускает ваш проект с cargo run
  • тестирует ваш проект с cargo test
  • собирает документацию для вашего проекта с cargo doc
  • публикует библиотеку на crates.io с cargo publish

Чтобы удостовериться, что Rust и Cargo установлены, вы можете запустить в терминале следующую команду:

Другие инструменты

Поддержка Rust есть во многих редакторах:

Шак третий: rustc-interface

Ага. Тут мы уже ближе к самому процессу компиляции. Все конфиги подъедены, файлы тоже замеплены. Смотрим на исходники интерфейса. Их хоть и не так-то много, но это наш центральный вокзал, где куча других крейтов собирается воедино.

Так, осматриваемся и находим

Кстати тут же, недалеко, мы можем найти настройку механизма кодогенерации.

Быстренько посмотрим на наши сорцы и увидим что у нас прямо в сорцах есть 3 различных модуля кодогенерации. Что они делают? Превращают MIR в конечный код для системы компиляции. Открываем rustc-codegen-llvm и смотрим в README:

Ок, ну тут всё понятно, мы берём MIR и переделываем его в LLVM IR. После этого LLVM может скомпилировать код в конечный бинарник. Но погодите, помимо LLVM бекенда у нас есть ещё два других! Смотрим туда. rustc-codegen-ssa согласно документации, позволяет генерировать низкоуровневый код, который не будет привязан к определённому бекэнду (например, LLVM) и позволит в дальнейшем использовать другие системы компиляции.

Собственно говоря, прямо там же вы найдёте rustc-codegen-cranelift. То есть MIR в будущем может компилироваться через cranelift, который в идеале ускорит процесс компиляции. Ну это в будущем, пока что проект в процессе тестирования и работает не лучше, чем Газель без мотора.

Открываем модуль и смотрим, что происходит внутри:

Ага, вот тут мы берём быка за рога и начинаем разбирать исходный код на части. Далее, создаём и проверяем AST

И вот тут у нас начинается полное мясо. Прикол вот в чём, обычно компиляторы делают достаточно простую вещь - берёшь сорцы, проходишься по ним несколько раз, парсишь синтаксис, находишь ошибки, разбираешь на куски макросы, всё хорошо. rust в стародавние времена начинал именно так же. Но, со временем, была предложена новая модель компиляции. Запросы. Вместо того чтобы делать всю работу несколько раз подряд, давайте просто превратим проходы в запросы. Результат запроса можно сохранить в кеш. Если пользователь (программист) не менял ничего в определённом файле, то и компилировать его не надо. Если мы видим что делать это не надо, мы просто возвращаем данные из кеша запроса.

Даже если вы и поменяли что-то в каком-либо файле, то благодаря системе запросов вы сможете избежать ненужной перекомпиляции. Что если вы изменили только одну линию в комментариях к файлу? Пересобирать такой не придётся.

Давайте посмотрим на запросы, которые создаёт компилятор:

Парсинг, создание крейта, сбор HIR - всё это делается через запросы. Один момент про который полезно знать, это то что ещё не всё переписано на запросах.

В итоге у нас на выходе получается большая и толстая структура:

И как раз её можно дёргать для выполнения необходимых запросов.

Шак одиннадцатый: прощай, rust!

Полученный оптимизированный MIR можно теперь переделать в LLVM IR. Поехали. rustc-codegen-llvm создаёт LLVM-IR на базе MIR, который мы сгенерировали на предыдущем этапе. Здесь заканчивается rust и начинается llvm. Хотя, мы ещё не закончили с сорцами компилятора.

Тут можно найти пару интересных моментов, например rust-master\compiler\rustc_codegen_llvm\src\asm.rs содержит код для компилирования ассемблера напрямую из rust. Даже не замечал этого. Смотрим в документацию - есть такая поддержка в этом компиляторе!

Копаемся чуть глубже и находим rustc-target в котором видим различные дополнительные классы для работы с определённым ассемблером.

После того как кодогенерация завершена, мы можем передать IR в сам LLVM. rustc_llvm нам в помощь.

Вот, собственно говоря, и всё, ребята! LLVM за пределами нашей видимости. На моей операционной системе Visual Studio Build Tools берут на себя контроль и перегоняют LLVMIR в обычный бинарник.

Процесс компиляции в rust - это вам не мешки ворочать. Надо проверить неимоверное количество разных вещей. Вот что происходит с вашим кодом:

Он парсится из текста в AST.

AST обрабатывается и оптимизируется в HIR

HIR обрабатывается и оптимизируется в MIR.

MIR делает проверки заимствования и оптимизацию и перегоняется в LLVMIR.

LLVMIR компилируется на конечной платформе.

▍ Что дальше?

И всё это доступно прямо сейчас в rust. Надеюсь вы узнали для себя немного нового и возможно у вас появились идеи о том, как вы могли бы это применить в вашей работе. Что же, если это так, то я очень рад, что вам пригодилось.

И, как обычно, конкурс. На этот раз задача будет отстоять в реализации самой компактной игры 2048 написанной на rust. Первое место — эквивалент $25 в пейпал. Второе место — $15, третье $5.

Мерять будем потребление оперативки. Игра должна быть написана на rust и в ней обязательно использовать winapi. Она должна быть графической. Но конкретный движок на выбор.


В моей предыдущей статье о rust я попытался рассказать об истории языка, и показать откуда он пришёл. В статье было сделано множество упрощений. Просто нереальное множество. Народу не понравилось. Но в опросе, в конце статьи вы сказали, что надо бы показать кишки компилятора. Ну что же, под катом вы найдёте разбор исходных кодов компилятора rust. Мы проследим путь программы, начиная из исходного файла, прямиком к бинарнику.

Небольшое приложение на Rust

Теперь давайте напишем небольшое приложение с нашей новой зависимостью. В файл main.rs добавьте следующий код:

После того, как мы это сохраним, мы можем запустить наше приложение набрав:

При условии, что всё пошло хорошо, вы должны увидеть, что ваше приложение вывело на экран следующее:

Шаг седьмой: rustc_ty

И .\rust-master\compiler\rustc_middle\src\ty\mod.rs . Одна из самых больших частей компилятора занимается проверками системы типов после того, как у нас есть HIR. Какой тип будет у let mut a = 5; ? Вот на этот вопрос и ответит наша система работы с типами. Две основных структуры здесь:

Последняя тянется через весь процесс компиляции.

Файл просто огромный. Нам надо вычислить типы каждой переменной, замыкания и трейта. Сам модуль занимает более 3000 строк, не считая остальные файлы в директории.

Кстати, смотрим в rust-master\compiler\rustc_typeck\src\check\expr.rs

Хмм.. Если мы натыкаемся на брейк, после которого есть только один лейбл - rust то нужно запустить функцию fatally_break_rust .

Компилируем и запускаем:

Пасхалки они выглядят именно вот так.

Так, вычислили типы и теперь можем проверить что никто не пытается запихнуть строку в Int. Хорошо. Можно идти дальше.

▍ Введение

Для тех кто незнаком с Rust — вам необходимо будет подтянуть свои знания. Хотя бы потому что с момента своего создания в 2010 году язык завоёвывает популярность. С 2016 года язык появлялся в отчётах stackoverflow в списках самых любимых языков. В 2021 году Rust остаётся самым любимым языком на stackoverflow, что не мешает ему оставаться очень нишевым языком, доступным только избранным. В основном потому, что сам по себе Rust это низкоуровневый язык, который хоть и красив и приятен, но всё же учится не за 20 минут по видео из ютуба.

Rust используется в ядре Linux. Естественно, так как Rust был изначально создан в Mozilla Foundation, то большое количество компонентов Firefox написано именно на нём. В Microsoft решили, что не стоит отставать, и начали использовать Rust в части своих проектов.


И если год назад вы могли увидеть в репозитории упоминания, что проект не находится в стабильном состоянии и не рекомендуется к использованию в работе, то сейчас эти упоминания из проекта пропали. (Хотя, для того чтобы вы могли воспользоваться результатами этого проекта, вам всё равно придётся установить Rust Nightly билд, и вы успеете насмотреться на предупреждения от компилятора).

Итак, в чём заключается проект? Все Windows API импортированы в Rust и вы можете использовать любые стандартные функции прямо из вашей программы, без большого количества колдовства.

Шаг восьмой: rustc_mir и rustc_mir_build

Теперь наш HIR можно преобразовать в MIR. Берём ранее созданный TyCtxt и начинаем преобразовывать его в

И так далее по всем нодам. MIR это намного более генерализированная версия HIR. Она очень близка к тому что требует от нас LLVM для компиляции. В результате этой генерализации мы можем намного более эффективно работать над оптимизацией написанного вами кода и заниматься проверками заимствований и оптимизацией.

Шаг четвёртый: rustc-parse и rustc-lexer

Далее по тексту вы найдёте простую логику всех этих запросов. "Простая" логика заключается в вызове крейтов, которые её обрабатывают. Например, rustc-parse. Это крейт, который использует rustc-lexer. Лексер читает строки из файлов и преобразовывает их в очень простые токены. Токены передаются парсеру, который превращает их в Span и продолжает работу с кодом. Основной момент этого Span заключается в том, что к каждому элементу в дереве кода будет добавлена информация о том, в каком конкретно месте этот элемент записан в исходном файле. Когда компилятор будет сообщать об ошибке, вы увидите, где именно эта ошибка произошла.

Основная часть парсера запускается через вызов parse_crate_mod в rustc_parse\src\parser\item.rs . А дальше по тексту вы найдёте невероятное количество проверок синтаксиса, который этот парсер делает. Вот, например:

Другие методы установки

Для большинства разработчиков, процесс установки, при помощи rustup , описанный выше, является предпочтительным способом установки Rust. Однако, Rust также может быть установлен при помощи других методов.


Недавно я написал статью Трясём стариной — или как вспомнить Ассемблер, если ты его учил 20 лет назад. В статье рассказывается о том, как изучать ассемблер на примере игрушки 2048. Возможно для целей самой статьи игрушка была подходящая, но конечный результат меня немного удручил. Бинарник размером в 10 килобайт, который потребляет 2 мегабайта памяти, из-за неправильно слинкованной библиотеки резал глаза.

Посему я задался вопросом, а как это можно было бы сделать правильнее? Наверняка есть намного более удачное решение. (И организовал ещё один конкурс с призами в конце статьи)

А почему бы не сделать на Rust, и правильно прикрученных библиотеках? При этом, если вы знаете, что делаете, то вы можете запросто уменьшить количество потребляемой оперативной памяти, но при этом написать визуальную игрушку с использованием Windows API.

Причём это не значит, что вы будете использовать какую-то нестандартную библиотеку. Встречайте — windows-rs, проект поддерживаемый Microsoft. Ваш билет в мир Windows, если вы пишете на Rust.

При написании этой статьи я понял, что мы берём понемногу из двух миров — Windows API и rust. Определённые моменты будут казаться очевидными для rust разработчиков, другие моменты будут казаться очевидными для Windows разработчиков. Так как это — статья для всех, то я решил что будет лучше, если объясню больше, чем меньше.

Добавление зависимостей

Давайте добавим зависимость в наше приложение. Вы можете найти разного рода библиотеки на crates.io, реестре пакетов для Rust. В Rust мы обычно называем пакет "crates".

В этом проекте, мы используем пакет с именем ferris-says .

В нашем Cargo.toml файле мы добавим следующую информацию (которую мы получили со страницы пакета):

Теперь мы можем запустить:

. и Cargo установит наши зависимости.

Вы увидите, что эта команда создала новый файл, Cargo.lock . Этот файл представляет собой журнал точных версий зависимостей, которые мы используем локально.

Для использования нашей зависимости, мы можем открыть файл main.rs , удалить всё, что там есть (это просто ещё один пример) и добавить следующую строку:

Это строка означает, что мы теперь можем использовать функцию say , которую нам предоставил пакет ferris-says .

Кто этот краб, Ferris?

Ferris (Феррис) - это неофициальный талисман сообщества Rust. Многие программисты на Rust называют себя "Растациане", обыгрывая слово "crustacean".

Ferris - это имя, обыгрывающее прилагательное "ferrous" ("железистый"), обозначающее "содержащий железо". Поскольку Rust (один из переводов которого - "ржавчина") образуется на железе, название нашего талисмана выглядит забавным!

Кажется у вас запущена macOS, Linux или другая Unix-подобная ОС. Для загрузки Rustup и установки Rust, запустите следующее в вашем терминале и следуйте инструкциям на экране.

Похоже, вы работаете под управлением Windows. Чтобы начать использовать Rust, загрузите установщик, затем запустите программу и следуйте инструкциям на экране. Возможно, Вам потребуется установитьVisual Studio C++ Build tools при появлении соответствующего запроса. Если вы не работаете в Windows, смотрите "другие методы установки".

Windows Subsystem for Linux

Если вы используете Windows Subsystem for Linux, для установки Rust запустите следующее в вашем терминале и затем следуйте инструкциям на экране.

Rust запускается на Windows, Linux, macOS, FreeBSD и NetBSD. Если вы используете одну из этих платформ и видите это, то пожалуйста, сообщите о проблеме и следующих значениях:

Если вы используете Unix, то для установки Rust
запустите в терминале следующую команду и следуйте инструкциям на экране.

Если у вас запущен Windows,
скачайте и запустите rustup‑init.exe и затем следуйте инструкциям на экране.

Если у вас запущен Windows,
скачайте и запустите rustup‑init.exe, а затем следуйте инструкциям на экране.

Шаг второй: rustc-driver

Ладно, всё выглядит слишком уж просто. Погружаемся дальше. rustc тянет за собой rustc-driver. Ныряем туда.

Тут мы найдём небольшой readme, который расскажет нам о том, что компилятора в самом драйвере мы не найдём. Эта программа собирает конфигурацию из аргументов и запускает сам процесс компиляции из других крейтов. После изучения исходников находим функцию для запуска процесса компиляции.

Да, в этом крейте файлов не так-то много, но что бы тут не творилось, на самом деле всё сводится к вызову методов в крейте под названием interface. Вышеприведённый код это и показывает. interface::run_compiler и поехали.

Что же произошло в rustc-driver? Мы собрали все конфиги. Подгрузили все файлы и нашли их местоположение в файловой системе. Создали замыкание, которое следит за процессом компиляции и запускает линкер после успешной компиляции. Запустили линтеры (если такие имелись) и приготовили сам компилятор к запуску. Давайте запускать.

Шаг девятый: Проверка заимствования

Самая "страшная" функция rust это всем известный borrow cheker. Сам он живёт в

В rust-master\compiler\rustc_mir\src\borrow_check\mod.rs . Да, сам модуль такой же огромный и страшный, как и borrow checker. А вот тут, например, можно найти всю логику проверки заимствования при перемещении переменных rust-master\compiler\rustc_mir\src\borrow_check\diagnostics\move_errors.rs

Начало

Поехали. Мы будем лезть нашими ручками в сам компилятор и смотреть на его исходники. Для начала нам понадобятся кое-какие инструменты. Ставим чистую виртуальную машину с Windows 10. Идём в интернеты и льём следующее:

Сорцы компилятора. Достаются с github. Можно лить просто zip, ибо обратно коммитить мы ничего не будем.

Установщик компилятора. Любая свежая стабильная версия подойдёт.

Не будем мучиться, давайте, заодно, установим nightly компилятор.
rustup toolchain install nightly --allow-downgrade --profile minimal --component clippy rustup default nightly

Guide to Rustc Development. Инструкция по разработке компилятора. 460 страниц. Не хило. Сохраняем pdf.

Ну и хорошо. Этого, для начала достаточно. Отключаемся от проводного интернета, хватаем ноутбук и идём на веранду, сидеть и погружаться. Начинаем погружаться, понимаем что будет глупо говорить о компиляторе, если мы не скомпилируем хоть что-то. Ок, так и сделаем.

Ок, это было просто. Но мы не будем использовать cargo для самой компиляции. Используем компилятор напрямую. Но я же на надо cargo издеваюсь, так ведь?

Отступление по теме

Как не надо устанавливать rust

Как не надо устанавливать rust

Чего? Так, сам по себе компилятор всё собрал, но ругается на отсутствие линкера. От жеж, зараза. То есть, линкер ему нужен внешний. Ругаемся на компилятор, встаём с удобного кресла и идём обратно, подключаться к проводному интернету, потому что палить 5 гигов установщика Visual Studio Build Tools не хочется на хотспоте.

Билдим всё ещё раз и смотрим.

Ширина и жирина файлов.

Ширина и жирина файлов.

Ах, ты, ржавая банка! Какого чёрта?? Я уже как две недели рассказываю всем обитателям Хабра о том, какой ты прекрасный компилятор, и как хорошо ты собираешь минимальные бинарники, а ты. 150 килобайт исполняемого кода из-за одной только линии текста на экране?

Пытаемся скомпилировать с -C opt-level=3 и получаем то же самое. Что случилось с бинарником? Сейчас на этот вопрос отвечать не будем. Мотаем на Ус и едем дальше.

Копирайт - сдесь же.

Копирайт - сдесь же.

Ус недоволен. На него и так уже много чего намотано, он не понимает, почему ему надо разбираться с исходниками раста теперь.

Ладно, что мы знаем? Компилятор не работает без внешнего линкера и исходник для вывода одной строки текста раздувается до 150 килобайт. Ну, по крайней мере мы это можем скомпилировать. Давайте пока распакуем исходники компилятора и начнём рыться. (Собирать компилятор я не собираюсь. Если вам очень хочется - это можно сделать, но процесс это долгий и утомительный.)

Шаг первый: rustc

Открываем сорцы и наслаждаемся. Всё выглядит очень прилично и чисто. Тут, понятное дело, можно учиться тому как правильно разделять свой проект на куски и как правильно управлять кодом на rust. Собственно говоря, сразу понятно куда идти. Забираемся в compiler/rustc/src/main.rs и смотрим.

Всё только начинается. Держитесь.

Всё только начинается. Держитесь.

Хм. То есть точка входа в программу просто тянет jemalloc вызовы и запускает ещё две функции. Ну вот, всё. Теперь понятно как работает компилятор rust. Делов-то! Кстати, jemalloc это специальный менеджер памяти, изначально разработанный для FreeBSD в 2005 году. Основной упор был сделан на то, чтобы избежать фрагментации памяти при работе с этим аллокатором. В оригинальной версии он просто заменяет malloc. В 2007 году Firefox начал использовать этот менеджер для снижения расхода памяти, а ещё через пару лет он попал в Facebook.

Шаг десятый: Оптимизации

Про систему оптимизаций в rust можно писать отдельную книгу. Всё аккуратно сложено в rust-master\compiler\rustc_mir\src\transform . LLVM сам по себе не сможет оптимизировать некоторые высокоуровневые примитивы, о которых знает только rust. И вот тут мы как раз и занимаемся оптимизацией этих примитивов.

Примечания об установке Rust

Начало работы

Если вы только начали работать с Rust и хотите более глубокого погружения, посмотрите страницу о начале работы.

Особенности Windows

На Windows, Rust дополнительно требует инструменты сборки C++ для Visual Studio 2013 или более поздней версии. Самый простой способ получить эти инструменты - это установка Microsoft Visual C++ Build Tools 2019 , которая предоставляет только инструменты сборки Visual C++. В качестве альтернативы этому способу, вы можете установить Visual Studio 2019, Visual Studio 2017, Visual Studio 2015 или Visual Studio 2013 и в процессе установки выбрать "C++ tools".

Для получения дополнительной информации о настройке Rust в Windows, смотрите Windows-специфичную документацию rustup .

Управление инструментами с rustup

Rust устанавливается и управляется при помощи rustup . Rust имеет 6-недельный процесс выпуска и поддерживает большое количество платформ, так что большое количество сборок Rust доступно в любое время. rustup согласованно управляет этими сборками на каждой платформе, поддерживаемой Rust, включая установку Rust из beta и nightly каналов выпусков, а также поддерживает дополнительные цели для кросс-компиляции.

Если вы ранее устанавливали rustup , то вы можете обновить инструменты разработчика запустив rustup update .

Для дополнительной информации смотрите документацию по rustup .

Настройка переменной окружения PATH

В среде разработки Rust, все инструменты устанавливаются в директорию

/.cargo/bin %USERPROFILE%\.cargo\bin , где вы можете найти набор инструментов Rust, включая rustc , cargo и rustup .

Соответственно, разработчики на Rust обычно включают её в переменную окружения PATH . В процессе установки rustup пытается сконфигурировать PATH . Из-за разницы между платформами, командными оболочками и багами в rustup , изменение PATH может не принести результата до тех пор, пока консоль не будет перезапущена или пользователь не перезайдёт в систему, а может и не удастся вообще.

Если после установки запуск команды rustc --version в консоли терпит неудачу, это может быть наиболее вероятной причиной.

Удалить Rust

Если вы по какой-то причине хотите удалить Rust, вы можете запустить rustup self uninstall . Нам будет тебя не хватать!

▍ Начало работы

Итак, что же нам нужно сделать, для того чтобы начать работать с Windows API в Rust.

Для начала, нам потребуется rust nightly.

rustup default nightly
rustup update

После этого вам нужно будет создать новый проект на rust и сразу создать дополнительную библиотеку под названием bindings.
cargo new testproject
cd testproject
cargo new --lib bindings .
И, после этого добавить в cargo.toml в нашем проекте зависимости для подключения библиотеки Microsoft.

[dependencies]
bindings = < path = "bindings" >
windows = "0.21.1"

На момент написания статьи, актуальная версия библиотеки 0.21.1, посему везде будем использовать именно эту версию.

После этого в самой папке с библиотекой bindings нам нужно будет добавить в Cargo.toml следующий текст:
[package]
name = "bindings"
version = "0.1.0"
edition = "2018"

[dependencies]
windows = "0.21.1"

[build-dependencies]
windows = "0.21.1"
Итак, что у нас тут получается? У нас есть проект под названием testproject, в нём есть библиотека bindings. Цель этой библиотеки — подключать зависимости для того, чтобы вы могли работать с Windows API в вашем приложении.

Сам файл bindings/src/lib.rs будет состоять из одной команды:


Это — вызов макроса, который подключит все необходимые зависимости.

И теперь, самое интересное, файл bindings/build.rs

Читайте также: