Комментарии 7
В студенческую бытность имел коммуникатор asus p525 (217МГц и 32Мб оперативки), на него был способ запустить gentoo.
Вот там брался настольный комп, на нём настраивался кросс компилятор, и мобилка выполняла только этап конфигурации, затем отдавала компиляцию большому брату.
Так же знаю людей кто таким же образом настраивал билд сервер, для не отличающейся архитектуры.
Если честно, то так себе решение. Обычно, когда собираешь под embedded Linux, то тебе нужна специфическая периферия, которую не сможет предоставить ваша виртуалка. Так что только cross-compiling. Правда у меня собрана 5.9, которая распространяется в виде готового дебиан пакета. Более новые версии Qt не собирал
Посмотрите про Cross build environment в гентушной вики. Там всё это уже давно автоматизировано и работает намного быстрее, так как сборка не задействует эмуляцию в виртуальной машине. Хотя я не пробовал собирать так тяжёлые приложения типа Qt, только лёгкие вроде сетевых утилит (на компьютере x86-64 собирались приложения под USB-модем с процессором типа ARM). Наверняка можно нарваться на то, что некоторые ебилды (скрипты сборки для Gentoo) не работают в режиме кросс-компиляции и нужно их править. Но зависимости должны доставляться автоматически, а не вручную, как у автора статьи.
Кросс-тулчейном действительно собирать в разы проще, когда этот кросс-тулчейн есть или когда его вообще возможно собрать. Но иногда у тебя на руках только железка с SD-картой с ядром и rootfs'ом на борту, где, о чудо, иногда ещё есть и компилятор. Без исходников кросс-тулчейн нужной версии получить сложнее, чем собирать код прямо на железке.
Другой вопрос, что когда ты встречаешься с жЫрным софтом, сборка на дохлой ARM-железке оказывается слишком медленной. В таком случае у тебя несколько вариантов:
- собирать таки кросс-тулчейн, подбирая libc и хэдэры ядра в соответствии rootfs'ом железки
- брать rootfs с железки и запускать сборку внутри неё на хостовой системе
Автор выбрал второй путь. Проблема лишь в том, что он воспользовался полной виртуализацией (=эмулировал оборудование, I/O, работу драйверов файловой системы, графику и т.д.) тогда, когда было достаточно преобразовывать ARM-вызовы syscall'ов в x86. Для этого у qemu есть набор инструментов под все популярные архитектуры. Например, можно взять любой статический armv7-бинарь, собранный под линукс (например, busybox) и запустить его через qemu-arm busybox. А можно пойти дальше и заchroot'иться в систему, засунув туда qemu-arm-static (static потому что у него не будет доступа до хостовых библиотек вне chroot), тогда /bin/bash, собранный под ARM, будет запускаться на х86, используя qemu-arm-static и библиотеки из rootfs.
В отличие от полной виртуализации, при chroot в ARM-окружение у тебя есть доступ до всех ядер процессора, до всей доступной RAM, до всего дискового пространства хостовой системы, так ещё и очень сильно сокращается overhead от эмуляции процессора и I/O.
Я попробовал сделать Proof-of-Concept, у меня получились очень неплохие результаты:
pi@lerochka:~/qt-everywhere-src-5.15.0 $ time ./configure -skip qt3d -no-warnings-are-errors -release -recheck-all -prefix /Qt/5.15.0 -opensource -confirm-license -nomake examples -nomake tests -c++std c++17 -I /usr/include/xcb/ -xcb-xlib -xcb -feature-thread -feature-xkbcommon -qt-libpng -qt-libjpeg -qt-zlib -I /usr/include/xcb/ --recheck-all -skip wayland -skip qtwebengine -skip qtwayland
...
real 17m22.799s
user 16m59.336s
sys 0m23.783s
Такой вариант в 5 раз быстрее (17 минут против 91 у автора), чем сборка в полностью виртуализированном окружении. И это на Intel® Pentium® CPU G4560 @ 3.50GHz в 1 потоке.
Я думаю, можно вызвать ./configure так, чтобы он юзал все потоки, будет намного быстрее.
Конечно, это всё ещё не нативная сборка Qt под x86 на x86: там «конфигурация» проходит за 2 минуты на этом же процессоре.
Под спойлером небольшая инструкция о том, как воспроизвести chroot в ARM-окружение (проверялось на Arch Linux, /home/xxx/rootfs замените на какую-нибудь удобную для вас директорию):
downloads.raspberrypi.org/raspios_lite_armhf_latest
2. Вытаскиваем rootfs из образа диска:
sudo su
modprobe loop
losetup -fP --show 2020-05-27-raspios-buster-lite-armhf.img
mount /dev/loop0p2 /mnt
cd /mnt
cp -r * /home/xxx/rootfs
3. Скачиваем на свою систему binfmt-support и qemu-arm-static (для Debian, у арча в AUR'е есть пакет qemu-user-static):
sudo apt-get install qemu-user-static qemu-user-static
4. Копируем qemu-arm-static в rootfs:
cp "$(which qemu-arm-static)" /home/xxx/rootfs/usr/bin
5. Монтируем dev, sys, proc, run, tmp в rootfs (не забудьте потом это всё отмонтировать после работы):
mount --bind /dev /home/xxx/rootfs/dev
mount --bind /sys /home/xxx/rootfs/sys
mount --bind /proc /home/xxx/rootfs/proc
mount -t tmpfs tmp /home/xxx/rootfs/tmp
mount -t tmpfs run /home/xxx/rootfs/run
6. Делаем chroot в систему:
chroot /home/xxx/rootfs/
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
echo "nameserver 8.8.8.8" > /etc/resolv.conf
7. Профит, мы как будто в обычном chroot'е, но только в ARM'овом :)
P.S. Для сборки я брал Qt 5.15 отсюда, поставил все зависимости из статьи, собирал под пользователем pi (нужно вызвать su — pi, чтобы не собирать под root'ом), + я не очень понял почему это так работает, но я поправил ещё строчку в qtbase/configure:
- "$outpath/bin/qmake" "$relpathMangled" -- "$@"
+ "$outpath/bin/qmake" "$relpathMangled/qt.pro" -- "$@"
Я как бы в таком случае много раз собирал Qt как то так (так, сказать, по-быстрому):
1. Берется и «сливается» rootfs из реального у-ва посредством rsync (или иным образом).
2. Берется любой готовый тулчейн (GCC) для ARM примерно той-же версии что и использовался на у-ве (просто ставим из репозитория на хост или качаем отдельно).
3. На хосте запускаем 'qemu-static-arm' (или как оно называется), чрутимся на скачанную rootfs и доустанавливаем 'devel' пакеты в rootfs (те, которые нужны для сборки, если, конечно, у железки есть свой репозиторий). Если репозитория нет — то придется собирать все недостающие пакеты кросс-компилятором и «устанавливать» в rootfs.
4. Собственно, всё, кросс-компилим Qt используя наш тулчейн и «нашу» rootfs.
PS: И да, как уже сказали выше — это самый быстрый и простой способ.
В чате ещё предлагали собрать отдельно кросстулчейн на musl и под Linux 2.6, им же скомпилировать статически-слинкованный Qt, потом собрать приложение и упаковать ресурсы Qt и статически-слинкованное приложение в один пакет. Таким образом, софт вообще не зависит от системного libc и версии ядра и будет работать где угодно.
Сэмулируй сборку приложения ARM на x86 процессоре на примере Qt