Как связать общую библиотеку без необходимости экспортировать ее внутренние целевые объекты

#cmake

Вопрос:

Не удалось настроить следующий проект повторного создания. Цель состоит в том, чтобы создать общую библиотеку, которая внутренне состоит из пары статических библиотек. Я хочу, чтобы внутренние символы, включая пути и т. Д., Были экспортированы из общей библиотеки. Для этого я делаю внутренние библиотеки ОБЩЕДОСТУПНЫМИ библиотеками ссылок. Но затем cmake говорит мне, что мне нужно экспортировать свою цель. Я не хочу «загрязнять» конфигурацию моего пакета кучей внутренних целей. Нет ли способа «объединить» внутренние целевые объекты (статические библиотеки) в общедоступную экспортируемую целевую (общую библиотеку) или скрыть ее в файле целевых объектов конфигурации?

Импортированный целевой объект SystemC::systemc не отображается в моем целевом файле и также не создает никаких ошибок. Я предполагаю, что это связано с тем, что этот целевой объект уже экспортирован в своем собственном пакете? Если да, значит ли это, что мне нужно создать свои внутренние пакеты библиотек и таким образом импортировать целевые объекты, чтобы они исчезли из моего списка экспортированных целевых объектов?

 cmake_minimum_required(VERSION 3.16)
project(mylib)

find_package(SystemCLanguage 2.3.3 CONFIG REQUIRED)

add_library(mysublib STATIC mysublib.cpp)

add_library(mylib SHARED mylib.cpp)
target_link_libraries(mylib
    PUBLIC SystemC::systemc
    PUBLIC mysublib
)

export(
    TARGETS mylib
    NAMESPACE MyLib::
    FILE MyLibTargets.cmake
)
 

Ошибка, сгенерированная при настройке

 CMake Error in CMakeLists.txt:
  export called with target "mylib" which requires target "mysublib" that is
  not in any export set.
 

Ответ №1:

Цель состоит в том, чтобы создать общую библиотеку, которая внутренне состоит из пары статических библиотек. Я хочу, чтобы внутренние символы, включая пути и т. Д., Были экспортированы из общей библиотеки. Для этого я делаю внутренние библиотеки ОБЩЕДОСТУПНЫМИ библиотеками ссылок.

Итак, во-первых, я отмечу, что PUBLIC это не имеет никакого отношения к видимости символов. В вашем примере mysublib нет никаких INTERFACE свойств, поэтому вы могли бы сделать это PRIVATE mylib и избежать необходимости экспорта mysublib .

Однако, если вам действительно нужно mysublib в INTERFACE оф mylib , то вам действительно нужно его экспортировать, и точка. Как вы говорите, невозможно «объединить» внутренние целевые объекты […] в общедоступную экспортируемую цель […] или скрыть ее в файле целевых объектов конфигурации». Но это тоже не настоящая проблема.

Если вы беспокоитесь о людях , на которых полагаетесь mysublib , то вы можете установить EXPORT_NAME свойству of mysublib значение, указывающее, что оно не предназначено для использования, например _private_mysublib :

 set_target_properties(mysublib PROPERTIES EXPORT_NAME _private_mysublib)
 

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

 string(RANDOM LENGTH 12 mysublib_export)
set_target_properties(mysublib PROPERTIES EXPORT_NAME "x${mysublib_export}")
 

Добавление an x гарантирует, что оно не начинается с числа. Существует также небольшая вероятность столкновения, если вы будете делать это часто. Если вы хотите быть в абсолютной безопасности, вам следует написать функцию, которая записывает имена, которые она уже вернула, в глобальное свойство и повторяет попытку, если она выберет столкновение.

Импортированный целевой объект SystemC::systemc не отображается в моем целевом файле и также не создает никаких ошибок. Я предполагаю, что это связано с тем, что этот целевой объект уже экспортирован в своем собственном пакете? Если да, значит ли это, что мне нужно создать свои внутренние пакеты библиотек и таким образом импортировать целевые объекты, чтобы они исчезли из моего списка экспортированных целевых объектов?

Вы правы: поскольку SystemC::systemc он импортирован, его не нужно (и фактически не может быть) реэкспортировать. Ожидается, что вы вызовете find_dependency(SystemCLanguage 2.3.3) свой MyLibConfig.cmake файл как в дереве сборки ( export ), так и после установки ( install(EXPORT) ).

Если вы хотите , чтобы это поведение применялось mysublib , тогда да, вам нужно будет разделить свои проекты на части. Однако я не вижу веской причины для этого. Либо сделайте mysublib PRIVATE , либо просто смиритесь с тем, что он будет переименован в вашей конфигурации пакета. Цели не являются драгоценными, и они расположены в пространстве имен, так что нет никаких реальных причин для беспокойства.

Комментарии:

1. Я привык делать файлы более прямыми, делай это, получай то. Я предполагаю, что cmake попытается доказать это в будущем, если я, например, изменю mysublib для СОВМЕСТНОГО ИСПОЛЬЗОВАНИЯ. Теперь мне просто нужно выяснить, как получить зависимости (dll) в целевую папку сборки (exe), чтобы ctest мог запускать созданные целевые объекты…

2. Попробуй CMAKE_RUNTIME_OUTPUT_DIRECTORY