首页 > 解决方案 > 将 CMake 对象库与共享库相结合

问题描述

我有以下 CMakeLists.txt 根据对象库定义一个对象库和一个共享库,如下所示:

add_library(foo OBJECT 
  foo.cpp
)

add_library(bar SHARED 
  bar.cpp
  $<TARGET_OBJECTS:foo>
)

add_executable(baz baz.cpp)
target_link_libraries(baz
  PUBLIC bar
)

链接时出现以下链接器错误baz

/usr/bin/ld: CMakeFiles/foo.dir/foo.cpp.o: relocation R_X86_64_PC32 against symbol `_ZSt4cout@@GLIBCXX_3.4' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value

这是因为foo.cpp不是用-fPIC( bar.cppis) 构建的。这可以通过添加来解决:

set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE ON)

这是解决此问题的正确方法吗?在我看来,应该有一个更清洁的解决方案。我觉得 CMake 在这里可以更聪明,并且看到来自的对象foo仅在需要的上下文中-fPIC使用。我正在使用 CMake 3.11。

一些上下文;在我们的项目中,我们需要从分散在不同目录中的大量资源构建一个共享库。现在,我们为每个目录创建单独的共享库。这些库中的大多数都依赖于 Bison 源,而这些源在幕后依赖于add_custom_command构建。这引入了库之间的编译时间依赖性,严重限制了我们可以并行化构建的程度(参见:https ://gitlab.kitware.com/cmake/cmake/issues/15555 )。

然后用于构建共享库的每个目录的对象库似乎是解决此问题的好方法。

标签: c++cmake

解决方案


这是解决此问题的正确方法吗?

是的。

由于bar(shared) 与foo(static) 链接,两者都bar必须foo使用与位置无关的代码进行编译。

CMake 知道bar是一个共享库,并且默认启用与位置无关的代码。但是由于foo它是一个静态对象,即使它可以猜测它需要是 PIC 1,它默认不会为 PIC 启用 PIC foo

根据 SO 的问题What is the idiomatic way in CMAKE 添加 -fPIC 编译器选项?

您可以在所有目标上设置与位置无关的代码属性:

set(CMAKE_POSITION_INDEPENDENT_CODE ON)

或在特定库中:

add_library(lib1 SHARED lib1.cpp)
set_property(TARGET lib1 PROPERTY POSITION_INDEPENDENT_CODE ON)

参考:CMAKE_POSITION_INDEPENDENT_CODE cmake 构建系统


1)这可能是一个建议的功能,也许它已经是。


推荐阅读