【问题标题】:How to prevent CMake from double compiling sources when bundling static C++ libraries?捆绑静态 C++ 库时如何防止 CMake 双重编译源?
【发布时间】:2022-01-09 11:28:01
【问题描述】:

我正在尝试使用 CMake 构建静态库 libbarlibbar 应该包含 libfoo,即子目录目标 libfoo 中的所有目标文件也应该出现在 libbar 中。最简单的目录树如下:

bar
├── bar.cpp
├── CMakeLists.txt
└── foo
    ├── CMakeLists.txt
    └── foo.cpp

这里是foo/CMakeLists.txt

cmake_minimum_required(VERSION 3.14)
project(foo)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_library(foo)
target_sources(foo PUBLIC foo.cpp)

这里是顶级CMakeLists.txt

cmake_minimum_required(VERSION 3.14)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

project(bar)

add_library(bar)
add_subdirectory(foo)
target_sources(bar PUBLIC bar.cpp)
target_link_libraries(bar PRIVATE foo)

bar/ 我执行以下操作:

cmake . -Bbuild
cd build
cmake --build .

我明白了

Scanning dependencies of target foo
[ 20%] Building CXX object foo/CMakeFiles/foo.dir/foo.cpp.o
[ 40%] Linking CXX static library libfoo.a
[ 40%] Built target foo
Scanning dependencies of target bar
[ 60%] Building CXX object CMakeFiles/bar.dir/bar.cpp.o
[ 80%] Building CXX object CMakeFiles/bar.dir/foo/foo.cpp.o
[100%] Linking CXX static library libbar.a
[100%] Built target bar

如您所见,文件 foo.cpp 被编译了两次,我正试图摆脱这种行为。顺便说一句,这个方法给了我一个正确的结果:

$ ar t libbar.a 
bar.cpp.o
foo.cpp.o

如果我在foo/CMakeLists.txt把PUBLIC改成PRIVATE,构建日志如下:

Scanning dependencies of target foo
[ 25%] Building CXX object foo/CMakeFiles/foo.dir/foo.cpp.o
[ 50%] Linking CXX static library libfoo.a
[ 50%] Built target foo
Scanning dependencies of target bar
[ 75%] Building CXX object CMakeFiles/bar.dir/bar.cpp.o
[100%] Linking CXX static library libbar.a
[100%] Built target bar

但是 foo.cpp.o 没有进入 libbar

$ ar t libbar.a 
bar.cpp.o

在没有双重编译的情况下构建包含 libfoolibbar 的正确方法是什么?

【问题讨论】:

    标签: c++ cmake static


    【解决方案1】:

    target_sources(foo PUBLIC foo.cpp)

    此行强制链接到foo 的目标将foo.cpp 包含在其来源中。

    在没有双重编译的情况下构建包含 libfoo 的 libbar 的正确方法是什么?

    你已经明确要求这个,所以只是......不要:

    target_sources(foo PRIVATE foo.cpp)
    
    • PUBLIC 表示“适用于自己和被链接者”。
    • PRIVATE 表示“适用于自己”
    • INTERFACE 表示“仅适用于被链接者”

    如果您真的希望 foo.o 出现在两个档案中(这很可疑),那么您可以使用 OBJECT 库,libbarlibfoo 都链接到该库。

    add_library(foo_objs OBJECT foo.cpp)
    
    # later ...
    target_link_libraries(foo PRIVATE foo_objs)
    # ...
    target_link_libraries(bar PRIVATE foo_objs)
    

    【讨论】:

    • 我的问题中描述的案例是真实案例的简化模型。我有一个库,我们称它为 libfoo,它在许多项目中使用并作为子模块拉取。我的同事要求我提供一个库 libbar。我写的高度依赖于libfoo,但是它们不需要两个库,所以我决定将libfoo合并到libbar中。因此,在我当前的项目中,我根本不需要构建 libfoo,只需要包含所有内容的 libbar。谢谢,我会检查 OBJECT 库。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多