c++ - 允许在 Cmake 中相互依赖

标签 c++ cmake linker

我正在尝试将大量代码从自定义内部工具链迁移到 Cmake。此代码由许多共享库和一些可执行文件组成。

其中一些库是相互依赖的。我们以 Lib1 和 Lib2 为例,其中 Lib1 使用 Lib2 的符号,而 Lib2 使用 Lib1 的符号。
为了创建 Lib1 DLL,我们需要从 Lib2 导出符号,而 Lib2 又需要从 Lib1 导出符号。目前我们通过分两个阶段链接解决了这个问题,如下所述:Mutual Imports ).这为我们提供了以下步骤:

  1. 创建 lib1.lib 和 lib1.exp
    创建 lib2.lib 和 lib2.exp
  2. 使用 lib1.obj 和 lib2.lib/lib2.exp 创建 lib1.DLL
    使用 lib2.obj 和 lib1.lib/lib1.exp 创建 lib2.DLL

我知道这是一种代码味道,但代码库太大,无法尝试纠正所有这些循环。所以我想使用 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 系统,但操作系统不可知论者会很棒!

谢谢

最佳答案

我太专注于制作一个 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 以便于使用

这里我们可以使用Dependency Walker查看每个DLL的内容: enter image description here

关于c++ - 允许在 Cmake 中相互依赖,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58043280/

相关文章:

c++ - 在 .cpp 和 .h 中包含 header 的区别

c++ - 使用 Visual C++ 环境和 "Asm"关键字作为 Assembler IDE 的替代方案?

c++ - 为什么 GCC 和 Clang 不做这种别名优化?

c++ - 在 CMake 中混合 C 和 C++,什么是 CMakeCCompilerId.c 以及如何丢弃它

cmake - 将二进制文件放在 CMake 的何处?

c++ - Mac OSX 下的 TCHAR 和 _tprintf

c++ - 使用 qmake 执行 shell 命令

linux - -fprofile-arcs 链接器选项是什么意思?

c - gcc 在 Cygwin 中失败并显示 "undefined reference",但引用存在于链接库中

c++ - 消除未使用的虚函数