一个 CMake 目标可以链接到另一个库目标的 *共享* 版本吗?

Nic*_*asM 5 c++ cmake

我有一个项目,其中包含一个核心库(LibA在下面的示例中)、一个可执行文件和一个LibB依赖于第一个库的第二个库 ( )。第二个库 ( LibB) 始终以共享(动态库)形式构建。

有什么办法,我可以强制LibB永远压连杆共享的版本LibA

这是一个CMakeLists.txt说明问题的小文件:

cmake_minimum_required(VERSION 3.16)

project(my_project LANGUAGES CXX)

# LibA should be buildable in either static or shared form.
add_library(LibA A.cpp)
# In the real case, there are many customizations to `LibA`: 
# compile flags, include dirs, target properties, etc.

add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibA)

# I want library myB to *always* link against the dynamic library libLibA.so.
add_library(LibB SHARED B.cpp)
target_link_libraries(LibB PUBLIC LibA m pthread)
Run Code Online (Sandbox Code Playgroud)

它可以使用以下命令构建:

echo 'int main() {}' > main.cpp
touch A.cpp B.cpp
mkdir -p build 
cmake -B build/ -S .
cmake --build build/
Run Code Online (Sandbox Code Playgroud)

我知道我可以强制LibA始终与 共享add_library(LibA SHARED A.cpp),但我希望能够构建LibA为静态库。

真正的背景是我有一个核心库 ( LibA),并希望在创建可执行文件时静态链接它,但LibA.so在创建 Python 扩展模块 ( LibB.so)时动态链接它(作为)。

jpo*_*o38 5

这是不可能的,libA只能是静态的或动态的,不能两者兼而有之。

您需要有两个版本libA,一个是动态的,一个是静态的:

cmake_minimum_required(VERSION 3.16)

project(my_project LANGUAGES CXX)

function( addLibA suffix type )

    set( libname LibA${suffix} )
    add_library(${libname} ${type} A.cpp)

    # specify library properties here

endfunction()

# LibA should be buildable in either static or shared form.
addLibA("s" STATIC)
addLibA("" SHARED)
# In the real case, there are many customizations to `LibA`: 
# compile flags, include dirs, target properties, etc.

add_executable(ExecutableA main.cpp)
target_link_libraries(ExecutableA LibAs)

# I want library myB to *always* link against the dynamic library libLibA.so.
add_library(LibB SHARED B.cpp)
target_link_libraries(LibB PUBLIC LibA m pthread)
Run Code Online (Sandbox Code Playgroud)


Hum*_*ler 5

正如评论/ jpo38 的答案中提到的,您具体要求的内容将需要多个目标

但是,您可能有兴趣使用 CMake 的对象库来在库目标和可执行目标之间共享对象。例如:

cmake_minimum_required(VERSION 3.16)

project(my_project LANGUAGES CXX)

# Objects get built exactly once
add_library(LibA.objects OBJECTS 
  A.cpp
)
target_compile_commands( ... )
target_include_directories( ... )

# Shared library for libA
add_library(LibA SHARED
  $<OBJECTS:LibA.objects>
)

# LibB -- always shared, always linked against dynamic LibA
add_library(LibB SHARED
  B.cpp
)
target_link_libraries(LibB PUBLIC LibA)

# ExecutableA, built using LibA's objects 
# (effectively the same linking a static LibA.a)
add_executable(ExecutableA
  main.cpp
  $<OBJECTS:LibA.objects>
)
Run Code Online (Sandbox Code Playgroud)

使用对象库,您的对象只需构建一次,即可在多个目标之间共享。另一方面,使用多个库目标将强制重建每个对象,因为每个目标可能使用不同的编译命令。

这允许ExecutableALibAs 对象内置到其中,因此它的行为就像在LibA.a. 在这种情况下,LibA现在已SHARED明确构建为库,因为这是LibB动态链接所需的。

如果您使用的是较新版本的 CMake,您还可以避免使用$<OBJECTS:...>生成器表达式,而只需直接链接到对象库target_link_libraries- 例如:

target_link_libraries(libA PRIVATE LibA.objects)
...
target_link_libraries(ExecutableA PRIVATE LibA.objects)
Run Code Online (Sandbox Code Playgroud)

这种方法还允许将属性一次性应用到各自的目标。有关源文件本身的任何属性只需要直接应用于对象库。有关库设置/布局的任何属性(例如输出位置、后缀等)都严格适用于库目标。