捆绑静态C++库时如何防止CMake双重编译源?
How to prevent CMake from double compiling sources when bundling static C++ libraries?
我正在尝试使用 CMake 构建静态库 libbar。 libbar 应包含 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
在没有双重编译的情况下构建包含 libfoo 的 libbar 的正确方法是什么?
target_sources(foo PUBLIC foo.cpp)
此行强制 link 到 foo
的目标在其来源中包含 foo.cpp
。
What is the correct way to build libbar containing libfoo without double compilation?
您已明确要求这样做,所以...不要:
target_sources(foo PRIVATE foo.cpp)
PUBLIC
表示“适用于自己和 linkees”。
PRIVATE
表示“应用于自身”
INTERFACE
表示“仅适用于 linkees”
如果您真的希望 foo.o
出现在两个档案中(这是可疑的),那么您可以使用一个 OBJECT
库,其中 libbar
和 libfoo
link到.
add_library(foo_objs OBJECT foo.cpp)
# later ...
target_link_libraries(foo PRIVATE foo_objs)
# ...
target_link_libraries(bar PRIVATE foo_objs)
我正在尝试使用 CMake 构建静态库 libbar。 libbar 应包含 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
在没有双重编译的情况下构建包含 libfoo 的 libbar 的正确方法是什么?
target_sources(foo PUBLIC foo.cpp)
此行强制 link 到 foo
的目标在其来源中包含 foo.cpp
。
What is the correct way to build libbar containing libfoo without double compilation?
您已明确要求这样做,所以...不要:
target_sources(foo PRIVATE foo.cpp)
PUBLIC
表示“适用于自己和 linkees”。PRIVATE
表示“应用于自身”INTERFACE
表示“仅适用于 linkees”
如果您真的希望 foo.o
出现在两个档案中(这是可疑的),那么您可以使用一个 OBJECT
库,其中 libbar
和 libfoo
link到.
add_library(foo_objs OBJECT foo.cpp)
# later ...
target_link_libraries(foo PRIVATE foo_objs)
# ...
target_link_libraries(bar PRIVATE foo_objs)