вторник, 19 марта 2013 г.

Портируем CMake проект на ARM Windows RT

CMake замечательная штука для создания действительно кросс платформенных проектов. В заметке несколько рецептов о том, как быстро портировать свой любимый проект на новую систему.
CMake из коробки умеет генерировать проекты для Visual Studio, и это предпочтительный способ сборки, если вы работаете на Windows. К большому сожалению, cmake до сих пор, даже в ночных сборках не научился опознавать компилятор под ARM и генерировать правильный проект. Ребята из Kitware активно работают над новой версией и обещают поддержку Windows RT к версии 2.8.11, а мы тем временем пойдём другим путём.
Быстрый пробег по поисковой выдаче Гугла даёт обсуждение на Stackoverflow. Начальная идея найдена. Можно генерировать не проект для Visual Studio, а Makefile для nmake. Достаточно правильно выставить переменные окружения. После такого фокуса CMake думает, что имеет дело со стандартным хостовым компилятором и ничего не знает про кросс компиляцию.
Конфигурация обычно проходит нормально, но запустив билд любого мало мальски серьёзного проекта мы получим сообщение об ошибке:
C:\Program Files\Microsoft Visual Studio 11.0\VC\INCLUDE\crtdefs.h(338):
fatal error C1189: #error: Compiling Desktop applications for the ARM platform is not supported.
Решение проблемы можно найти в crtdefs.h или в том же обсуждении. Достаточно добавить макрос ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE. Для cmake это лучше сделать функцией add_definitions. Он сам добавит макрос в нужном формате и там где надо:
project(MyFavouriteProject)
add_definitions(ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE)
... 
В большинстве случаев добавление макроса решает все проблемы, но это не всё. Настоящие кросс платформенные проекты часто используют разные системные и не очень инклюды, которые могут отличаються от платформы к платформе. Для проверки наличия того или иного заголовочного файла в cmake используется функция check_include_file. При вызове этой функции cmake автоматически создаёт маленькую программу на C\С++ с подключенным заголовком и пытается её скомпилировать. Если билд прошёл успешно, значит заголовок есть и можно идти дальше. Но причиной падения может быть не только отсутствие заголовочного файла, но и та же беда в crtdefs.h, если это файл прямо или косвенно входит в тестовую программу.
Причину провала таких тестов можно посмотреть в логах в директории CMakeFiles в билд каталоге вашего проекта. Для того, чтобы такие логи сохранялись в файл добавьте ключ --debug-trycompile в командную строку cmake'a при конфигурации. Макрос добавленный функцией add_definitions не попадает в список макросов при компиляции тестовых программ. Его надо добавить самостоятельно в переменную CMAKE_REQUIRED_DEFINITIONS:
project(MyFavouriteProject)
set(CMAKE_REQUIRED_DEFINITIONS -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE) 
add_definitions(ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE)
check_include_file(assert.h HAVE_ASSERT_H)
...
И ещё один маленький рецепт напоследок. Вместо nmake можно использовать Ninja. Инструмент быстро и легко собирается из исходного кода. Правда для старта ему нужен Python. Такая полезная в хозяйств штука у большинства разработчиков и так есть, поэтому никакой сложности сборка составить не должна. После сборки складываем единственный получившийся исполняемый файл куда вам нравится и добавляем этот путь в PATH. После этого в командной строке cmake заменяем -G "NMake Makefiles" на -GNinja и зовём ninja вместо nmake.
Ninja работает намного быстрее своего штатного аналога и сразу распараллеливает билд на все доступные системе процессоры. Проект развивается как замена обычному Unix mak'у, работает на множестве платформ и вообще отличная штука!

воскресенье, 10 марта 2013 г.

GDB Седержимое ВСЕХ регистов на ARM архитектуре

Недавно отлаживая очень странное падение нативного кода на Android телефоне с процессором, поддерживающем NEON, наткнулся на интересную особенность. Отладчик gdb из состава NDK-r8d по команде info registers показывает не все регистры для арифметики с плавающей точкой. Если точнее, то в дампе только первые 16, как будь то NEON расширения нет совсем. Как выяснилось чуть позднее, он ведёт себя так на ARM-v7a всегда. Чтобы посмотреть дополнительные регистры, надо сказать в  gdb консоли info all-registers.