android — общие подкаталоги проекта CMake избегают перестройки

Для проекта я использую скрипты Android Gradle с CMake, плагин Gradle версии 3: 0: 0, CMake версии 3.6. Файлы Gradle и CMake довольно просты и неинтересны (просто определяя используемые файлы — я все равно могу копировать и вставлять их по мере необходимости).

У меня есть следующая структура проекта; в основном это кодовая база, создающая несколько десятков файлов .so (нативная часть для пакетов Android, которые упаковываются в apk, называемый, таким образом, «Исполняемыми файлами»), которые все зависят от одного и того же кода совместно используемой библиотеки (статические библиотеки, которые называются «библиотеки»). «). Код библиотеки по-прежнему (относительно) изменчив, поэтому я хочу, чтобы исполняемые файлы имели зависимости на уровне проекта, чтобы при сборке исполняемых файлов библиотеки перестраивались по требованию при каждом изменении их кода.
Структура выглядит так:

+ LibProjects/
---Bin/ (Originally empty)
---Lib1/CMakeLists.txt (+sources files, same level as the CMakeLists.txt)
...
---Lib10/CMakeLists.txt (same)
+ Executables/
---Executable1/CMakeLists.txt (source files here)
--------------/AndroidFiles/build.gradle (and other android project files)(points to the CMakeLists.txt)
...
---Executable40/CMakeLists.txt

CMakeLists из библиотек перенаправляют свой вывод в папку Bin, используя

set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY {CMAKE_CURRENT_SOURCE_DIR}/../Bin/${ANDROID_ABI}/${LibraryName})

Проекты исполняемого файла добавляют зависимости от библиотек «как обычно»

add_subdirectory(${PROJECTS_ROOT}/LibProjects/${LibraryName} ${PROJECTS_ROOT}/Framework/Bin/Android/${ANDROID_ABI}/${LibraryName})...

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

Проблема заключается в том, что при последовательном построении исполняемых файлов каждый из них НЕ использует выходные данные других проектов библиотечного проекта: когда я собираю Executable1, он будет собирать все библиотеки (обычные), а затем сам себя. Впоследствии, когда я собираю Executable2, он НЕ будет повторно использовать библиотеки, которые уже были созданы для Executable1, и т. Д. — это эффективно увеличивает время моей сборки в ~ 10 раз.

Я могу найти выходные данные сборки каждой библиотеки в папке / Bin, как и ожидалось, но они не используются повторно в исполняемых файлах — в папке bin нет «файлов проекта» CMake (это правильный термин), все они генерироваться в каталоге исполняемой сборки.

Проблема, которую я пытаюсь решить, — это время сборки, обусловленное тем, что каждая библиотека перестраивается для каждого исполняемого файла.

В настоящий момент я рассматриваю решение, как-то проинструктировать CMake использовать папку Bin (или другую папку) в качестве рабочей папки для каждой библиотеки в своей папке вместо исполняемого файла, надеясь, что плагин gradle для Android будет достаточно умен. чтобы затем определить, что ни cmakefiles, ни объектные файлы не должны быть восстановлены, и избежать перестроения.

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

5

Решение

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

Когда вы запускаете CMake вручную в Executables/<x> каталог, cmake получить информацию из каталога сборки, связанной с Executable/<x> каталог. Затем он проверяет, соответствует ли метка времени построенного файла последней сборке, выполненной в этом каталоге компоновки. Если нет, это восстановить. Что происходит так: Lib1 файл библиотеки создается после сборки Executable1тогда вы запускаете cmake в Executalbe2он сравнивает временную метку Lib1 целевой файл, убедитесь, что этот файл не был создан этим экземпляром сборки cmake, а затем пересоберите lib. И так далее.

Итак, у вас есть два варианта:

1- Либо вы создаете библиотеку и устанавливаете их целевые файлы в binкаталог (используя install команда cmake и make install команда bash для примера). Тогда в Executalbe<x>/CMakeLists ты используешь find_library команда вместо add_subdirectory,

2- Или вы создаете супер проект, который имеет следующую структуру:

+  supper_project
---CMakeLists.txt #add_subdirectory(LibProjects/lib<x>)... add_subdirectory(Executables/Executalbe<x>)...
+ LibProjects/
---Bin/ (Originally empty)
---Lib1/CMakeLists.txt (+sources files, same level as the CMakeLists.txt)
...
---Lib10/CMakeLists.txt (same)
+ Executables/
---Executable1/CMakeLists.txt (source files here)
--------------/AndroidFiles/build.gradle (and other android project files)
(not any more:points to the CMakeLists.txt)
...
---Executable40/CMakeLists.txt
2

Другие решения

Я думаю, что проблема заключается в том, как вы определили свои зависимости.

Для каждого исполняемого файла вы создаете отдельные цели, используя add_subdirectory.
например для исполняемого файла 1 у вас есть add_subdirectory(${PROJECTS_ROOT}/LibProjects/${Library1}) и для исполняемого файла 2 также у вас есть add_subdirectory(${PROJECTS_ROOT}/LibProjects/${Library1}), поэтому cmake создаст две отдельные цели для одной и той же библиотеки1 в каждом из подкаталога исполняемого файла и, таким образом, создаст отдельные файлы меток времени и кеша. Вот почему кажется, что она собирает одну и ту же библиотеку несколько раз, но на самом деле для cmake они являются разными целями.

Чтобы это исправить, вы можете включить все библиотеки в CMakeLists.txt верхнего уровня, используя add_subdirectory и они в CMakeLists.txt каждого исполняемого файла добавляют зависимость, используя add_dependencies команда.

0

Мне удалось обойти эту проблему — но, в конце концов, это была работа вокруг, а не с CMake.

Я удалил зависимости уровня CMakeFile (add_subdirectory) и оставил библиотеки только на уровне связывания (исполняемый файл target_link_libraries [файлы библиотеки])

После этого я создал сценарии gradle для каждой библиотеки и добавил зависимости к этим сценариям в каждом сценарии gradle приложения, так что сборка библиотек запускается зависимостями gradle вместо зависимостей CMake. Это медленнее, чем было бы, если бы можно было избежать gradle, но гораздо быстрее, чем перестройка каждый раз, и издержки как минимум постоянны (несколько секунд на проект).

0
По вопросам рекламы ammmcru@yandex.ru