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

使用CMake ExternalProject引入SQLite3时清理后重构建的问题

解决CMake ExternalProject构建SQLite3时clean后重复编译的问题

我通过CMake的ExternalProject模块引入SQLite3,使用Ninja作为构建后端。现在遇到的问题是:每次执行clean操作后,SQLite3都要重新构建,严重拖慢了构建速度。实际上除非SQLite3版本更新,否则只需要构建一次即可。

我本来打算写个包装脚本,把libsqlite3.a复制到项目根目录的/cache目录,检测到该文件就直接复制到指定位置,不用重新调用make。但想知道CMake是否有内置机制实现这个需求?

原ExternalProject配置代码

ExternalProject_Add(
  sqlite3
  URL https://www.sqlite.org/2024/sqlite-src-3460100.zip
  URL_HASH SHA3_256=23fdf1ebc809971e73fa7875c1cc9f854f4c2274446f4f4a18c9fa2ec6cae12e
  CONFIGURE_COMMAND <INSTALL_DIR>/src/sqlite3/configure
  BUILD_COMMAND make
  INSTALL_COMMAND cmake -E echo "Skipping install step."
  BUILD_IN_SOURCE 1
  # Note that normally there should be a /bld/ subdir preceeding .libs, the object files seem to
  # be generated right along source files. It is not a problem, however.
  BUILD_BYPRODUCTS <INSTALL_DIR>/src/sqlite3/.libs/libsqlite3.a
)

ExternalProject_Get_Property(sqlite3 install_dir)

add_library(sqlite3-lib STATIC IMPORTED)
add_dependencies(sqlite3-lib sqlite3)

set_target_properties(sqlite3-lib PROPERTIES
  IMPORTED_LOCATION ${install_dir}/src/sqlite3/.libs/libsqlite3.a
)

add_dependencies(MyProject sqlite3-lib)

原FetchContent配置代码(曾能保留库但Ninja报错)

FetchContent_Declare(
  sqlite3
  URL https://www.sqlite.org/2024/sqlite-src-3460100.zip
  URL_HASH SHA3_256=23fdf1ebc809971e73fa7875c1cc9f854f4c2274446f4f4a18c9fa2ec6cae12e
  DOWNLOAD_EXTRACT_TIMESTAMP true
)
FetchContent_MakeAvailable(sqlite3)

set(SQLITE3_LIB "${sqlite3_SOURCE_DIR}/bld/.libs/libsqlite3.a")

if(NOT EXISTS ${SQLITE3_LIB})
  add_custom_target(build_sqlite3
    COMMAND ${CMAKE_COMMAND} -E make_directory "${sqlite3_SOURCE_DIR}/bld"

    COMMAND ${CMAKE_COMMAND} -E chdir "${sqlite3_SOURCE_DIR}/bld" ${sqlite3_SOURCE_DIR}/configure
    COMMAND ${CMAKE_COMMAND} -E chdir "${sqlite3_SOURCE_DIR}/bld" make

    DEPENDS ${sqlite3_SOURCE_DIR}/configure
  )
else()
  add_custom_target(build_sqlite3)
endif()

add_library(sqlite3 STATIC IMPORTED)

set_target_properties(sqlite3 PROPERTIES
  IMPORTED_LOCATION "${SQLITE3_LIB}"
  INTERFACE_INCLUDE_DIRECTORIES "${sqlite3_SOURCE_DIR}"
)

add_dependencies(MyProject build_sqlite3)

CMake内置解决方案:将外部项目产物存到独立缓存目录

CMake本身提供了机制避免这个问题——核心是让ExternalProject(或FetchContent)的源码和构建产物脱离当前构建目录,这样执行clean时不会删除这些缓存内容。

修改后的ExternalProject配置

# 定义SQLite3的缓存目录,放在项目根目录下,与构建目录分离
set(SQLITE3_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache/sqlite3")

ExternalProject_Add(
  sqlite3
  URL https://www.sqlite.org/2024/sqlite-src-3460100.zip
  URL_HASH SHA3_256=23fdf1ebc809971e73fa7875c1cc9f854f4c2274446f4f4a18c9fa2ec6cae12e
  # 指定缓存相关路径,避免被clean操作删除
  PREFIX "${SQLITE3_CACHE_DIR}"
  SOURCE_DIR "${SQLITE3_CACHE_DIR}/src"
  BINARY_DIR "${SQLITE3_CACHE_DIR}/build"
  CONFIGURE_COMMAND "${SQLITE3_CACHE_DIR}/src/configure"
  BUILD_COMMAND make
  INSTALL_COMMAND cmake -E echo "Skipping install step."
  # 使用独立构建目录,更规范且避免源码目录污染
  BUILD_BYPRODUCTS "${SQLITE3_CACHE_DIR}/build/.libs/libsqlite3.a"
)

ExternalProject_Get_Property(sqlite3 binary_dir)

add_library(sqlite3-lib STATIC IMPORTED)
add_dependencies(sqlite3-lib sqlite3)

set_target_properties(sqlite3-lib PROPERTIES
  IMPORTED_LOCATION "${binary_dir}/.libs/libsqlite3.a"
  INTERFACE_INCLUDE_DIRECTORIES "${SQLITE3_CACHE_DIR}/src"
)

add_dependencies(MyProject sqlite3-lib)

配置优势

  • 缓存目录${CMAKE_SOURCE_DIR}/.cache/sqlite3不受构建目录clean操作影响,产物会永久保留
  • 只有当SQLite3的URL或HASH值变更时,才会触发重新下载和构建
  • 无需额外脚本,完全依赖CMake内置机制实现

修复后的FetchContent配置(解决Ninja报错)

之前FetchContent的问题在于依赖追踪不严谨,且源码默认放在构建目录下。修改后可以同时保留缓存能力和适配Ninja:

set(SQLITE3_CACHE_DIR "${CMAKE_SOURCE_DIR}/.cache/sqlite3")

FetchContent_Declare(
  sqlite3
  URL https://www.sqlite.org/2024/sqlite-src-3460100.zip
  URL_HASH SHA3_256=23fdf1ebc809971e73fa7875c1cc9f854f4c2274446f4f4a18c9fa2ec6cae12e
  DOWNLOAD_EXTRACT_TIMESTAMP true
  # 指定源码到缓存目录,脱离构建目录
  SOURCE_DIR "${SQLITE3_CACHE_DIR}/src"
)
FetchContent_MakeAvailable(sqlite3)

set(SQLITE3_BUILD_DIR "${SQLITE3_CACHE_DIR}/build")
set(SQLITE3_LIB "${SQLITE3_BUILD_DIR}/.libs/libsqlite3.a")

# 用add_custom_command生成库文件,让CMake正确追踪依赖关系,解决Ninja报错
add_custom_command(
  OUTPUT "${SQLITE3_LIB}"
  COMMAND ${CMAKE_COMMAND} -E make_directory "${SQLITE3_BUILD_DIR}"
  COMMAND ${CMAKE_COMMAND} -E chdir "${SQLITE3_BUILD_DIR}" "${SQLITE3_CACHE_DIR}/src/configure"
  COMMAND ${CMAKE_COMMAND} -E chdir "${SQLITE3_BUILD_DIR}" make
  DEPENDS "${SQLITE3_CACHE_DIR}/src/configure"
  COMMENT "Building SQLite3 library"
)

add_custom_target(build_sqlite3 ALL DEPENDS "${SQLITE3_LIB}")

add_library(sqlite3 STATIC IMPORTED)
add_dependencies(sqlite3 build_sqlite3)

set_target_properties(sqlite3 PROPERTIES
  IMPORTED_LOCATION "${SQLITE3_LIB}"
  INTERFACE_INCLUDE_DIRECTORIES "${SQLITE3_CACHE_DIR}/src"
)

add_dependencies(MyProject sqlite3)

修复点说明

  • 将SQLite3源码放到项目根目录的缓存目录,避免clean时被删除
  • 用add_custom_command替代条件判断,让CMake明确库文件的生成规则,Ninja能正确识别依赖
  • ALL关键字确保build_sqlite3目标在默认构建流程中自动执行

内容的提问来源于stack exchange,提问作者Maciej Kravchyk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 02:00:56