Вопрос или проблема
У меня есть статическая библиотека, собранная с помощью CMake. Эта библиотека зависит от нескольких других, и чтобы облегчить работу другой команде, мы объединяем все статические библиотеки в одну перед отправкой продукта им (по некоторым причинам было решено отправлять наш продукт в виде статической библиотеки, а не динамической, и я не могу это изменить).
На сегодняшний день мы вручную собрали список зависимостей и написали скрипт, который вызывает архиватор, однако я думал, что это можно было бы сделать автоматически с помощью cmake, и я попробовал это.
Мне удалось извлечь список зависимостей, модифицировав этот ответ, но я не совсем уверен, как превратить это в список путей, которые я могу предоставить ar/libtool. Вот код моей последней попытки. Судя по выводу, выглядит так, что все аргументы передаются в libtool как единая строка в кавычках.
function(get_dependencies TARGET)
get_target_property(target_type ${TARGET} TYPE)
if (NOT target_type STREQUAL "STATIC_LIBRARY")
return()
endif()
get_target_property(IMPORTED ${TARGET} IMPORTED)
list(APPEND TARGET_DEPENDENCIES ${TARGET})
if (IMPORTED)
get_target_property(LIBS ${TARGET} INTERFACE_LINK_LIBRARIES)
else()
get_target_property(LIBS ${TARGET} LINK_LIBRARIES)
endif()
foreach(LIB ${LIBS})
if (TARGET ${LIB})
list(FIND TARGET_DEPENDENCIES ${LIB} VISITED)
if (${VISITED} EQUAL -1)
get_dependencies(${LIB})
endif()
endif()
endforeach()
set(TARGET_DEPENDENCIES ${TARGET_DEPENDENCIES} PARENT_SCOPE)
endfunction()
function(merge_libraries target destination)
get_dependencies(${target})
list(TRANSFORM TARGET_DEPENDENCIES PREPEND "$<TARGET_FILE:")
list(TRANSFORM TARGET_DEPENDENCIES APPEND ">")
add_custom_target(Merge${target}Libraries
COMMAND libtool -static -o ${destination} "$<GENEX_EVAL:$<JOIN:${TARGET_DEPENDENCIES}, >>"
COMMAND_EXPAND_LISTS
DEPENDS ${target})
endfunction()
Вывод:
error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: can't open file: /path/to/lib1.a /path/to/lib2.a /path/to/lib3.a ... (Имя файла слишком длинное)
Ответ или решение
Объединение статических библиотек и их зависимостей с использованием CMake
Вам необходимо объединить статические библиотеки и их зависимости в одну библиотеку для упрощения работы другой команды. Это можно сделать с помощью CMake, что позволит автоматизировать процесс. Давайте подробно рассмотрим, как вы можете этого достичь.
1. Извлечение зависимостей
Начнем с функции, которая получает список зависимостей статической библиотеки. Ваша существующая функция выглядит хорошо, однако я внесу небольшие корректировки, которые помогут убедиться, что результат будет передан в команду архивации правильно.
function(get_dependencies TARGET)
get_target_property(target_type ${TARGET} TYPE)
if (NOT target_type STREQUAL "STATIC_LIBRARY")
return()
endif()
list(APPEND TARGET_DEPENDENCIES ${TARGET})
get_target_property(LIBS ${TARGET} INTERFACE_LINK_LIBRARIES)
foreach(LIB ${LIBS})
if (TARGET ${LIB})
list(FIND TARGET_DEPENDENCIES ${LIB} VISITED)
if (${VISITED} EQUAL -1)
get_dependencies(${LIB})
endif()
endif()
endforeach()
endfunction()
В этой функции мы собираем список всех зависимых библиотек, относящихся только к статическим библиотекам.
2. Подготовка команд для объединения библиотек
Теперь нам необходимо модифицировать функцию merge_libraries
, чтобы правильно сформировать команду, передающую списки библиотек для libtool
. Ключевым моментом здесь является использование COMMAND
с DEPENDS
, который позволит гарантировать, что библиотеки будут собраны сначала.
function(merge_libraries target destination)
set(TARGET_DEPENDENCIES) # Инициализация списка зависимостей
get_dependencies(${target})
# Преобразование списка в нужный формат
list(TRANSFORM TARGET_DEPENDENCIES PREPEND "<TARGET_FILE:")
list(TRANSFORM TARGET_DEPENDENCIES APPEND ">")
# Формируем команду libtool
add_custom_target(Merge${target}Libraries
COMMAND libtool -static -o ${destination} $<JOIN:TARGET_DEPENDENCIES, >
COMMAND_EXPAND_LISTS
DEPENDS ${target}
)
endfunction()
3. Проблемы с передачей длинного списка аргументов
Вы столкнулись с проблемой, когда длинный список аргументов передается в команду, что может вызывать ошибку об слишком длинном именах файлов. Используя COMMAND $<JOIN:TARGET_DEPENDENCIES, >
, вы сможете передать все библиотеки в формате, который ожидает libtool
.
4. Запуск сборки
Не забудьте вызывать вашу функцию merge_libraries
из основного CMakeLists.txt
:
merge_libraries(MyStaticLibrary merged_library.a)
Заключение
Данным образом вы сможете объединить статические библиотеки и их зависимости в одну, используя CMake. Автоматизация данного процесса значительно упростит дальнейшую работу вашей команды. Убедитесь, что команды выполняются в нужном порядке, а библиотеки собраны корректно, что позволит избежать возможных ошибок при интеграции.