Недавно у меня перестал работать вайфай-рутер и после некоторых раздумий я заказал Asus RT-N16. Хотелось наконец–то познакомиться с альтернативными прошивками. Характеристики этого рутера уже описывались на Хабре. Итак, DD-WRT установлена (v2.24), самба заведена, в первый юсб порт воткнута системная флешка, а во второй — внешний жесткий диск. А дальше я заинтересовался: а смогу ли я запустить свои программы на этом рутере? Я не нашел в сети руководства по сборке программ под рутер и надеюсь этой статьей восполнить пробел. Приведу пошаговое руководство с описанием небольших проблем, встреченных на пути.
В качестве подопытной программы мне хотелось запустить Easysync, о которой я недавно писал. Повторюсь, что это открытая программа для синхронизации файлов в стиле дропбокса. Программа написана с использованием Qt 4, а в качестве движка синхронизации используется Unison. Так что, эта статья описывает как откомпилировать Qt, Unison, Easysync для архитектуры MIPS и рассказывает о запуске Easysync на вашем домашнем рутере.
В рутерах используются непревычные обычному пользователю процессоры. Домашние пользователи привыкли к архитектуре x86, процессорам Intel и AMD. В Asus RT-N16 используется процессор Broadcom BCM4718 c MIPS архитектурой. Ресурсов на самом рутере может не хватить для сборки программы и поэтому обычно программы компилируют на большом брате (например, привычный десктопный компьютер), но под нужную архитектуру. Этот процесс называется кросс–компиляцией.
Все, теперь у нас на домашнем рутере есть синхронизирующий сервер. Если вы можете подключаться к рутеру из вне, то и синхронизация будет работать из любого места.
В качестве подопытной программы мне хотелось запустить Easysync, о которой я недавно писал. Повторюсь, что это открытая программа для синхронизации файлов в стиле дропбокса. Программа написана с использованием Qt 4, а в качестве движка синхронизации используется Unison. Так что, эта статья описывает как откомпилировать Qt, Unison, Easysync для архитектуры MIPS и рассказывает о запуске Easysync на вашем домашнем рутере.
Хозяйке на заметку.
В рутерах используются непревычные обычному пользователю процессоры. Домашние пользователи привыкли к архитектуре x86, процессорам Intel и AMD. В Asus RT-N16 используется процессор Broadcom BCM4718 c MIPS архитектурой. Ресурсов на самом рутере может не хватить для сборки программы и поэтому обычно программы компилируют на большом брате (например, привычный десктопный компьютер), но под нужную архитектуру. Этот процесс называется кросс–компиляцией.
Инструменты.
- Нам понадобится рабочий компьютер с линуксом на борту. Я использовал Ubuntu;
- Компиляторы (gcc, g++);
- Стандартные библиотеки Си, Си++;
- Утилиты в виде GNU make, TAR, GZIP, GIT и так далее ;). В случае с Убунту, большинство уже установлено.
Шаги
- Первое, что нам нужно, это понять как вообще собираются программы для DD-WRT. Страница в их вики вводит в курс дела. Особенно интересен раздел Instructions. Там приводится ссылка на toolchain (далее – тулчейн), который используется для сборки DD-WRT из исходников. Тулчейн в данном случае это уже откомпилированная под нужную архитектуру библиотека Uclibc, а так же компилятор. Итак, тулчейн качается с сайта DD-WRT. Там не написанно, но собрано все под архитектурой x86_64. Поэтому если вы, набрав в терминале команду uname -m, не увидите что–нибудь со значением 64 (x86_64 или amd64), то вам придется установить новую версию линукса. Альтернативный метод — собрать тулчейн самому, но я предпочел поставить нужную мне систему. Дождавшись завершения скачивания (а это на сегодняшний день 716 Мб), переходим к следующему пункту.
- Открываем архив, в нем папки с тулчейнами под разные архитектуры. Нам нужен toolchain-mipsel_gcc4.1.2. Я распаковал эту папку в /home/fralik/. Почему именно toolchain-mipsel_gcc4.1.2? Mipsel, потому что я видел, что на рутере optware ставится именно из mipsel пакетов, а значит используется порядок байт от младшего к старшему (little-endian). Остальные папки, содержащие mipsel в названии, по–моему используются для сборки компонентов ядра DD-WRT.
- Добавляем тулчейн к пути:
- PATH=$PATH:~/toolchain-mipsel_gcc4.1.2/bin/
- cd ~
- mipsel-linux-gcc --version
Вы должны увидеть информацию о версии GCC. - Для проверки того, что все работает, можно использовать две helloworld программы. helloworld-c.c:
- #include <stdlib.h>
- #include <stdio.h>
- int main() {
- printf("Hello world!\n");
- return 0;
- }
Собираем и проверяем, используя команду file:
mipsel-linux-gcc helloworld-c.c -o helloworld-c
file helloworld-c
Должны увидеть:helloworld-c: ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
Можно запустить helloworld-c на рутере и проверить работоспособность еще и в реальности. Теперь helloworld-cpp.cpp:
#define NEED_PRINTF 1
#include <iostream>
int main() {
std::cout << "Hellow world!" << std::endl;
return 0;
}
В терминале:
mipsel-linux-g++ helloworld-cpp.cpp -o helloworld-cpp
Обратите внимание на первую строчку! Без нее программа не соберется и будет выдана ошибка:
/home/fralik/toolchain-mipsel_gcc4.1.2/bin/../lib/gcc/mipsel-linux-uclibc/4.1.2/../../../../include/c++/4.1.2/cstdio:126: error: '::printf' has not been declared
Собираем, проверяем, что все работает на рутере. - Настало время собрать Qt. Качаем Qt libraries for embedded Linux. Я распаковал архив так же в домашнюю директорию.
- Идем в терминале в папку с Qt. Нужно обратить внимание на папку mkspecs/qws. В ней хранятся Make файлы под разные архитектуры. Например, mkspecs/qws/linux-mips-g++/qmake.conf.
Копируем папку linux-mips-g++ в linux-mipsel-g++:
cp -R mkspecs/qws/linux-mips-g++/ mkspecs/qws/linux-mipsel-g++
- Редактируем файл mkspecs/qws/linux-mipsesl-g++/qmake.conf, чтобы он использовал команды mipsel-linux-* вместо mips-linux-*. В качестве флагов я использую
-mel -march=mips32r2
- Далее приступаем к конфигурации Qt. Но для начала устанавливаем libxext-dev, иначе получим ошибку:
Basic XLib functionality test failed!
sudo apt-get install libxext-dev
./configure -no-cups -release -shared -no-qt3support -no-phonon -no-audio-backend -no-javascript-jit -no-webkit -qt-sql-lite -no-script -no-scripttools -opensource -no-gui -no-nis -no-opengl -nomake examples -nomake demos
Должны увидеть:
Qt is now configured for building. Just run 'make'. Once everything is built, you must run 'make install'. Qt will be installed into /usr/local/Trolltech/Qt-4.7.2
Запускаем конфигуратор еще раз:
./configure -no-cups -release -shared -no-qt3support -no-phonon -no-audio-backend -no-javascript-jit -no-webkit -qt-sql-sqlite -no-script -no-scripttools -platform linux-g++-64 -xplatform qws/linux-mipsel-g++ -opensource -no-gui -no-nis -embedded mips -little-endian -no-opengl -nomake examples -nomake demos
В первый раз мы сконфигурировали Qt для текущей архитектуры, во второй — для MIPS. Во второй команде аргумент xplatform как раз указывает на ту папку, которую мы создали в шаге 6. Я убрал поддержку ненужных мне вещей: no-qt3support, no-phonon, no-audio-backend, -nomake example и т.д.
В результате видим такое сообщение:
Qt is now configured for building. Just run 'make'. Once everything is built, you must run 'make install'. Qt will be installed into /usr/local/Trolltech/QtEmbedded-4.7.2-mips
- Запускаем make. Можно пойти перекурить или заварить чаю. =)
На этом шаге у меня возникает очередная проблема:
.obj/release-shared-emb-mips/qrect.o: In function `QRectF::toAlignedRect() const': qrect.cpp:(.text+0x1468): undefined reference to `ceilf' qrect.cpp:(.text+0x1488): undefined reference to `ceilf'
Дело в том, что в библиотеке uclibc не включена по умолчанию функция ceilf. Можно, конечно, пересобрать библиотеку и добавить туда эту функцию, но мы все–таки используем тулчейн от DD-WRT и значит на рутере тоже стоит библиотека без функции ceilf. На этом шаге я долго танцевал с бубном, пытаясь превратить вызов ceilf в ceil. Но Qt была непоколебима. Пришлось браться за скальпель, особенно учитывая то, что класс QRect мне не понадобится. Открываем файл ~/qt-everywhere-opensource-src-4.7.2/src/corelib/tools/qrect.cpp, находим строчку 2379. Меняем на:
int xmax = int( (float)((int)xp + w));
то есть заменяем вызовqCeil(xp+y)
на(float)((int)xp + y)
Аналогичную операцию проводим над строчкой 2381, а также в строчке 640 файла ~/qt-everywhere-opensource-src-4.7.2/src/corelib/tools/qtimeline.cpp
Снова вызываем make, на этот раз процесс должен завершиться успешно. - Выполняем
sudo make install
Проверяем, что теперь у нас есть библиотека Qt под MIPS (несмотря на заверения Qt, что установка произойдет в папку /usr/local/Trolltech/QtEmbedded-4.7.2-mips, у меня все установилось в /usr/local/Trolltech/Qt-4.7.2):
file /usr/local/Trolltech/Qt-4.7.2/lib/libQtCore.so.4.7.2
/usr/local/Trolltech/Qt-4.7.2/lib/libQtCore.so.4.7.2: ELF 32-bit LSB shared object, MIPS, MIPS32 version 1 (SYSV), dynamically linked (uses shared libs), not stripped
- Переходим к сборке Easysync.
# Заходим в какую–нибудь директорию, например,
cd ~
git clone git://github.com/fralik/Easysync.git
cd Easysync/server
/usr/local/Trolltech/Qt-4.7.2/bin/qmake easysync-server.pro
make
# проверяем:
file build/easysync-server - Теперь нам нужен Unison. Не смотря на его полезность, его нет в optware. Будем собирать его прямо на рутере. Заходим на рутер по ssh или telnet.
ipkg-opt install buildroot ocaml
mkdir /mnt/unison
cd /mnt/unison
wget http://www.seas.upenn.edu/~bcpierce/unison//download/releases/stable/unison-2.40.61.tar.gz
tar xvfz unison-2.40.61.tar.gz
ocaml mkProjectInfo.ml > Makefile.ProjectInfo
# Прежде чем собирать унисон, нужно сделать символьную ссылку с libncurses на libcurses
ln -s /opt/lib/libncurses.so.5.7 /opt/lib/libcurses.so.5.7
ln -s /opt/lib/libcurses.so.5.7 /opt/lib/libcurses.so.5
ln -s /opt/lib/libcurses.so.5 /opt/lib/libcurses.so
make NATIVE=false UISTYLE=text
./unison -version
cp ./unison /opt/bin/unison
Здесь ключевым моментом является ocaml mkProjectInfo.ml > Makefile.ProjectInfo. Без этого не соберется. - Теперь нам нужно запустить все то, что мы собрали. Допустим адрес рутера 192.168.2.1 и нам доступна директория /mnt для записи
scp /usr/local/Trolltech/Qt-4.7.2/lib/libQtCore.so.4.7.2 root@192.168.2.1:/opt/lib
scp /usr/local/Trolltech/Qt-4.7.2/lib/libQtNetwork.so.4.7.2 root@192.168.2.1:/opt/lib
scp /usr/local/Trolltech/Qt-4.7.2/lib/libQtSql.so.4.7.2 root@192.168.2.1:/opt/lib/
cd <Easysync/server>
# Запаковываем Easysync-server в один файл, чтобы было проще передать на рутер:
./build_package_dd-wrt.sh
scp dd-wrt_bundle.tar.gz root@192.168.2.1:/mnt - Заходим на рутер, в папку /mnt, распаковываем easysync-server-mipsel32.tar.gz
tar xvfz easysync-server_mipsel.tar.gz
ln -s /opt/lib/libQtCore.so.4.7.2 /opt/lib/libQtCore.so.4.7
ln -s /opt/lib/libQtCore.so.4.7 /opt/lib/libQtCore.so.4
ln -s /opt/lib/libQtCore.so.4 /opt/lib/libQtCore.so
ln -s /opt/lib/libQtSql.so.4.7.2 /opt/lib/libQtSql.so.4.7
ln -s /opt/lib/libQtSql.so.4.7 /opt/lib/libQtSql.so.4
ln -s /opt/lib/libQtSql.so.4 /opt/lib/libQtSql.so
ln -s /opt/lib/libQtNetwork.so.4.7.2 /opt/lib/libQtNetwork.so.4.7
ln -s /opt/lib/libQtNetwork.so.4.7 /opt/lib/libQtNetwork.so.4
ln -s /opt/lib/libQtNetwork.so.4 /opt/lib/libQtNetwork.so
- Далее есть смысл проверить работу унисона без Easysync (можно обратиться как к документации самого унисона, так и к install-файлам Easysync'а). После настройки унисона, возвращаемся на рутер, редактируем файл config.ini.sample и запускаем:
./setup_dd-wrt.sh
Все, теперь у нас на домашнем рутере есть синхронизирующий сервер. Если вы можете подключаться к рутеру из вне, то и синхронизация будет работать из любого места.
Краткая выжимка
- Собирать программы для DD-WRT можно, используя тулчейн с их сайта. Для C++ программ необходимо использовать #define NEED_PRINTF.
- Несмотря на отсутствие унисона в сборке optware, его можно собрать на рутере. Можно, в принципе, сделать и кросс–компиляцию, но я не разбирался с этим.
- Qt почти что без проблем собирается под MIPS: +1 к кроссплатформенности ваших программ.
- Easysync теперь и на домашних рутерах! Стоит отметить, что после перезагрузки сервис не будет запущен автоматически. Скорее всего, он даже не будет помечен как установленный (потому что флаг установки хранится в /tmp). Его можно снова установить командой /opt/bin/easysync-server -i или же запустить без установки командой /opt/etc/init.d/easysync-server start
Для тех, кто заинтересуется Easysync'ом, но не захочет собирать его из исходников, доступна уже скомпилированная версия.
Обновление, 30.05.2016
Пользователь Nabytovych подсказывает, что ��екоторые ссылки устарели со временем. Обновил ссылки на тулчейн и Qt.