Кросс компиляция пакета для роутера на примере Qbittorrent

в 1:45, , рубрики: open source, OpenWrt, qbittorrent, Компиляторы, кросскомпиляция, Разработка под Linux
Кросс компиляция пакета для роутера на примере Qbittorrent - 1

Добрый день друзья. Как-то мне захотелось установить Qbittorrent на мой роутер который оснащен OpenWRT. Конечно создатели OpenWRT уже предусмотрели возможность сборки кастомных пакетов об этом можно почитать вот тут: https://habr.com/ru/company/ruvds/blog/530984/ . Но данный способ очень долгий, приходится скачивать исходники OpenWRT, компилировать тулчайн и прочее. И я подумал а почему-бы просто не скачать тулчайн и собрать проект обычным образом. Под катом мой опыт.

Тулчайны что это такое

Итак для людей которые недавно познакомились с Linux (как впрочем и я) поясняю тулчайн это набор пакетов необходимый для сборки приложения. В него входят компилятор, линкер и т. д, программой которая вызывает всю цепочку пакетов называется gcc. Для Linux существует множество тулчайнов которые позволяют собирать программы как под другие операционные системы (Windows и т. д) так и под другие платформы (Arm и т. д). Например тулчайн для Windows называется MinGW. При помощи него можно компилировать программы для Windows прямо из под Linux звучит как магия.

Подготовка

Что-же нам нужно? Ну во первых нам нужен Linux все опыты проводились в Linux Mint. На него нужно установит следующие пакеты:

sudo apt update
sudo apt install build-essential curl pkg-config automake libtool 
git perl python3 python3-dev python3-numpy 
unzip cmake ninja

Также нам нужен тулчайн. Какие бывают тулчайны? Ну во первых они отличаются архитектурой под которую они собирают пакеты. Также они могут иметь разные стандартные библиотеки языка C. Наиболее распространённая библиотека это glibc, но нам она не подойдет, поскольку OpenWRT использует библиотеку musl. Поэтому заходим по ссылки https://musl.cc/#binaries и качаем нужный тулчайн. Поскольку мой роутер использует процессор с архитектурой aarch64, то я выберу aarch64-linux-musl-cross и скачаю его. Распаковываем его в папку путь к которой далее я буду называть crosshost_dir для краткости.

Также нам необходимы исходники не только Qbittorrent но и исходники всех библиотек которые используются в Qbittorrent.

  1. zlib https://github.com/madler/zlib

  2. openssl https://github.com/openssl/openssl

  3. boost https://boostorg.jfrog.io/ui/native/main/release/1.77.0/source

  4. libtorrent https://github.com/arvidn/libtorrent

  5. qt-everywhere https://download.qt.io/archive/qt/5.15/5.15.2/single/

  6. qbittorrent https://github.com/qbittorrent/qBittorrent

Также нужно создать папку в которой мы будем работать и распаковать в неё все эти архивы. Эту папку я далее буду называть Install_dir. В ней нужно создать папку Build в которую будут складываться результаты наших трудов.

Теория

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

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

К сожалению если мы применим динамическое связывание наша программа не запустится. Система будет жаловаться на неопределённые символы. Поэтому мы применим статическое. Одним из плюсов данного подхода будет то, что у нас будет самая актуальная версия библиотек. А это очень важно например в случае с Libtorrent эта библиотека очень быстро обновляется и сильно влияет на работу Qbittorrent. Но отрицательной стороной данного подхода является сильно разросшийся размер программы. Например у меня получился Qbittorrent размером 22 МБ . Кажется это немного, но нужно помнить что ещё недавно у роутеров было 4 МБ флэш памяти и 4 МБ оперативной памяти.

Сборка любого проекта состоит из 3-х этапов

  1. Конфигурирование

  2. Сборка

  3. Инсталляция пакета. То есть перенос его в нужную директорию.

В Linux существует две системы сборки проектов это Autotools и Сmake. Autotools это устаревшая система но некоторые проекты до сих пор используют её. Поэтому мы будем использовать и ту и другую.

Сборка

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

PATH=crosshost_dir/bin:$PATH
PATH=Install_dir/Build/bin:$PATH

CHOST=aarch64-linux-musl
CC=aarch64-linux-musl-gcc
AR=aarch64-linux-musl-ar
CXX=aarch64-linux-musl-g++
PKG_CONFIG_PATH=Install_dir/Build/lib/pkgconfig
LD_LIBRARY_PATH=-LInstall_dir/Buildv/lib

BOOST_ROOT="Install_dir/Build/boost"
BOOST_INCLUDEDIR="Install_dir/Build/boost"
BOOST_BUILD_PATH="Install_dir/Build/boost"

aarch64-linux-musl надо заменить на тот тулчайн который вы скачали.

Zlib

./configure --prefix=Install_dir/Build --static 
make -j8 CC=aarch64-linux-musl-gcc AR=aarch64-linux-musl-ar 
CXX=aarch64-linux-musl-g++ 
CXXFLAGS="-std=c++17 -static -w -s -IInstall_dir/Build/include" 
CPPFLAGS="-static -w -s -IInstall_dir/Build/include" 
LDFLAGS="-static -Wl,--no-as-needed -LInstall_dir/Build/lib -lpthread -pthread"
make install

После -j нужно поставить количество ядер вашего процессора у меня их 8. Zlib упорно не хотел воспринимать переменные среды поэтому пришлось передать их вместе с командой make.

OpenSSl

./Configure "linux-aarch64" --prefix=Install_dir/Build 
--openssldir="/etc/ssl" threads no-shared no-dso no-comp
make -j8 CC=aarch64-linux-musl-gcc AR=aarch64-linux-musl-ar 
CXX=aarch64-linux-musl-g++ 
CXXFLAGS="-std=c++17 -static -w -s -IInstall_dir/Build/include" 
CPPFLAGS="-static -w -s -IInstall_dir/Build/include" 
LDFLAGS="-static -Wl,--no-as-needed -LInstall_dir/Build/lib -lpthread -pthread"
make install_sw

Тут все похоже на прошлый.

Boost

Boost устанавливать не надо. Нужно просто переместить его в папку Install_dir/Build. И переименовать его папку просто в boost. А проекты которые от него зависят сами возьмут из этой папки что им надо.

Libtorrent

mkdir -p Install_dir/Build/graphs/libtorrent-rasterbar
patch -p1 < patch-libtorrent
cmake -Wno-dev -Wno-deprecated 
--graphviz=Install_dir/Build/graphs/libtorrent-rasterbar/dep-graph.dot 
-G Ninja -B build -DCMAKE_CXX_COMPILER=aarch64-linux-musl-g++ 
-DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STANDARD=17 
-DCMAKE_PREFIX_PATH="Install_dir/Build;Install_dir/Build/boost" 
-DBoost_NO_BOOST_CMAKE=TRUE 
-DCMAKE_CXX_FLAGS="-std=c++17 -static -w -s -IInstall_dir/Build/include" 
-DBUILD_SHARED_LIBS=OFF -DCMAKE_INSTALL_PREFIX="Install_dir/Build"
cmake --build build
cmake --install build

Для того чтобы собрать Libtorrent нужно применить патч . Здесь уже используется cmake.

Qt

Надо отметить что Qbittorrent до сих пор не поддерживает Qt 6-й версии поэтому нужно брать пятую. Перед сборкой нужно зайти в файл qt-everywhere_dir/qtbase/mkspecs/linux-aarch64-gnu-g++/qmake.conf и заменить aarch64-linux-gnu на aarch64-linux-musl или на вашу архитектуру если у вас другой тулчайн.

./configure -xplatform "linux-aarch64-gnu-g++" -prefix "Install_dir/Build" 
-no-icu -no-iconv  -opensource -confirm-license -release  -static -c++std "c++17" 
-qt-pcre -no-feature-glib -no-feature-opengl -no-feature-dbus -no-feature-gui 
-no-feature-widgets -no-feature-testlib -no-compile-examples -nomake examples 
-nomake tests -no-opengl -skip 3d -skip activeqt -skip androidextras 
-skip datavis3d -skip doc -skip macextras -skip quick3d -skip quickcontrols 
-skip quicktimeline -skip translations -skip wayland -skip webengine 
-skip webglplugin -skip winextras -skip x11extras  -I"Install_dir/Build/include" 
-L"Install_dir/Build/lib" 
QMAKE_LFLAGS="-static -Wl,--no-as-needed -LInstall_dir/Build/lib -lpthread -pthread"
make -j8
make install

Qbittorrent

mkdir -p Install_dir/Build/graphs/qBittorrent-release-4.4.0beta3
cmake -Wno-dev -Wno-deprecated 
--graphviz="Install_dir/Build/graphs/qBittorrent-release-4.4.0beta3/dep-graph.dot" 
-G Ninja -B build -DCMAKE_CXX_COMPILER="aarch64-linux-musl-g++" 
-DCMAKE_BUILD_TYPE="release" -DCMAKE_CXX_STANDARD="17" 
-DCMAKE_PREFIX_PATH="Install_dir/Build;Install_dir/Build/boost" 
-DBoost_NO_BOOST_CMAKE=TRUE 
-DCMAKE_CXX_FLAGS="-std=c++17 -static -w -s -I"Install_dir/Build/include"" 
-DSTACKTRACE=OFF -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DGUI=OFF 
-DCMAKE_INSTALL_PREFIX="Install_dir/Build"
cmake --build build
cmake --install build

Настройка и запуск Qbittorrent

Первым делом нужно переместить файл qbittorrent-nox в директорию usrbin вашего роутера. Теперь можно попробовать его запустить с опцией -d чтобы он запустился в режиме демона, иначе он выключится как только вы закроете окно putty. Но во первых делать это каждый раз неудобно да и qbittorrent запускается с правами root а это небезопасно. Поэтому сначала добавляем пользователя qbittorrent:

echo qbittorrent:x:227:227:qbittorrent:/home/qbittorrent:/bin/false >> /etc/passwd
echo qbittorrent:x:227:qbittorrent >> /etc/group
echo qbittorrent:x:0:0:99999:7::: >> /etc/shadow

После этого создаете файл /etc/init.d/qbittorrent

#! /bin/sh /etc/rc.common
USE_PROCD=1

START=98
STOP=01

DAEMON="/usr/bin/qbittorrent-nox"
USER="qbittorrent"
GROUP="qbittorrent"
home_dir="/home/qbittorrent"

start_service() {

	[ -d "$home_dir" ] || {
		mkdir -p "$home_dir"
		chmod 0755 "$home_dir"
		chown "$USER:$GROUP" "$home_dir"
	}

	procd_open_instance
	procd_set_param command "$DAEMON"
	procd_set_param user $USER
	procd_set_param group $GROUP
	procd_set_param env HOME="$home_dir"
	procd_close_instance
}

И разрешаете выполнение:

chmod 755 /etc/init.d/qbittorrent

Теперь qbittorrentom можно управлять как и другими демонами из веб интерфейса.

Где можно взять Qbittorrent если не хочется компилировать?

Конечно-же все это я взял не с потолка. На github я нашел репозитарий https://github.com/userdocs/qbittorrent-nox-static там есть скрипт который все вышесказанное сделает за вас. Но кроме того в разделе релизов уже лежат скомпилированные Qbittorrent'ы нужно только выбрать подходящую архитектуру процессора.

Автор: Дмитрий

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js