Разрешить взаимозависимости в Cmake - PullRequest
2 голосов
/ 21 сентября 2019

Я пытаюсь перенести огромную базу кода из собственного внутреннего набора инструментов в Cmake.Этот код состоит из множества общих библиотек и некоторых исполняемых файлов.

Некоторые из этих библиотек взаимозависимы.Давайте возьмем в качестве примеров Lib1 и Lib2, где Lib1 использует символы из Lib2, а Lib2 использует символы из Lib1.
Чтобы создать библиотеку DLL Lib1, нам нужны экспортированные символы из Lib2, которые, в свою очередь, требуют экспортированные символы из Lib1.В настоящее время мы решили эту проблему путем объединения в два этапа, как описано здесь: Взаимный импорт ).Это дает нам следующие шаги:

  1. Создание lib1.lib и lib1.exp
    Создание lib2.lib и lib2.exp
  2. Создание lib1.DLL с использованием lib1.obj иlib2.lib / lib2.exp
    Создание lib2.DLL с использованием lib2.obj и lib1.lib / lib1.exp

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

Устаревшая цепочка инструментов выполняет следующие вызовы:

# compile sources
cl lib1\SRC\lib1help.cpp ... /Fo"build\cl\lib1.obj"
cl lib2\SRC\lib2help.cpp ... /Fo"build\cl\lib2.obj"

# create lib + exp symbols
lib /DEF build\cl\lib1.obj /OUT:build\link1\lib1.lib
lib /DEF build\cl\lib2.obj /OUT:build\link1\lib2.lib

# create mutual dependant dll using exp
link build\cl\lib1.obj build\link1\lib2.lib /DLL /OUT:build\link2\lib1.dll 
link build\cl\lib2.obj build\link1\lib1.lib /DLL /OUT:build\link2\lib2.dll

На данный момент у меня есть следующий CmakeLists.txt:

add_library(lib2 SHARED lib2/src/lib2help.cpp)
add_library(lib1 SHARED lib1/src/lib1help.cpp)

target_include_directories(lib1 PUBLIC lib1/include/)
target_compile_definitions(lib1 PRIVATE __LIB1)
target_link_libraries(lib1 PRIVATE lib2)

target_include_directories(lib2 PUBLIC lib2/include/)
target_compile_definitions(lib2 PRIVATE __LIB2)
target_link_libraries(lib2 PRIVATE lib1)

Это дает мне следующий результат:

[cmake] CMake Error: The inter-target dependency graph contains the following strongly connected component (cycle)  
[cmake]   "lib2" of type SHARED_LIBRARY  
[cmake]     depends on "lib1" (weak)  
[cmake]   "lib1" of type SHARED_LIBRARY  
[cmake]     depends on "lib2" (weak)  

Ребята, вы знаете, как я мог бы реализовать это с помощью Cmake?
Пока я планирую ориентироваться только на системы Windows, но независимость от ОС будет потрясающей!

Спасибо

1 Ответ

0 голосов
/ 22 сентября 2019

Я был настолько увлечен созданием библиотеки SHARED, что не стал изучать STATIC + SHARED.Спасибо @ arrowd и @ tsyvaref за предложение.

Я получил его, используя следующий CmakeLists.txt

add_library(lib1_obj OBJECT src/lib1help.cpp)
target_include_directories(lib1_obj PUBLIC include/)
target_include_directories(lib1_obj PRIVATE $<TARGET_PROPERTY:lib2_obj,INCLUDE_DIRECTORIES>)
target_compile_definitions(lib1_obj PRIVATE __LIB1)

add_library(lib1_static STATIC $<TARGET_OBJECTS:lib1_obj>)
target_link_libraries(lib1_static PUBLIC lib2_static)
set_target_properties(lib1_static PROPERTIES STATIC_LIBRARY_OPTIONS "/DEF") 
set_target_properties(lib1_static PROPERTIES OUTPUT_NAME lib1)

add_library(lib1_shared SHARED $<TARGET_OBJECTS:lib1_obj>)
target_link_libraries(lib1_shared PRIVATE lib1_static)
set_target_properties(lib1_shared PROPERTIES RUNTIME_OUTPUT_NAME lib1)

add_library(lib1 ALIAS lib1_shared) 

Точноетот же файл используется для lib2, за исключением, конечно, переключения имен.Я не уверен, что это лучший способ, но я достаточно счастлив на данный момент.Вот что происходит:

  • Компиляция источников в библиотеку OBJECT
  • Свяжите взаимозависимые библиотеки как статические, с "/ DEF" для создания файла экспорта
  • Переименуйте вывод статических библиотек, чтобы облегчить их использование для компоновщика
  • Связать совместно используемую библиотеку с помощью предварительно созданных .obj, .lib и .exp
  • Переименуйте упрощенную библиотеку DLL, чтобы ее было проще использовать

Здесь мы можем увидеть содержимое каждой библиотеки DLL, используя Dependency Walker : enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...