Вы никогда не задумывались о том, чтобы запустить на домашнем роутере какой-нибудь пакет Ubuntu? Для этого можно было бы использовать контейнеры LXC. Всё это легко настроить, но такая установка будет не очень эффективной: зачем устанавливать целый дистрибутив Linux на маршрутизатор ради маленьких программ, используемых в домашней автоматизации?
В качестве примера в статье рассматривается маршрутизатор Turris Omnia.
Какие ещё есть варианты?
Остановимся на варианте с Rust. Чтобы получить программу Rust, запускаемую на Turris, нужно:
Примечание: следующие инструкции предназначены для Ubuntu 18.04 LTS. Для запуска Ubuntu на компьютере с Windows я использую подсистему Windows для Linux.
Цели кросс-компиляции обычно представлены в таком формате:
{architecture}-{vendor}-{system}-{abi}Мы уже знаем, что процессор Turris Omnia имеет архитектуру ARMv7. В случае с системами Linux поставщик обычно неизвестен (unknown
), потому что имя поставщика дистрибутива не так важно. Последняя часть (ABI) — это двоичный интерфейс приложений, используемый операционной системой Turris OS. В Linux это связано с реализацией libc, которую можно узнать с помощью ldd --version.
$ ssh [email protected] "ldd --version"
musl libc (armhf)
Version 1.1.19
Dynamic Program Loader
Usage: ldd [options] [--] pathname
Цель кросс-компиляции для Turris Omnia представлена в таком виде: armv7-unknown-linux-musleabihf
. К счастью для нас, в Rust есть поддержка 2-ого уровня платформ:
Второй уровень платформ предусматривает«гарантированную сборку». Автоматические тесты не выполняются, поэтому создание рабочей сборки не гарантируется, но платформы работают обычно довольно хорошо, и предлагаемые улучшения всегда приветствуются!
Прежде чем начинать, давайте убедимся, что у нас установлен необходимый инструментарий.
$ sudo apt-get install build-essentialНаша задача стала бы намного проще, если бы мы нацеливались на gnueabihf
вместо musleabihf
, потому что в Ubuntu есть пакеты с набором инструментальных средств кросс-компиляции для целей gnueabihf
. MUSL пока что для меня загадка: я почти ничего не знаю об этой реализации стандартной библиотеки C.
К счастью, есть проект под названием musl-cross-make, который даст нам «простую makefile-сборку для кросс-компилятора musl», и он отлично работает! Сначала загружаем исходные коды с GitHub:
$ wget https://github.com/richfelker/musl-cross-make/archive/master.tar.gz
$ tar xzf master.tar.gz
$ cd musl-cross-make-master
Давайте настроим параметры конфигурации, прежде чем приступать к сборке. Скопируем файл шаблона конфигурации config.mak.dist
в config.mak
и установим следующие параметры (вы можете отменить преобразование соответствующих строк шаблона в комментарий):
TARGET=arm-linux-musleabihf
OUTPUT=/usr/local
MUSL_VER = 1.1.19
(Лучше использовать ту же версию MUSL, которая указана в ldd --version
на вашей Turris. У меня на момент написания статьи была версия 1.1.19
).
Пора делать сборку!
$ make
$ make install
Весь инструментарий у нас должен быть установлен в /usr/local
и доступен на PATH
. Давайте проверим и запустим gcc:
$ arm-linux-musleabihf-gcc --version
arm-linux-musleabihf-gcc (GCC) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
(...)
Пока что у нас есть только предположительная цель компиляции, соответствующая платформе Turris. Пришло время проверить наши предположения на практике.
Напишем простую программу “Hello world” на C и сохраним следующий код в файл с именем hello.c
:
#include <stdio.h>
int main() {
printf("Hello, World!\n");
return 0;
}
Выполняем кросс-компиляцию этой программы для Turris:
arm-linux-musleabihf-gcc hello.c -o helloЗагружаем программу на маршрутизатор и выполняем её там. Я сохраняю файл в /srv
(который поддерживается накопителем mSATA SSD), чтобы избежать ненужных записей во внутреннюю флэш-память. Если всё пройдёт хорошо, вы должны получить знакомое приветствие:
$ scp hello [email protected]:/srv
hello 100% 7292 1.6MB/s 00:00
$ ssh [email protected] /srv/hello
Hello, World!
Есть разные способы установки Rust, я остановил свой выбор на рекомендуемом подходе, в котором используется rustup
.
Необходимо также установить стандартные крейты (базовые модули Rust), скомпилированные для нашей целевой платформы.
$ rustup target add armv7-unknown-linux-musleabihfНа последнем этапе мы сообщаем компилятору Rust, какой компоновщик следует использовать при компиляции для целевой платформы. Добавляем в ~/.cargo/config
следующее:
[target.armv7-unknown-linux-musleabihf]
linker = "arm-linux-musleabihf-gcc"
Создаём программу “Hello world” на Rust и компилируем её:
$ cargo new --bin hello
$ cd hello
$ cargo build --target=armv7-unknown-linux-musleabihf
Compiling hello v0.1.0 (/home/bajtos/src/hello)
Finished dev [unoptimized + debuginfo] target(s) in 2.53s
Загружаем программу на маршрутизатор и выполняем её там. Если всё идёт хорошо, снова получаем наше приветствие.
$ scp target/armv7-unknown-linux-musleabihf/debug/hello [email protected]:/srv
hello 100% 2903KB 10.8MB/s 00:00 $ ssh [email protected] /srv/hello
Hello, World!
Поздравляю, теперь вы можете взять любую программу на Rust и запустить её на маршрутизаторе Turris Omnia. Например, если вы используете Mastodon и Twitter, то можете синхронизировать между этими двумя сетями всё то, что вы в них выкладываете, с помощью mastodon-twitter-sync.
Большая часть информации в этой статье основана на замечательном руководстве по кросс-компиляции программ на Rust.
Список платформ, поддерживаемых Rust, можно найти в официальной документации проекта здесь.
И наконец, мне потребовалась бы целая вечность, чтобы понять, как выполняется кросс-компиляция для MUSL ABI, если бы не было отличного проекта musl-cross-make project Рича Фелкера.
Вы заметили, что наша программа на C весит 7 Кб, в то время как версия Rust имеет 2903 Кб? Есть несколько способов уменьшить размер исполняемого файла программ на Rust. Активировав оптимизацию во время компоновки, мне удалось быстро уменьшить размер полученной сборки до 1408 Кб. О других, более продвинутых способах можно узнать в «Минимизации размера двоичного кода Rust»: https://github.com/johnthagen/min-sized-rust.
Перевод статьи Miroslav Bajtoš: Cross-compile Rust programs to run on Turris Omnia
Комментарии