Android cmake что это

Детективная история с участием 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 года назад. А где же свежие сорцы? Не понятно!

Вторая ссылка из того же поиска привела меня на инструкцию «как скачать исходный код 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.

Читайте также:  Что такое clean architecture android

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

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

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

Источник

Введение в CMake

CMake — кроcсплатформенная утилита для автоматической сборки программы из исходного кода. При этом сама CMake непосредственно сборкой не занимается, а представляет из себя front-end. В качестве back-end`a могут выступать различные версии make и Ninja. Так же CMake позволяет создавать проекты для CodeBlocks, Eclipse, KDevelop3, MS VC++ и Xcode. Стоит отметить, что большинство проектов создаются не нативных, а всё с теми же back-end`ами.

Для того что бы собрать проект средствами CMake, необходимо в корне дерева исходников разместить файл CMakeLists.txt, хранящий правила и цели сборки, и произвести несколько простых шагов.
Разберёмся на примерах.

Пример 1. Hello, World:

Синтаксис CMake похож на синтаксис bash, всё что после символа «#» является комментарием и обрабатываться программой не будет. CMake позволяет не засорять дерево исходных кодов временными файлами — очень просто и без лишних телодвижений сборка производится «Out-of-Source».

Создадим пустую директорию для временных файлов и перейдём туда.

$ mkdir tmp
fshp@panica-desktop:

$ cd tmp/
fshp@panica-desktop:

/cmake/example_1/

— Build files have been written to: /home/fshp/tmp
fshp@panica-desktop:

/tmp$ ls
CMakeCache.txt CMakeFiles cmake_install.cmake Makefile
fshp@panica-desktop:

/tmp$ make
Scanning dependencies of target main
[100%] Building CXX object CMakeFiles/main.dir/main.cpp.o
Linking CXX executable main
[100%] Built target main
fshp@panica-desktop:

/tmp$ ./main
Hello, World!
fshp@panica-desktop:

Итак, наша программа собралась.
Папку tmp можно очищать\удалять без риска поломать исходники. Если CMakeLists.txt был изменен, то вызов make автоматически запустит cmake. Если исходники были перемещены, то нужно очистить временную директорию и запустить cmake вручную.

Пример 2. Библиотеки:

Переменные могут хранить списки значений, разделённых пробелами\табуляциями\переносами:

Оба варианта правильные
Что бы получить значение переменной ипользуем конструкцию:

Итак, эта версия нашего проекта включает в себя одну статическую библиотеку, собираемую из исходников. Если заменить «STATIC» на «SHARED», то получим библиотеку динамическую. Если тип библиотеки не указать, по умолчанию она соберётся как статическая.
При линковке указываются все необходимые библиотеки:

Как и при ручной компиляции, имена библиотек указываются без стандартного префикса «lib».
Итак, сборка библиотек с CMake не вызывает проблем, при этом тип библиотеки статическая\динамическая меняется лишь одним параметром.

Пример 3. Подпроекты:

В файле подпроекта ничего нового для вас нет. А вот в основном файле новые команды:

Читайте также:  Android studio закрыть activity по кнопке

main.cpp мы не меняли, а foo.h перенесли. Команда указывает компилятору, где искать заголовочные файлы. Может быть вызвана несколько раз. Хидеры будут искаться во всех указаных директориях.

Указываем директорию с подпроектом, который будет собран как самостоятельный.
Вывод: проекты на CMake можно объединять в довольно сложные иерархические структуры, причем каждый подпроект в реальности является самостоятельным проектом, который в свою очередь может сам состоять из подпроектов. Это позволяет легко разбить вашу программу на необходимое количество отдельных модулей. Примером такого подхода может служить KDE.

Пример 4. Поиск библиотек:

CMake обладает достаточно развитыми средствами поиска установленых библиотек, правда они не встроеные, а реализованы в виде отдельных модулей. В стандартной поставке довольно много модулей, но некоторые проекты (например Ogre) поставляют свои. Они позволяют системе автоматически определить наличие необходимых для линковки проекта библиотек.
На debian модули располагаются в /usr/share/cmake-2.8/Modules/ (у вас версия может отличаться). За поиск библиотек отвечают модули, называющиеся FindNAME.cmake, где NAME — имя библиотеки.

Думаю, смысл должен быть понятен. Первый и второй блок — поиск библиотеки. Если в системе её нет, выведется сообщение об ошибке и завершается выполнение cmake. Третий блок похож, только он ищет не целый пакет библиотек, а лишь необходимый компонент. Каждый такой автоматизированый поиск определяет после выполнения как минимум 3 переменные:
SDL_FOUND, LIBXML2_FOUND, Boost_FOUND — признак присутствия бибилиотеки;
SDL_LIBRARY, LIBXML2_LIBRARIES, Boost_LIBRARIES — имена библиотек для линковки;
SDL_INCLUDE_DIR, LIBXML2_INCLUDE_DIR, Boost_INCLUDE_DIRS — пути к заголовочным файлам.
Если с первыми более или менее понятно, то вторые и третьи мне доставили много хлопот — половина имеет имена в единственном числе, половина — во множественном. Но оказалось, это легко отследить. В каждом модуле вначале есть коментарии, там описаны определяемые переменные. Посмотрите, например, /usr/share/cmake-2.8/Modules/FindLibXml2.cmake
Как видите, CMake способен сам определить наличие и местоположение необходимых библиотек и заголовочных файлов. В принципе, это должна уметь любая система автоматической сборки, иначе смысл в ней?

Пример 5. Внешние библиотеки и объектные файлы:

Если вы пишите для «дяди», а злой «дядя» любит самописные библиотеки и делиться исходниками не желает, поэтому присылает готовую библиотеку, то вы по адресу.
Объектные файлы в CMake стоят на ряду с исходниками — достаточно включить объектник в список файлов для компиляции.
С библиотеками потуже. Как известно, статическая библиотека это не что иное, как ar-архив, внутри которого лежат обычные объектники, никак не связаные между собой. Вы, наверное, уже догадались, как я поступал сначала. Да, просто потрошил библиотеку. Но потом был найден способ поэлегантнее:

Слово «IMPORTED», указывает, что библиотека берётся извне.
В CMake каждая цель имеет параметры, а set_property позволяет их изменять.
Линкуется такая библиотека стандартно:

Для динамических библиотек все аналогично, только тип «SHARED», расширение — «.so».
К сожалению, поддержка несистемных библиотек реализована немного костыльно. Возможно, я просто не знаю правильного варианта, поэтому буду рад, если «ткнете мордочкой». С другой стороны это не навороченый экзоскелет с системой жизнеобеспечения, а простейший костыль из двух строк.

Генераторы:

/cmake/example_3/ -G «KDevelop3 — Unix Makefiles»

Заключение:

Это не перевод мануала, а результат использования CMake в одном коммерческом проекте. Буду рад, если статья поможет хотя бы одному человеку — на русском языке подобной документации довольно мало.

Чем понравился CMake лично мне:

  • один проект — один файл. Не нужно хранить кучу скриптов настройки, сборки и прочего хлама;
  • Скорость работы в сравнении с autotools;
  • простой и понятный синтаксис, конечно с элегантностью питона не потягаться, но и не брейнфак, в конце концов.;
  • является front-end`ом для множества IDE;
  • отображение прогресса — довольно удобно;
  • цветной вывод — в серые будни немного краски не помешает;

Для Sublime Text есть плагин, добавляющий подсветку синтаксиса CMake, он так и называется — «CMake».
Примеры

Источник

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