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

使用CMake ExternalProject构建项目时链接耗时过长问题排查

问题描述

我正尝试基于CMake构建一个简单的C++项目,该项目依赖Spdlog库。需求是将依赖库本地存放在源码旁,每次构建应用时可同时编译依赖库,既能随时升级库版本,也能在无网络时不依赖远程仓库,且仅在删除build目录时才重新编译依赖库,无需每次清理项目后都重新编译。

项目结构

├── CMakeLists.txt
├── inc/
│   ├── main.h
├── lib/
│   ├── spdlog/
│   │   ├── CMakeLists.txt
│   │   ├── include/
│   │   │   └── spdlog/
│   │   │       ├── spdlog.h
│   │   │       ├── ...
│   │   ├── src/
│   │   │   ├── ...
│   │   ├── tests/
│   │   │   ├── ...
│   │   ├── CMakeLists.txt
│   │   ├── ...
├── src/
│   ├── main.cpp
└── build/

main.cpp代码

#include <iostream>
#include <spdlog/spdlog.h>

int main()
{
    spdlog::info("Hello , World!");

    return 0;
}

现有CMake脚本

cmake_minimum_required(VERSION 3.10)
project(MyProjec)

set(CMAKE_VERBOSE_MAKEFILE ON)

# Add ExternalProject_Add for spdlog
include(ExternalProject)
ExternalProject_Add(spdlog_external
    PREFIX ${CMAKE_BINARY_DIR}/spdlog
    SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lib/spdlog
    BINARY_DIR ${CMAKE_BINARY_DIR}/spdlog_build
    INSTALL_COMMAND ""
    CMAKE_ARGS -DSPDLOG_BUILD_SHARED=ON  # Adjust options as needed
               -DSPDLOG_BUILD_STATIC=OFF
               -DCMAKE_INSTALL_PREFIX=${CMAKE_BINARY_DIR}/spdlog_install
    BUILD_COMMAND ${CMAKE_COMMAND} --build . --target install && ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/lib/spdlog/include ${CMAKE_BINARY_DIR}/spdlog_build/include
)

# Set the include directory for the main project
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/inc)
include_directories(${CMAKE_BINARY_DIR}/spdlog_build/include)

# Set the source files for the main project
set(SOURCES
    src/main.cpp
)

# Set the header files for the main project
set(HEADERS
    inc/main.h
)

# Create the executable for the main project
add_executable(MyProjec ${SOURCES} ${HEADERS})

# Specify the include directories for the executable
target_include_directories(MyProjec PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/inc ${CMAKE_BINARY_DIR}/spdlog_build/include)

# Ensure spdlog is built before building the main project
add_dependencies(MyProjec spdlog_external)

# Get the spdlog library path
ExternalProject_Get_Property(spdlog_external BINARY_DIR)
set(SPDLOG_LIB_DIR ${BINARY_DIR})
set(SPDLOG_INCLUDE_DIR ${BINARY_DIR}/include)

# Link the spdlog library to the main project
if (UNIX)
    target_link_libraries(MyProjec PRIVATE ${SPDLOG_LIB_DIR}/libspdlog.so)
else()
    target_link_libraries(MyProjec PRIVATE ${SPDLOG_LIB_DIR}/spdlog.dll)
endif()

当前问题:Spdlog可正常编译,CMake也能将头文件复制到对应目录,但每次构建应用(哪怕仅对main.cpp做简单修改)时,链接步骤耗时过长(普通笔记本约60秒),询问CMake脚本是否存在问题。


问题分析与修复方案

核心问题

你的CMake脚本存在两个关键问题导致链接耗时过长:

  • 手动复制头文件触发不必要的依赖:BUILD_COMMAND里的copy_directory操作会在每次构建时执行,导致spdlog_external目标被重新触发,间接让链接步骤重复执行不必要的操作。
  • 直接链接.so/.dll文件而非CMake目标:手动指定库文件路径没有利用CMake的依赖追踪机制,无法正确识别库是否已更新,导致每次都重新链接。

修复后的CMake脚本

cmake_minimum_required(VERSION 3.10)
project(MyProjec)

set(CMAKE_VERBOSE_MAKEFILE ON)

# 控制spdlog的编译选项(需在add_subdirectory前设置)
set(SPDLOG_BUILD_SHARED ON CACHE BOOL "Build shared library" FORCE)
set(SPDLOG_BUILD_STATIC OFF CACHE BOOL "Build static library" FORCE)

# 直接引入本地spdlog库,替代ExternalProject
add_subdirectory(lib/spdlog)

# 设置主项目源文件
set(SOURCES
    src/main.cpp
)

set(HEADERS
    inc/main.h
)

add_executable(MyProjec ${SOURCES} ${HEADERS})

# 指定主项目的包含目录
target_include_directories(MyProjec PUBLIC 
    ${CMAKE_CURRENT_SOURCE_DIR}/inc
)

# 直接链接spdlog的CMake目标,自动处理依赖和路径
target_link_libraries(MyProjec PRIVATE spdlog::spdlog)

修复说明

  1. 用add_subdirectory替代ExternalProject_Add:

    • 本地依赖库直接通过add_subdirectory引入,CMake会自动处理spdlog的构建流程,仅在spdlog源码或配置变更时才重新编译,完全符合你“仅删除build目录才重新编译依赖”的需求。
    • 无需手动复制头文件,spdlog的CMake配置已经自动导出了包含目录,通过链接目标时会自动传递包含路径。
  2. 链接CMake目标而非直接库文件:

    • spdlog::spdlog是spdlog提供的官方CMake目标,链接它会自动处理库路径、包含目录、编译选项等,CMake能精准追踪库的更新状态,只有当库本身变化时才会重新链接,避免不必要的耗时操作。
  3. 简化编译选项设置:

    • 在add_subdirectory前设置spdlog的缓存变量,直接控制其编译模式,无需在ExternalProject里传递复杂参数。

额外优化建议

如果需要隔离依赖的构建目录(比如不想让spdlog的build文件混在主项目build里),可以添加以下配置:

# 自定义spdlog的构建目录
set(SPDLOG_BUILD_DIR ${CMAKE_BINARY_DIR}/spdlog_build)
add_subdirectory(lib/spdlog ${SPDLOG_BUILD_DIR})

内容的提问来源于stack exchange,提问作者Mahmoud Hosseinipour

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 06:42:33