Visual studio cmake android

Детективная история с участием CMake 3.10 и Android Studio

Disclaimer: всё описанное ниже не является хорошей практикой. Не следует читать этот текст как руководство к действию — его роль, скорее, развлекательная. По этой же причине, не имеет смысла советовать автору (мне) сменить язык, инструменты, ОС, железо, пол и страну пребывания.

У меня есть один проект. Для сборки он использует CMake, а также менеджер пакетов для C++ под названием Hunter, хорошо с CMake интегрированный. Проекту необходимо собираться для нескольких платформ, одна из которых — Android. Hunter собирает зависимости под Android без проблем — но ему нужна версия CMake >= 3.7, поскольку именно в 3.7 была добавлена улучшенная поддержка этой платформы. Эта очень важная деталь.

CMake поддерживает генерацию проектов для Android под Windows/Visual Studio при помощи плагина NVIDIA Nsight Tegra. К сожалению, этот плагин не ставится на Visual Studio 2017, а ставить 2015ую ради одного проекта не хотелось. С другой стороны, в VS2017 есть поддержка сборки под Android — но нет генерации таких проектов из CMake. Точнее, она есть, но требует самодельной версии CMake от Microsoft, разработка которой была заброшена в районе версии 3.4, то есть, мне она не подходит.

Хорошо, если не Visual Studio, то Android Studio! CMake, конечно, её не поддерживает, зато она поддерживает его, аж с версии 2.x. Указываешь путь к CMakeLists.txt в build.gradle, запускаешь синхронизацию, и всё должно работать. Но не работает, а говорит «У вас не установлен CMake». Почему — а потому, что она работает тоже со своим собственным форком CMake, который надо качать из репозитория Android, и который застыл на версии 3.6.

Казалось бы тупик. Но на самом деле нет, потому что начиная с версии 3.0, Android Studio умеет работать с внешними версиями CMake старше 3.6, за счёт той самой «улучшенной поддержки Android». Достаточно прописать в local.properties поле cmake.dir, и всё должно работать. Но не работает, а говорит… Хм, вот честно говоря я уже забыл, что он там говорил, но суть в том, что текст ошибки, забитый в Google, привёл меня к разговору в баг-треккере, где упоминалось, что в версиях 3.7 и 3.8 CMake с Android Studio как-то неправильно общаются, и это всё должно быть исправлено в версии 3.9.

А у меня как раз стоит CMake 3.8. Ну что же, не беда, идём на сайт и качаем свежайший CMake, который имеет версию 3.10 (ну правда же 3.10 должна быть лучше, чем 3.9, или во всяком случае не хуже?). Устанавливаем, и всё должно работать. Но не работает, а говорит «Ошибка общения с CMake Server — смотрите логи». Логи же лаконично заявляют:

Как видите, решительно никаких ошибок. Кстати, да, а что вообще за CMake Server? Первый раз слышу. Идём в документацию, и читаем, что это такой новый режим работы CMake, который позволяет внешним программам получать информацию о CMake-проекте в машино-читаемом виде, что упрощает интеграцию с разными IDE и дополнительными инструментами.

Вот тут и начинается детектив. Первая улика — поля «major» и «minor» в ответе сервера. Раз есть версия протокола — её кто-нибудь может проверять, и не работать с «неправильными» версиями. Предположение очень вероятное, но лишь предположение — хорошо бы получить его подтверждение.

На самом деле в этот момент я решил сделать паузу и передать дело в полицию завести баг в баг-треккере Android Studio, как они сами предлагают в своей документации. К сожалению, реакции на баг не последовало, а через несколько дней он пропал из треккера — не был закрыт, пусть даже и с WONTFIX, а именно пропал без следа. Обозлившись, я решил довести собственное расследование до конца.

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

Мне надо было найти исходники плагина Android для Gradle, который и ответственен за интеграцию с CMake. Как обычный порядочный гражданин, я забил фразу «android gradle plugin source» в Google, и получил в ответ страницу репозитория. Однако, краткий поиск по ней при помощи веб-интерфейса, показал, что последний коммит в master был 2 года назад. А где же свежие сорцы? Не понятно!

Читайте также:  Андроид головное устройство 10 дюймов

Вторая ссылка из того же поиска привела меня на инструкцию «как скачать исходный код AOSP». Сделать это, надо сказать, не просто: у Google, как всегда, всё не как у людей, и нельзя просто выкачать конкретный проект из Git. Надо взять их собственный инструмент под названием repo, и использовать его.

Edit: в комментариях подсказывают, что можно, и проекты таки лежат в отдельном Git’е каждый — а я сослепу просто не увидел большой надписи «Clone this repo:» в верху страницы. Прошу прощения за дезинформацию!

Берём repo, убеждаемся, что это обычный скрипт на Питоне, запускаем, и получаем ошибку — не найден импорт fcntl. Да, этот скрипт не работает под Windows. Ура, я люблю тебя, Google. Запускаем случайно завалявшуюся в углу виртуальную машину с Ubuntu, скачиваем repo туда, запускаем, и, видя, что что-то происходит, уходим обедать.

По возвращение, меня встретила ошибка «no space left on device». Ну да, там его было 5Gb, но нужный мне проект никак не может столько весить, даже со всеми зависимостями! Однако, короткое расследование показало, что repo выкачивает весь, или почти весь репозиторий AOSP, и указать ему отдельный проект — нет совершенно никакой возможности. Частично, как я понимаю, это вина Git’a, а точнее — того, как его использует Google. Вместо того, чтобы засунуть каждый проект в свой репозиторий, они всё засунули в один. А Git, в отличие от SVN, не умеет выкачивать суб-директории репозитория от слова «совсем».

«Нет, — решил я, — выкачивать весь Андроид с цирком и конями ради одного-двух файлов, которые мне надо посмотреть, я не хочу.»

Интуиция подсказывала, что где-то всё-таки должны быть исходники нужной мне версии плагина. Но разум зашёл в тупик. Поэтому я решил поискать помощи на официальных ресурсах для разработчиков Android. Группу в Google+ отвергаем сразу — это не платформа для серьёзных разговоров. А вот старые добрые Mailing List’ы Google Groups — это то что нам надо! Их есть два — «просто Android (android-developers)» и «для тех кто NDK (android-ndk)». Моя проблема к NDK отношения, вроде бы, имеет мало, поэтому открываем первую ссылку… И получаем сообщение — «Эта группа рассылает malware, поэтому мы её закрыли нафиг. Подпись, Ваш Google.».

Сцена немого удивления.

Ладно, открываем вторую группу, для разработчиков NDK. Она рабочая. В поиск вбиваем слово CMake, надеясь зацепить что-нибудь интересное — и находим! Тема называется «Как указать Android Studio внешний CMake?». Её краткий обзор показывает, что это как раз то место, где обсуждалось изменение, приведшее к появлению в плагине версии 3.0.0. этой возможности. В тему был призван человек, что-то понимающий в плагине. Он дал автору темы ссылку на репозиторий (всё ту же бесполезную, где написано использовать repo), но самое главное — не утерпел, и скопировал в одно из писем часть кода из файла, указав его имя!

Этого мне было достаточно. Я забил имя в поиск Google, и тут же нашёл его в их репозитории. Правда, это был файл из ветки studio-2.2-preview3, то есть, более ранней, не имеющей интеграции с внешними версиями CMake.

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

Меняем прямо в URL имя ветки на studio-3.0, и… Находим, но не совсем то: в этом файле нет никаких упоминаний про версию протокола CMake Server. Но это уже не страшно, благо через веб-интерфейс, в отличие от repo, можно скачать в tgz отдельную папку репозитория, и в ней искать нужное.

Читайте также:  Прошивка для smaggi aio smarti android

Просмотр кода показал, что дело действительно было в версии протокола. Плагин сравнивал её на чёткое соответствие 1.0 (в функции getSupportedVersion), а свежий CMake использовал 1.1 (в следующей версии, кстати, уже будет 1.2). Из исследования кода CMake, я знал, что версия 1.1 не добавляет ничего принципиально ломающего, поэтому не было никаких препятствий к тому, чтобы Android Studio могла с ней работать, кроме этой дурацкой проверки. Поэтому, я нашёл у себя на диске файл gradle-core-3.0.0.jar, достал из него нужный класс, и при помощи Java Bytecode Editor, изменил проверку так, чтобы всё работало (disclaimer: не повторяйте дома (а там более на рабочем месте); трюк выполнен отчаявшимся и очень обозлённым программистом).

Источник

Отладка Android CMake проекта по-взрослому


После перевода наших проектов на CMake, встал вопрос об отладке нативной части Android. Так как инструменты NDK стали неактуальны, пришлось залезть в дебри и научить Eclipse запускать удалённую отладку CDT-проекта, что называется, вручную. В идеале, чтобы это выполнялось в один клик.

Если вам не чужда разработка с использованием Android NDK, и вы хотите познать некоторые тонкости отладки, велкам под кат.

В одной из наших студий было принято решение о переводе кроссплатформенных проектов на CMake, что позволило ускорить их разработку, но также внесло свои коррективы в некоторые этапы. CMake полностью заменил систему сборки ndk-build, и «инструменты отладки» ndk-stack, ndk-gdb стали недоступны. Помедитировав над Eclipse и CDT в частности, появилась мысль о том, что отладку нативного кода CMake Android-проекта можно сделать удобной, быстрой и доступной.

CMake Android-проект

В этой статье мы рассмотрим нашу задачу в слегка уменьшенном масштабе — на примере Teapot из состава Android NDK. Его сборка была переведена с ndk-build скриптов на CMake. Надо пояснить, что CMake не заточен полностью под Android, как и под любую другую платформу. Дополнительный функционал нужно писать самому, что и было сделано в данном случае, поэтому не удивляйтесь, если видите какую-то переменную или функцию, о которых в документации CMake ни слова. Бóльшую часть я попытаюсь описать, но кое-что могу упустить, поэтому если вы решите перенять опыт, то вам придётся вникнуть в используемые скрипты и хотя бы примерно понимать их работу, дабы при выходе новой версии NDK не сесть в лужу.

Для успешной сборки и настройки отладчика, вам понадобятся:

  • Android SDK
  • Android NDK r8+
  • CMake 2.8.11+
  • MinGW (если вы на Windows)
  • Переменная окружения ANDROID_NDK, указывающая на распакованный NDK

После загрузки демо-проекта, запустите cmake.cmd/sh , после чего в Eclipse импортируйте проекты из папок build/android_debug и sources/Teapot .
Для проекта TeapotNativeActivity можно добавить референс на TeapotNativeActivity-Debug@android_debug , чтобы пересборка происходила автоматически.

В итоге у вас должен получиться такой workspace:

Немного теории

Отладка native кода Android-приложения включает в себя несколько этапов:

  1. Сборка нативных библиотек с отладочными символами (чтобы отладчик мог связать код в исходниках и скомпилированный код).
  2. Создание урезанных версий библиотек без отладочных символов, но со ссылкой на них.
  3. Сборка и установка APK на устройство с урезанными версиями библиотек.
  4. Запуск APK.
  5. Поиск идентификатора процесса (PID) запущенного APK.
  6. Запуск удалённого отладчика на устройстве с указанием PID. Отладчик открывает TCP порт на устройстве, куда можно слать команды gdb.
  7. Пробрасывание TCP порта с устройства на локальный компьютер.
  8. Загрузка с устройства системных файлов, необходимых для корректной работы отладчика (установки правильных адресов и смещений).
  9. Запуск отладчика на локальном компьютере с указанием локального TCP порта и конфигурацией путей поиска библиотек и исходников.

В Eclipse всё это разделяется на несколько основных этапов:

  1. Сборка нативного кода.
  2. Сборка APK.
  3. Запуск APK.
  4. Выполнение скрипта-хелпера для настройки отладчика локально и удалённо.
  5. Запуск отладчика нативного кода.

Наша задача — объединить это всё в один клик.

Challenge accepted

Сборка .so

Сборка отладочных версий библиотек не представляет сложностей (CMake всё делает за нас), однако нюанс поджидает в совместимости форматов отладочной информации. Мы используем для сборки своих проектов arm тулчейн gcc-4.8, в котором почему-то используется gdb, не совместимый из коробки с генерируемым форматом dwarf. Для нахождения общего языка, компилятору нужно указать конкретный формат dwarf.

Для этого прописываем флаги в CMake:

Читайте также:  Redmi 9c nfc обновление до 11 андроида
Помещение отладочной информации в отдельный файл

Размер библиотеки с отладочными данными может достигать нескольких сотен мегабайт, что негативно влияет на размер APK и, как следствие, скорость загрузки на устройство. Для решения этой проблемы выполняем strip отладочной информации в отдельный файл:

После сборки, полная версия .so переименовывается в .so.debug , и на её основе создаётся .so с убранной информацией об отладке и ссылкой на .so.debug файл.
Этот код находится в функции set_ndk_gdbserver_compatible(target) в файле CMake/auto_included/android_helpers.cmake . Помимо выполнения стрипа после сборки, он также выполняет другие важные шаги, о которых ниже.

Удаленный отладчик a.k.a. gdbserver

При сборке не отладочной конфигурации файл gdbserver будет удаляться.

Скрипт ndk-gdb.py

Для настройки устройства и локальной машины используется переработанная версия скрипта ndk-gdb.py из Android NDK.

В его задачи входит:

  1. Проверка наличия флага android:debuggable=»true» в AndroidManifest.xml .
  2. Получение идентификатора package из AndroidManifest.xml .
  3. Подключение к девайсу и поиск PID запущенного инстанса по идентификатору package.
  4. Запуск gdbserver , пробрасывание порта.
  5. Копирование дополнительных файлов для отладчика на локальную машину.
  6. Создание файла gdb.setup для отладчика на локальной машине.

Этот скрипт создаётся на основе шаблона CMake/auto_included/stuff/ndk-gdb.py.in в момент вызова set_ndk_gdbserver_compatible(target) . В процессе запуска отладки скрипт должен запускаться после старта APK.

Настройка Eclipse для запуска ndk-gdb.py

Здесь и далее, параллельно описанию, будет идти мануал по настройке демо-проекта.

Добавляем External Tool с такой конфигурацией:

Так как это промежуточный шаг для запуска отладчика, то привязка к билду нам не нужна:

Настройка отладчика C++ Remote Application

Eclipse CDT предлагает несколько вариантов работы отладчика, но нас интересует единственно верный в данном случае: C++ Remote Application .

В настройки отладчика прописываются пути:

  • приложения для отладки
  • отладчика
  • конфигурации отладчика

Приложение для отладки — это файл app_process , который загружается с устройства на локальный компьютер. app_process — это нативный исполняемый файл для платформы Android, через который стартуют все Java-процессы.

Конфигурация отладчика — это файл gdb.setup , в котором указаны пути для поиска библиотек.

После генерации CMake-проекта, в папке build/android_debug/ndk-gdb создаются пустышки app_process и gdb.setup , чтобы на них можно было натравить Eclipse. В момент запуска отладки, скрипт ndk-gdb.py подгружает с девайса настоящий файл app_process и конфигурирует gdb.setup .

Настройка отладчика в Eclipse

Что отлаживаем:

Чем отлаживаем:

Как удобно-то!

В результате этих действий мы получили несколько разных задач в Eclipse, которые уже позволяют запустить отладку, но для этого нужно:

  1. Запустить APK
  2. Запустить скрипт ndk-gdb.py
  3. Запустить отладчик

Мы же рассчитываем отлаживать наше приложение в один клик, так?

Launch Group to the rescue!

На наше счастье, Eclipse CDT предлагает механизм по автоматизации нескольких разных действий в Eclipse, и имя ему Launch Group.

Создайте конфигурацию с последовательносью:

  1. Запуск отладки APK, задержка 2 секунды. Задержка нужна для стабильного запуска APK, т.к. следующий шаг требует запущенный APK, иначе скрипт не найдёт нужный процесс.
  2. Запуск скрипта ndk-gdb.py, задержка 2 секунды. Задержка нужна для стабильного пробрасывания порта с устройства.
  3. Запуск отладчика C++ Remote Application.

Для удобства на вкладке Common активируйте отображение этого шага на кнопке отладки в Eclipse:

Debug me

Если всё сделано правильно и у вас хорошая карма, то при запуске этого действия вы сможете наслаждаться отладкой вашего проекта:

Что-то пошло не так?

Проблемы бывают, и мы их периодически ловим. Разные девайсы имеют разную производительность, прошивки, версии Android.
Чаще всего сложности возникают из-за медленного запуска APK, что приводит к подключению отладчика ещё на фазе загрузки .so, что негативно сказывается на запуске, и порой вообще невозможно продолжить работу. Для решения этой проблемы нужно увеличить задержку между первым и вторым шагом в Launch Group.
Ещё возможна проблема с зависанием отладчика на девайсе, ребут устройства обычно спасает.

Также в предложенном примере используется ndk-gdb.py скрипт, рассчитанный на то, что его будут запускать только на Linux x86, Mac OS X x64 или Windows x64. Если ваша конфигурация отличается, то вам придётся его подкрутить.

Заключение

Всё это позволило значительно упростить отладку любого Android CMake-проекта, и мы этому несказанно рады. Конечно, есть простор для улучшений и оптимизаций: в идеале хочется сделать нечто, что могло бы настроить все эти шаги в Eclipse автоматически, потому как каждый новый проект/ветка требует такой настройки.

Если у вас появились вопросы или предложения по улучшению/упрощению схемы, я буду рад их услышать!

Источник

Оцените статью