Cmake:使用来自另一个目标的函数而没有直接的target_link_libraries

时间:2017-09-05 03:08:57

标签: c++ cmake

这是一个奇怪的问题。我有一个"渲染器前端"静态目标和几个"渲染器后端"静态目标。 "渲染器前端"包含后端需要实现的头文件,前端的代码将调用它们。后端通过调用底层相应的API(例如,OpenGL或DirectX)来实现这些功能。

到目前为止,这么好。我可以在编译时选择后端并将其链接到前端。但是,我决定在前端添加单元测试,这需要一个"虚拟后端"而不是为主程序配置的后端。

所以不要这样做:

if(${RendererBackend} STREQUAL "OpenGL")
    target_link_libraries(Renderer RendererBackendGL)
elseif(...)
    ...
end
target_link_libraries(Application Renderer)

我想这样做:

target_link_libraries(Application Renderer)
target_link_libraries(RendererTest Renderer RendererBackendDummy)
if(${RendererBackend} STREQUAL "OPENGL")
    target_link_libraries(Application RendererBackendGL)
elseif(...)
    ...
end

但是,我的程序有"未定义的引用"每当渲染器前端调用由GCC下的后端实现的函数时,链接错误。该程序在MSVC下运行良好。

编辑:

我检查了链接命令,它是这样的:

/usr/bin/g++ CMakeFiles/Demo.dir/src/main.cpp.o  -o Demo -rdynamic -lm -ldl /usr/lib/x86_64-linux-gnu/libX11.so -lpthread ../Engine/OpenGL/libRendererBackendGL.a ../Engine/Graphics/libRenderer.a

问题是"渲染器"在" RendererBackendGL"。

中定义的库调用函数

1 个答案:

答案 0 :(得分:3)

您的依赖项建模不正确。

如果Renderer调用RendererBackendGL中的函数,则需要在CMake中建模该关系:

target_link_libraries(Renderer PUBLIC RendererBackendGL)
target_link_libraries(Application PRIVATE Renderer)

是的,这意味着每个链接到Renderer的人都需要链接到后端,包括测试。但这是您的软件架构的问题,即。在Renderer内调用了后端函数,而不是CMake的问题。

gcc中断的原因是链接器命令行上指定输入库的顺序很重要。对于MSVC来说情况并非如此(只要存在lib,它就会起作用,无论它是第一个还是最后一个)。由于此类顺序依赖性是特定于工具链的,因此实现此可移植性的唯一方法是通过在CMake中正确地建模所有目标间依赖关系。

那你现在可以做些什么来解决这个问题呢?我想到了一些选择:

  • 翻转依赖项。让后端依赖于前端,并且仅将应用程序链接到它想要使用的后端。
  • 转到插件概念。前端不是静态链接,而是在运行时动态加载它想要在共享库中使用的后端。
  • 在编译时选择特定的后端。这意味着,如果您仍然希望使用GL后端构建应用程序并使用虚拟后端作为同一构建步骤的一部分进行测试,则需要构建前端两次。这可能是最接近您目前尝试的方法。您可以使用object libraries来最小化前端的重新编译量,但最终仍会有多个前端库目标。

请注意,所有这些都需要对代码进行一些架构更改。因此,在开始重构之前,请务必考虑所有影响。