Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
171 lines (130 sloc) 10.8 KB

title: Кросс-компиляция Rust под Raspberry Pi в ArchLinux lang: ru tags: raspberry pi, rust, cross-compilation extends: default.liquid date: 13 Jun 2016 00:46:00 +0300 comments: true excerpt: | Намедни мне наконец-то приехала Raspberry Pi 3 на замену старому гудящему ноутбуку в качестве домашнего сервера. Поскольку вся серверная автоматизация была мной переписана на Rust, встала задача собрать всё это чудо под ARM. В качестве системы по-умолчанию у меня везде используется ArchLinux, Raspberry Pi не стала исключением.

Намедни мне наконец-то приехала Raspberry Pi 3 на замену старому гудящему ноутбуку в качестве домашнего сервера. Поскольку вся серверная автоматизация была мной переписана на Rust, встала задача собрать всё это чудо под ARM. В качестве системы по-умолчанию у меня везде используется ArchLinux, Raspberry Pi не стала исключением.

Стоит учесть одну особенность установки конкретно ArchLinux на Raspberry Pi 3. Сама третья малинка основана на процессоре ARMv8 64-битной архитектуры (AArch64), но пока что образа ArchLinux под эту архитектуру для малинки нет, так что приходится перебиваться образом для второй малинки под ARMv7, так что и собираю я под ARMv7. Пруф с офсайта:

Note: The current installation uses the 32-bit Raspberry Pi 2 armv7h root filesystem. This will be changing eventually to use our AArch64 repository to take full advantage of the ARMv8 Cortex-A53 cores. If you want an AArch64 system, consider the ODROID-C2.

Почему же тогда малинка, а не рекомендованный ODROID-C2? Потому что банально у малинки больше сообщество, так что найти мануалы, решения и ответы на вопросы проще.

Нагружать слабую малинку компиляцией под себя же я не стал, соответственно компилировать решено было на моём ноутбуке (с арчем, само собой). Я перепробовал следующие способы:

  • Кросс-компиляция со средой в докере — не взлетело, сборка контейнера постоянно валилась по самым разным причинам: то сеть отваливалась, то память кончалась. В итоге забил.
  • По мануалу с той же репы — слишком искусственно, не хотелось ставить пакеты без PKGBUILD-ов и возиться со своими PKGBUILD-ами.
  • В QEMU с помощью эмуляции ARMv7 — ядро, похоже, протухло и устарело. При попытке загрузить с ним система в панике висла (Attempted to kill init!). Собирать это ядро ручками мне совсем не улыбалось, тем более что оригинальный сайт со всеми инструкциями давно умер (https://xecdesign.com/downloads/linux-qemu/kernel-qemu).
  • С помощью скрипта для ArchLinux — и вот тут пошло повеселее. Этот способ сработал, хоть и было пару нюансов по ходу дела.

Во-первых, многие пакеты (в частности разные GCC) подписаны PGP-ключами разработчиков. Проблема в том, что yaourt требует, чтобы публичные части этих ключей были в локальном брелке пользователя и помеченные как доверенные, иначе ставить что-либо он отказывается. И он прав. Можно было бы во всех PKGBUILD-ах вручную убрать PGP-сигнатуры, но пакетов очень много, можно подзадолбаться, да и не правильно это, прямо скажем. В итоге я просто добавил нужные ключи себе в брелок и подписал их:

gpg --recv-keys 25EF0A436C2A4AFF
gpg --lsign 25EF0A436C2A4AFF

gpg --recv-keys 38DBBDC86092693E
gpg --lsign 38DBBDC86092693E

gpg --recv-keys 79BE3E4300411886
gpg --lsign 79BE3E4300411886

Возможно, что когда вы будете ставить эти пакеты, разработчики поменяют ключи, так что у вас сигнатуры будут отличаться. Мне же понадобилось поставить именно эти ключики.

После этого всё поставилось как по маслу, только нужно было отвечать «да» на вопросы о замене пакетов по ходу установки (gcc-stage1 заменяется gcc-stage2, а тот, в свою очередь, заменяется gcc).

Во-вторых, мне понадобились дополнительные библиотеки под ARM, в частности libssl и libz, которые вместе с GCC не собираются. Можно было бы их с сырцов собрать под ARM вручную, но я просто тупо скопировал все *.so и *.a файлы из /usr/lib самого Raspberry Pi в мой тулчейн в /usr/arm-linux-gnueabihf/lib и закрыл этот вопрос.

В-третьих, нужно было настроить Cargo. Это просто, надо только в ~/.cargo/config добавить такие строки:

[target.armv7-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
ar = "arm-linux-gnueabihf-ar"

[target.arm-unknown-linux-gnueabihf]
linker = "arm-linux-gnueabihf-gcc"
ar = "arm-linux-gnueabihf-ar"

В принципе достаточно было бы описать конфиг только для armv7-unknown-linux-gnueabihf, потому что я пользовался только этим таргетом, но я решил сделать всё основательно и на совесть.

В-четвёртых, надо поставить растовские таргет и тулчейн для ARMv7. Сделать это с rustup до обидного просто:

rustup toolchain install stable-arm-unknown-linux-gnueabihf
rustup target add armv7-unknown-linux-gnueabihf

Следующие грабли, на которые я наступил: в установленном этим способом тулчейне нет файла arm-linux-gnueabihf-cc, а Rust в процессе компиляции нативных библиотек (вроде openssl, которая требуется куче пакетов) требует вызова cc. Я решил эту проблему созданием симлинки:

cd /usr/bin
sudo ln -s arm-linux-gnueabihf-gcc arm-linux-gnueabihf-cc

После всех этих плясок я упёрся в такую ошибку:

$ cd ~/git/scripts
$ cargo build --release --target armv7-unknown-linux-gnueabihf
   Compiling bitflags v0.5.0
   Compiling bitflags v0.4.0
   Compiling encoding_index_tests v0.1.4
   Compiling unicode-normalization v0.1.2
   Compiling num-traits v0.1.32
   ...

Build failed, waiting for other jobs to finish...
error: failed to run custom build command for `rust-crypto v0.2.35`
Process didn't exit successfully: `/home/kstep/git/scripts/target/debug/build/rust-crypto-ee392cda555c7573/build-script-build` (exit code: 101)
--- stdout
TARGET = Some("armv7-unknown-linux-gnueabihf")
OPT_LEVEL = Some("0")
PROFILE = Some("debug")
TARGET = Some("armv7-unknown-linux-gnueabihf")
debug=true opt-level=0
TARGET = Some("armv7-unknown-linux-gnueabihf")
HOST = Some("x86_64-unknown-linux-gnu")
CFLAGS_armv7-unknown-linux-gnueabihf = None
CFLAGS_armv7_unknown_linux_gnueabihf = None
TARGET_CFLAGS = None
CFLAGS = None
running: "cc" "-O0" "-ffunction-sections" "-fdata-sections" "-g" "-fPIC" "-march=armv7-a" "-o" "/home/kstep/git/scripts/target/armv7-unknown-linux-gnueabihf/de
bug/build/rust-crypto-ee392cda555c7573/out/src/util_helpers.o" "-c" "src/util_helpers.c"
ExitStatus(ExitStatus(256))


command did not execute successfully, got: exit code: 1



--- stderr
src/util_helpers.c:1:0: error: bad value (armv7-a) for -march= switch
 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or

thread '<main>' panicked at 'explicit panic', /home/kstep/.cargo/registry/src/github.com-88ac128001ac3a9a/gcc-0.3.27/src/lib.rs:834
note: Run with `RUST_BACKTRACE=1` for a backtrace.

Эта сволочь пытается вызвать не тот cc. Что ж, пришлось подсказать:

$ CC=/usr/bin/arm-linux-gnueabihf-cc cargo build --release --target armv7-unknown-linux-gnueabihf
   Compiling xdg-basedir v1.0.0
   Compiling bitflags v0.3.3
   Compiling rust-crypto v0.2.35
   Compiling syntex_syntax v0.31.0
   ...
   Compiling scripts v0.0.1 (file:///home/kstep/git/scripts)

Ура! It's alive!

После этого «скрипты» были скопированы из target/armv7-unknown-linux-gnueabihf/release на мою новенькую малинку и заработали с ходу.

Занавес.