Заметки о кросс–компиляции приложений под DD-WRT

    Недавно у меня перестал работать вайфай-рутер и после некоторых раздумий я заказал 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 архитектурой. Ресурсов на самом рутере может не хватить для сборки программы и поэтому обычно программы компилируют на большом брате (например, привычный десктопный компьютер), но под нужную архитектуру. Этот процесс называется кросс–компиляцией.

    Инструменты.


    • Нам понадобится рабочий компьютер с линуксом на борту. Я использовал Ubuntu;
    • Компиляторы (gcc, g++);
    • Стандартные библиотеки Си, Си++;
    • Утилиты в виде GNU make, TAR, GZIP, GIT и так далее ;). В случае с Убунту, большинство уже установлено.

    Шаги


    1. Первое, что нам нужно, это понять как вообще собираются программы для DD-WRT. Страница в их вики вводит в курс дела. Особенно интересен раздел Instructions. Там приводится ссылка на toolchain (далее – тулчейн), который используется для сборки DD-WRT из исходников. Тулчейн в данном случае это уже откомпилированная под нужную архитектуру библиотека Uclibc, а так же компилятор. Итак, тулчейн качается с сайта DD-WRT. Там не написанно, но собрано все под архитектурой x86_64. Поэтому если вы, набрав в терминале команду uname -m, не увидите что–нибудь со значением 64 (x86_64 или amd64), то вам придется установить новую версию линукса. Альтернативный метод — собрать тулчейн самому, но я предпочел поставить нужную мне систему. Дождавшись завершения скачивания (а это на сегодняшний день 716 Мб), переходим к следующему пункту.
    2. Открываем архив, в нем папки с тулчейнами под разные архитектуры. Нам нужен toolchain-mipsel_gcc4.1.2. Я распаковал эту папку в /home/fralik/. Почему именно toolchain-mipsel_gcc4.1.2? Mipsel, потому что я видел, что на рутере optware ставится именно из mipsel пакетов, а значит используется порядок байт от младшего к старшему (little-endian). Остальные папки, содержащие mipsel в названии, по–моему используются для сборки компонентов ядра DD-WRT.
    3. Добавляем тулчейн к пути:
      1. PATH=$PATH:~/toolchain-mipsel_gcc4.1.2/bin/
      2. cd ~
      3. mipsel-linux-gcc --version

      Вы должны увидеть информацию о версии GCC.
    4. Для проверки того, что все работает, можно использовать две helloworld программы. helloworld-c.c:
      1. #include <stdlib.h>
      2. #include <stdio.h>
      3.  
      4. int main() {
      5.     printf("Hello world!\n");
      6.     return 0;
      7. }

      Собираем и проверяем, используя команду 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

      Собираем, проверяем, что все работает на рутере.
    5. Настало время собрать Qt. Качаем Qt libraries for embedded Linux. Я распаковал архив так же в домашнюю директорию.
    6. Идем в терминале в папку с 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++
    7. Редактируем файл mkspecs/qws/linux-mipsesl-g++/qmake.conf, чтобы он использовал команды mipsel-linux-* вместо mips-linux-*. В качестве флагов я использую
      -mel -march=mips32r2
    8. Далее приступаем к конфигурации 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
      
    9. Запускаем 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, на этот раз процесс должен завершиться успешно.
    10. Выполняем
      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
    11. Переходим к сборке 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
    12. Теперь нам нужен 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. Без этого не соберется.
    13. Теперь нам нужно запустить все то, что мы собрали. Допустим адрес рутера 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
    14. Заходим на рутер, в папку /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
       
    15. Далее есть смысл проверить работу унисона без Easysync (можно обратиться как к документации самого унисона, так и к install-файлам Easysync'а). После настройки унисона, возвращаемся на рутер, редактируем файл config.ini.sample и запускаем:
      ./setup_dd-wrt.sh


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

    Краткая выжимка


    1. Собирать программы для DD-WRT можно, используя тулчейн с их сайта. Для C++ программ необходимо использовать #define NEED_PRINTF.
    2. Несмотря на отсутствие унисона в сборке optware, его можно собрать на рутере. Можно, в принципе, сделать и кросс–компиляцию, но я не разбирался с этим.
    3. Qt почти что без проблем собирается под MIPS: +1 к кроссплатформенности ваших программ.
    4. Easysync теперь и на домашних рутерах! Стоит отметить, что после перезагрузки сервис не будет запущен автоматически. Скорее всего, он даже не будет помечен как установленный (потому что флаг установки хранится в /tmp). Его можно снова установить командой /opt/bin/easysync-server -i или же запустить без установки командой /opt/etc/init.d/easysync-server start
      Для тех, кто заинтересуется Easysync'ом, но не захочет собирать его из исходников, доступна уже скомпилированная версия.

      Обновление, 30.05.2016


      Пользователь Nabytovych подсказывает, что некоторые ссылки устарели со временем. Обновил ссылки на тулчейн и Qt.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 42

      –3
      — Слушайте, Шура, если уж вы окончательно перешли на французский язык, то называйте меня не месье, а ситуайен, что значит — гражданин.

      — рутер
      Если не маршрутизатор, то, может быть, все-таки раутер?
        +14
        Роутер.

        Традиционно «ou» транслитерируется как «оу», а не как «ау».

        И уж тем более не как «у» — от такой транслитерации у dictionary.com глаза на лоб лезут.
          +1
          Дело не в транслитерации, а в том что в инглише route может произноситься и как «рут» и как «раут».
          Router тоже можно произносить как «рутер» особенно если подразумевается не девайс, а профессия.
          Не вижу ничего плохого в использовании именно «рутер» в русском (к тому же и звучит оно не так коряво).
            0
            Я сделал просто — зашел на dictionary.com, посмотрел слово router, послушал произношение и не услышал там «рутера». Что-то среднее между «раутер» и «роутер», второе — уже устоявшееся в русском языке.
              0
              Ну вы можете зайти на dictionary.reference.com и всё же его услышать.
                0
                Я о нем и говорю — никакого «рутера» там нет.
                  0
                  а если внимательней поискать? :)
                    0
                    А еще можно зайти на translate.google.com и послушать там. Я тоже предпочитаю произносить это слово как «рутер».
                    0
                    Смотрите второй вариант на dictionary.reference.com и вот тут я попытался подробно ответить.
            +2
            рОутер.
            Хотя «рутер» это жаргонизм в среде dd-wrt'шников и любителей кастомных прошивок Asus
              0
              В словарях слово route имеет транскрипцию [ru:t], так что всё же «рутер».
                0
                Оскфордский словарь выдает транскрипцию /ˈraʊtə/, merriam-webster \ˈrau̇-tər\, MSN
                rout·er [ rówtər ]

                Судя по всему, у англичан раутер, у американцев роутер.

                  +1
                  Естественно. Англичане вообще коверкают слова немыслимо
                    +3
                    Но рутера нет ни у тех, ни у других.
                    +2
                    Оксфордский словарь — /ˈruːtə/. Пруф

                    Как произносить те или иные слова — это отличная тема для холивара. В отличии от Русского языка очень во многих странах существуют диалекты. И то, как произносит слово «router» житель Лондона, может отличаться от произношения жителя Эдинбурга. Оба они произносят это слово правильно. К тому же, как заметили ниже, Лондон вообще Ландэн. В эту степь можно добавить, что третий рейх на самом деле третий райх, если произносить так, как произносят немцы.

                    С точки зрения лингвистики, важно звучание слова, а не его написание. То, что написание слов, часто не совпадает с их звучанием, является свидетельством того, как это слово произносилось раньше. Изменение в написании «не поспевает» за изменением в звучании.

                    Существует два принятых способа заимствования слов из другого языка. Первый — транслитерация, второй — транскрипция. В случае транслитерации берется иностранное слово, например, Newton и тупо подставляются русские буквы вместо их предполагаемых аналогов в языке источника. Таким образом, Newton превращается в Невтон на русском. Так раньше и говорили. Этот способ был общеупотребительным. Кстати, это так же объясняет почему Лондон, а не Ландэн.

                    Позднее, начали использовать метод транскрипции, когда слово заимствуется по звучанию, превращая Newton в Ньютона. То есть основная задача транскрипции — передать звучание иностранного слова.

                    Теперь вернемся к router. Как правильно произносить это слово в русском? Тут уж, в принципе, каждый может выбирать вариант по вкусу. Британцы (Лондон), не смотря на то, что может стоять в словаре, чаще произносят рутер, американцы — раутер.
                    +2
                    В словарях слово Лондон имеет транскрипцию ['lʌndən], так что всё же «Ландэн».

                    Мне продолжать?
                  +1
                  С нетерпением жду сборки и запуска своей программы на холодильнике или микроволновки )
                    –1
                    Кстати я был бы очень не против если мой холодильник стал бы для меня домашним сервером.
                      +1
                      Действительно, а что, все при нем — охлаждение отменное, аптайм обеспечивается самый что ни на есть отличный, разве что кофе не готовит
                        0
                        Куча недостатков же
                        — влажность и конденсат
                        — невозможность провести внутрь питание без повреждений
                        — залитый борщом сервер
                          0
                          Система ноу-фрост, а кабели можно через вентиляционное отверстие холодильной камеры )
                          0
                          Не варит кофе? Чтож это пока...
                            +2
                            собственно:
                            image
                          0
                          Интересно, как WiFi ловит в холодильнике? Есть у кого опыт использования?
                        +4
                        Будем собирать его прямо на рутере.
                        Ещё можно вытащить из роутера корневую файлуху и сделать в неё chroot прямо из десктопного линукса. Да-да, из amd64 в mips. Если интересно как, гуглите qemu-user и binfmt. На основе этой технологии работает тот же scratchbox.
                          +3
                          Бешенно плюсую, и добавляю в избранное. Хотя сия статья про роутеры, но она может быть полезна при любой кросскомпиляции!
                            0
                            Я вот после этой статьи снова хочу взять и скомпилировать драйвера для wifi адаптера под телевизор :)
                              0
                              Что за телевизор с линуксом?
                                +1
                                Сегодня уместнее вопрос — что за телевизор без линукса.
                                www.samsung.com/global/opensource/
                                samygo.sourceforge.net/
                                  0
                                  Надо пойти, перечитать инструкцию к посудомойке — вдруг там тоже линукс…
                            0
                            Ведь на роутерах дебиан заводили без проблем, но поковыряться с DD-WRT конечно тоже не вредно.
                              0
                              qt на роутере, ставить новую систему вместо пересборки — мсье знает толк…
                                0
                                А в чем собственно извращения? Установка новой системы — человеку x86_64 нужна была именно для данной операции, рабочая система у него, вполне вероятно, 32bit. Qt на маршрутизаторе — это ведь не только gui тулкит, там немало разнообразных примочек, удобных в использовании, почему бы их не применить. Так что все вполне логично выглядит.
                                  0
                                  Вам нужно поменять свечи в автомобиле. Вы пришли в магазин, а там только для ролс-ройса свечи. Вы будете двигатель от ролс-ройса ставить в свою машину или все-таки поищете свечи для вашего двигателя в другом месте?
                                    +1
                                    Ну свечи я, конечно, поищу :-) Но в данной ситации немного другой расклад. Поставить еще одну систему — дело 15 минут и практически гарантированно без неожиданных граблей. А вот пересборка тулчейна может вылиться в еще одно приключение и неизвестно сколько времени и сил уйдет на устранение найденных проблем. Так что автор просто выбрал более простой и надежный путь.
                                0
                                А скорость работы PPTP не пугает? Или не используется? в DD-WRT самый тормозной PPTP среди всех кастомов которые смог опробовать.
                                  +2
                                  А что Вы можете сказать об Openwrt?
                                    +1
                                    Мне он нравится куда больше, чем dd-wrt. Во-первых, наглядный конфиг в файлах, во-вторых, веб-интерфейсов много, из них два основных, и настраивается понятней и проще(для меня).
                                      0
                                      Поддерживаю, ток вайфай на dir320 ложиться через неделю. С дд-врт такого не было.
                                        0
                                        На 2.6? На 2.6 он у меня ложился через день. Перешел на 2.4, аптайм 3 месяца — все ок. Но dir320 используется только в качестве проводного свитча и бриджа вайфая с внутренним бриджем. У меня сервер в коробке в качестве полноценного роутера.
                                          0
                                          да, 2.6. Используется точно таким же способом.
                                    0
                                    По идее, этим способом можно собрать ядро с Accel PPTP, тогда скорость pptp будет реактивной.

                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                                  Самое читаемое