将CMake对象库与共享库结合使用

Ton*_*vel 9 c++ 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
)
Run Code Online (Sandbox Code Playgroud)

链接时我收到以下链接器错误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
Run Code Online (Sandbox Code Playgroud)

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

set_property(TARGET foo PROPERTY POSITION_INDEPENDENT_CODE ON)
Run Code Online (Sandbox Code Playgroud)

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

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

每个目录的对象库随后用于构建共享库似乎是解决此问题的一个很好的解决方案.

YSC*_*YSC 6

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

是的.

由于bar(共享)对被链接foo(静态),两者的barfoo必须与位置无关的代码进行编译.

CMake know bar是一个共享库,默认情况下启用与位置无关的代码.但由于它foo是一个静态对象,即使它可能猜测它需要是PIC 1,它默认情况下不启用PIC foo.

根据SO的问题,CMAKE中添加-fPIC编译器选项的惯用方法是什么?

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

set(CMAKE_POSITION_INDEPENDENT_CODE ON)
Run Code Online (Sandbox Code Playgroud)

或在特定的图书馆:

add_library(lib1 SHARED lib1.cpp)
set_property(TARGET lib1 PROPERTY POSITION_INDEPENDENT_CODE ON)
Run Code Online (Sandbox Code Playgroud)

参考:CMAKE_POSITION_INDEPENDENT_CODE cmake构建系统


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

  • 请注意,`foo`不是静态库.它是CMake术语中的"OBJECT"库,实际上只是一组目标文件. (2认同)
  • "即使它可以猜测它需要是PIC" - 根据我的理解,CMake**永远不会**根据其*用法*尝试*猜测库属性.更可能的是**add_library(foo OBJECT SHARED ...)`用于通知CMake,该库的对象将用于SHARED库,因此与PIC相关的选项应该是相同的.(当编译**源时,PIC似乎是STATIC和SHARED库之间的唯一区别). (2认同)