You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

迁移至CMake后出现重复构建,如何避免并提升构建速度?

问题:CMake构建时重复编译库导致速度缓慢

我正在给一个原本使用waf作为构建系统的库添加CMake支持,但编写的CMake代码构建速度远慢于原waf构建系统,经排查发现核心问题:

我的CMake代码中库与可执行文件的定义大致如下:

# USE_PACKAGES 是包含已加载库(如Boost::serialization)的变量
add_library(library_a SHARED)
target_sources(library_a PUBLIC ${LIBRARY_A_SOURCES})
target_link_libraries(library_a PRIVATE ${USE_PACKAGES})

add_library(library_b SHARED)
target_sources(library_b PUBLIC ${LIBRARY_B_SOURCES})
target_link_libraries(library_b PRIVATE ${USE_PACKAGES} library_a)

add_executable(executable)
target_sources(executable PUBLIC ${EXECUTABLE_SOURCES})
target_link_libraries(executable PRIVATE ${USE_PACKAGES} library_a library_b)

生成Makefile后执行make && make install时,发现make会重复构建库:

  • 先构建library_a
  • 构建library_b时,会同时编译library_b的源码和library_a的源码(明明library_a已经完成编译)
  • 构建可执行文件时,又会重复编译executable、library_b和library_a的源码

例如,若LIBRARY_A_SOURCES包含library_a/library_a_foo.cxx,library_b包含library_b_bar.cxx,构建library_b时日志先显示Building CXX Object library_b/library_b_bar.cxx,随后又显示Building CXX Object library_a/library_a_foo.cxx,但该文件在构建library_a阶段已经编译完成。

曾尝试修改可见性,将PRIVATE改为PUBLIC,但并未改变该行为,想知道如何让每个库仅构建一次?


解决方案

1. 修正target_sources的可见性(核心修复)

你当前用PUBLIC标记库的源码文件,这会导致所有依赖该库的下游目标(如library_b、executable)都会把这些源码纳入自身的构建流程,这就是重复编译的根本原因。

将库的target_sources从PUBLIC改为PRIVATE(源码文件),如果是需要对外暴露的头文件则用INTERFACE或PUBLIC:

add_library(library_a SHARED)
# 源码文件用PRIVATE,仅当前目标编译;头文件若需对外暴露可单独用PUBLIC/INTERFACE
target_sources(library_a PRIVATE ${LIBRARY_A_SOURCES})
target_link_libraries(library_a PRIVATE ${USE_PACKAGES})

add_library(library_b SHARED)
target_sources(library_b PRIVATE ${LIBRARY_B_SOURCES})
target_link_libraries(library_b PRIVATE ${USE_PACKAGES} library_a)

add_executable(executable)
target_sources(executable PRIVATE ${EXECUTABLE_SOURCES})
target_link_libraries(executable PRIVATE ${USE_PACKAGES} library_a library_b)

PUBLIC源码的语义是:当前目标编译这些文件,同时所有链接该目标的下游目标也会编译它们——这完全违背了库的复用逻辑,直接触发重复编译。

2. 排查USE_PACKAGES变量是否存在重复依赖

确认USE_PACKAGES中没有意外包含本项目内的library_a或library_b,如果这个变量混入了项目内部目标,会导致依赖关系混乱,引发重复构建。

可以在CMake代码中添加输出语句排查:

message(STATUS "USE_PACKAGES内容: ${USE_PACKAGES}")

3. 清理构建目录,避免缓存干扰

旧的构建缓存可能导致异常行为,完全清理后重新构建:

rm -rf build/
mkdir build && cd build
cmake ..
make && make install

4. 验证依赖关系是否正确

用CMake生成依赖图,检查目标间的依赖是否符合预期:

cmake --graphviz=depends.dot ..

生成的depends.dot文件可以用Graphviz工具可视化,确认library_b和executable仅依赖library_a目标,而非重复引入其源码。


内容的提问来源于stack exchange,提问作者Bharath Radhakrishnan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 03:43:13