使用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
相关产品推荐
相关产品推荐

