Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Среда no_std в Rust

Термин «встраиваемое программирование» охватывает очень разные классы программ: от программирования 8-битных микроконтроллеров (например, ST72325xx) с несколькими килобайтами ОЗУ и ПЗУ до систем вроде Raspberry Pi (Model B 3+), у которой есть 32/64-битный четырёхъядерный Cortex-A53 на 1,4 ГГц и 1 ГБ ОЗУ. Ограничения, которые действуют при написании кода, зависят от типа целевой платформы и сценария использования.

Есть два общих класса встраиваемого программирования:

Hosted-среды

Такие среды близки к обычному ПК. Это значит, что вам предоставляется системный интерфейс например, POSIX, который даёт примитивы для взаимодействия с различными системами: файловыми системами, сетью, управлением памятью, потоками и т. д. Стандартные библиотеки, в свою очередь, обычно опираются на эти примитивы для реализации своей функциональности. Также у вас может быть какой-то sysroot и ограничения на использование ОЗУ и ПЗУ, а возможно, и специфическое оборудование или входы/выходы. В целом это ощущается как разработка для специализированного ПК.

Bare-metal среды

В bare-metal среде перед запуском вашей программы не загружается никакой код. Без программного обеспечения, которое предоставляет ОС, мы не можем загрузить стандартную библиотеку. Вместо этого программа вместе с крейтами, которые она использует, может работать только с аппаратным обеспечением (bare metal). Чтобы компилятор Rust не подключал стандартную библиотеку, используйте no_std. Платформонезависимые части стандартной библиотеки доступны через libcore. libcore также исключает то, что не всегда желательно во встраиваемой среде. Одна из таких вещей — аллокатор памяти для динамического выделения памяти. Если вам нужны он или любая другая функциональность, часто существуют крейты, которые её предоставляют.

Рантайм libstd

Как уже говорилось, использование libstd требует интеграции с какой-то системой. Причина не только в том, что libstd предоставляет общий способ доступа к абстракциям ОС, но и в том, что она включает рантайм. Этот рантайм, среди прочего, настраивает защиту от переполнения стека, обрабатывает аргументы командной строки и запускает главный поток до вызова функции main вашей программы. Этот рантайм также недоступен в среде no_std.

Итог

#![no_std] — это атрибут уровня крейта, который указывает, что крейт будет связываться с core-крейтом, а не со std-крейтом. Крейт libcore, в свою очередь, является платформонезависимым подмножеством std, которое не делает никаких предположений о системе, в которой будет работать программа. Поэтому он предоставляет API для примитивов языка, таких как числа с плавающей точкой, строки и срезы, а также API, которые раскрывают возможности процессора, например атомарные операции и SIMD-инструкции. Однако в нём нет API для всего, что связано с интеграцией с платформой. Из-за этих свойств код с no_std и libcore можно использовать для любого вида начального (stage 0) кода, например загрузчиков, прошивок или ядер.

Обзор

Возможностьno_stdstd
heap (динамическая память)*✓
коллекции (Vec, BTreeMap и т. д.)**✓
защита от переполнения стека✘✓
инициализирующий код выполняется до main✘✓
libstd доступна✘✓
libcore доступна✓✓
разработка прошивки, ядра или загрузчика✓✘

* Только если вы используете крейт alloc и подходящий аллокатор, например alloc-cortex-m.

** Только если вы используете крейт collections и настраиваете глобальный аллокатор по умолчанию.

** HashMap и HashSet недоступны из-за отсутствия безопасного генератора случайных чисел.

См. также