2010-11-01

Сборка Qt-приложений под Symbian: Tips&Tricks

Потребовалось мне тут собрать наш проект под Symbian. Как раз появилась дев-версия 4.7.0 и появилась возможность протестировать на n8. Проект не то чтобы очень большой и замудренный, но в итоге сборка его заняла немало времени. В этой статье собраны все грабли, на которые я наступил.



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

Грабли №1. Платформы
При сборке для Symbian можно собирать 4 разных варианта:
  1. winscw - сборка для симулятора
  2. gcce - сборка для устройства свободным компилятором
  3. armv5 - сборка для устройства платным компилятором
  4. armv6 - сборка для устройства платным компилятором
Мне была нужна только gcce и остальные захотелось вырубить (тем более что при дефолтной сборке система всегда ругалась на отсутствие rvct (платного компилятора) при первом запуске make). Делается это просто. Надо всего лишь добавить в .pro файл следующую строку:
SYMBIAN_PLATFORMS -= ARMV5 ARMV6 WINSCW

Грабли №2. QtCreator
На текущий момент QtCreator не умеет две вещи:
  • Правильно собирать SUBDIRS проекты
  • Правильно собирать shared библиотеки
Поподробнее про shared. При сборке под Symbian нам необходимо прогнать make для shared библиотеки два раза:
  1. Собираем библиотеку и ищем символы для экспорта
  2. Собираем библиотеку с экспортированными символами
Между этими двумя операциями необходимо отдельно собрать список этих символов. Итоговая комбинация команд:
make release-gcce && abld freeze && make release-gcce

В итоге всю сборку я перенес в консоль по-проектно (благо подпроектов у меня не много и не все нужны для Symbian).

Грабли №3. Сборка
Да, сама сборка тоже оказалась граблями. Тулчейн сборки не всегда правильно собирает и приходится следить за тем, какие символы нашлись для экспорта (бывает не все находит). Бывает забудет сделать moc для некоторых файлов (и следовательно потом ругается на undefined reference). Но это все лечится пересборкой. Единственное, что я не нашел как победить, это скорость сборки. Собирает тулчейн очень неспешно и наиболее долгие шаги никак не комментируются в консоли, поэтому что сделать для ускорения непонятно. 

Грабли №4. Shared библиотеки
Все shared библиотеки, которые есть в этом проекте валились на сборке c ошибкой вида "contains uninitialized writable data". Решить эту проблему можно добавлением в .pro файл строки:
TARGET.EPOCALLOWDLLDATA = 1

Грабли №5. Static библиотеки
Статические библиотеки этой проблемы лишены, но у них тоже есть свои интересные особенности.
Во-первых, я не нашел как указать линковщику что вот этот вот -lsomeLib это статическая библиотека, в итоге пришлось добавлять в проект строки вида:
MMP_RULES += "STATICLIBRARY libraryname.lib"
которые явно указывают что подключать статическую библиотеку.
Во-вторых, тулчейн по окончанию сборки кладет их в epoc32/release/gcce/urel, а вот ищет для линковки уже в epoc32/release/armv5/urel (это считается дефолтным местом и для armv5 и для gcce платформ). То есть просто после сборки библиотеки надо ее скопировать.
В-третьих, на всех статических библиотеках в этом проекте линковщик при их подключении ругался со словами "incompatible with standard C++". Интернет в качестве решения предлагает добавлять директиву STDCPP в .mmp файл, но она добавляется по умолчанию qmake'ом. Другое решение предлагает перевести их в shared, что я и сделал.

Грабли №6. QtUiTools
В принципе эти грабли вытекают из предыдущих. QtUiTools не собран в стандартной поставке Qt, а когда собираешь его, то линковка опять ругается на несовместимость. Пока временно (благо проект пока что не вышел в public и до этого момента еще долго) перенес его в shared библиотеки, но с этим точно надо будет что-то решать.

Грабли №7. QtConcurrent
Его просто нет. Надеюсь что все же хотя бы run() добавят в итоге.

Грабли №8. QPrinter
Его также нет, как и конкаррента. И тут надежд на добавление еще меньше (его также нет в WinMo и в симуляторе), но посмотрим что будет дальше.

Грабли №9. Не очень свежий gcc
В свое время в gcc был очень интересный баг (http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57). В стандартной поставке Nokia Symbian3 SDK+Open C/C++ plugin он присутствует. Сам баг заключается в том, что парсер неправильно понимает конструкцию вида:
void func(const QHash<QString, QVariant> &params = QHash<QString, QVariant>())
Запятая в дефолтном значении рассматривается как переход к следующему параметру и следовательно все сбивается. Решить можно переписав строку так:
void func(const QHash<QString, QVariant> &params = (QHash<QString, QVariant>()))

Грабли №10. Плагины
В Symbian все библиотеки должны лежать в /sys/bin, а плагины как известно должны быть разложены по папочкам. В качестве решения проблемы в папочках лежат stub-файлы, которые называются также как плагин, а сама библиотека следовательно ищется в /sys/bin. Также необходимо учитывать, что в подпапки /sys/bin ничего класть нельзя (или как минимум это сделать очень сложно, у меня при попытке сделать подобный финт каждый раз установка не могла завершиться с сообщением File Corrupted).

Грабли №11. QSplashScreen
Не знаю к чему конкретно относится этот баг: к конкретно 4.7 под Symbian или ко всем версиям Qt под Symbian. Но баг имеет место быть. При выводе информации на сплешскрин старые строки не стираются и накладываются друг на друга.

Грабли №13. Глюки со сборкой
Я не ошибся в нумеровании, эти грабли просто просятся на 13-ое место.Побороть я их так и не смог. Суть из заключается в том, что сборка не всегда проходит правильно  Причем ошибки сборки не появляются, а просто не запускается приложение. Если закомментировать большую часть кода, собрать опять, запустить (тут главное комментировать до тех пор, пока не запустится хоть как-то), раскомментировать обратно, собрать и приложение снова запустится.

10 комментариев:

  1. да уж, хочется пожелать удачи Нокии с ее телефонными платформами. Все пилят, пилят, а допилить до вменяемого состояния никак не могут.

    Странно то, что сборка приложений Qt для WinMobile почти без проблем происходит, правда я всегда из под VisualStudio работал, а для своей платформы нормально сделать не могут. И вроде времени уже предостаточно прошло, Нокия купила троллей еще в 2008.

    ОтветитьУдалить
  2. Да тут дело то больше не в Кьюте, а в самой Симбе и ее тулчейнах. Под Маемо все собирается очень красиво и легко. Ждем МиГо.

    ОтветитьУдалить
  3. А что, грабли gcc с целочисленным делением в Симбиан уже пофиксили?

    ОтветитьУдалить
  4. Не натыкался видать еще :) можно поподробнее?

    ОтветитьУдалить
  5. А какие проблемы у креатора со сборкой SUBDIRS?

    P.S. На сколько я помню, команда Symbian пыталась прикрутить свежий GCC, и у них на вики где-то даже были описаны все шаги.

    P.P.S. Раньше всегда собирал все под armv5, никаких глюков не наблюдалось

    ОтветитьУдалить
  6. Ну по большому счету проблемы связаны с использованием линкуемых библиотек в сабдирах. Ну и плюс вот этот баг http://bugreports.qt.nokia.com/browse/QTBUG-11292

    ОтветитьУдалить
  7. У себя в проекте зависимости для статических библиотек у SUBDIRS прописываю через PRE_TARGETDEPS и LIBS

    ОтветитьУдалить
  8. QPrinter точно не будет, QtConcurrent тоже

    ОтветитьУдалить
  9. Откуда дровишки? про Конкаррент не знаю, но про принтер я в свое время оставлял реквест на включение его в симулятор (а если включат туда, то включат и в симбиановскую сборку), реквест до сих пор не закрыт (как кстати и реквест на WinCE с принтером).

    ОтветитьУдалить
  10. первый пункт я решил немного по другому:
    в файле Qt\mkspecs\common\symbian\symbian-mmp.conf закоментил две последние цели:
    SYMBIAN_PLATFORMS = WINSCW GCCE #ARMV5 ARMV6

    А на счет пятого пункта (прилинковка статических либ к проекту), то в документации по этому поводу сказано:
    Note: On the Symbian platform, the build system makes a distinction between shared and static libraries. In most cases, qmake will figure out which library you are refering to, but in some cases you may have to specify it explicitly to get the expected behavior. This typically happens if you are building a library and using it in the same project. To specify that the library is either shared or static, add a ".dll" or ".lib" suffix, respectively, to the library name.
    http://doc.qt.nokia.com/latest/qmake-variable-reference.html#libs

    ОтветитьУдалить