CMake FetchContent与CMakePresets冲突:实现跨配置共享依赖
问题
在使用CMake开发C++项目时,通过FetchContent管理第三方依赖,希望实现依赖源码下载到共享位置(与构建配置无关),构建输出定向到对应CMake预设的子文件夹(区分32/64位、Debug/Release),但切换构建配置时遇到错误。
复现代码
CMakeLists.txt
cmake_minimum_required(VERSION 3.21) # Add application add_executable(FetchContentTest main.cpp) include(FetchContent) # Configure FetchContent set(FETCHCONTENT_QUIET off) set(BUILD_SHARED_LIBS ON) # Cache original FC base dir set(ORIGINAL_FC_DIR ${FETCHCONTENT_BASE_DIR}) # Redirect FC base dir to a shared location (instead of per-preset) get_filename_component(FC_NEW_BASE_DIR "../FetchContent" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}") set(FETCHCONTENT_BASE_DIR ${FC_NEW_BASE_DIR}) FetchContent_Declare( sdl2 URL https://github.com/libsdl-org/SDL/releases/download/release-2.24.0/SDL2-2.24.0.zip ) FetchContent_GetProperties(sdl2) if(NOT sdl2_POPULATED) FetchContent_Populate(sdl2) # Source stays in shared folder, while the build goes to the binary folder set(SDL_BINARY_DIR "${CMAKE_BINARY_DIR}/_deps/sdl2-build") add_subdirectory(${sdl2_SOURCE_DIR} ${SDL_BINARY_DIR}) set(SDL_LIBS SDL2main SDL2) target_link_libraries(FetchContentTest PRIVATE ${SDL_LIBS}) endif() # Reset FC base dir set(FETCHCONTENT_BASE_DIR ${ORIGINAL_FC_DIR})
CMakePresets.json
{ "version": 3, "cmakeMinimumRequired": { "major": 3, "minor": 21, "patch": 0 }, "configurePresets": [ { "name": "base", "hidden": true, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" }, "generator": "Visual Studio 17 2022", "binaryDir": "${sourceDir}/out/build/${presetName}", "cacheVariables": { "CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}", "CMAKE_CXX_COMPILER": "cl", "CMAKE_CONFIGURATION_TYPES": "Debug;Release" }, "warnings": { "dev": false }, "vendor": { "microsoft.com/VisualStudioSettings/CMake/1.0": { "hostOS": [ "Windows" ] } } }, { "name": "windows-x86", "inherits": "base", "architecture": { "value": "Win32", "strategy": "set" } }, { "name": "windows-x64", "inherits": "base", "architecture": { "value": "x64", "strategy": "set" } } ], "buildPresets": [ { "name": "windows-x64-debug", "configurePreset": "windows-x64", "configuration": "Debug", "cleanFirst": false }, { "name": "windows-x64-release", "configurePreset": "windows-x64", "configuration": "Release", "cleanFirst": false } ] }
错误信息
初始配置(如32位)可正常运行,但切换到其他配置时出现:
1> [CMake] CMake Error: Error: generator platform: x64 1> [CMake] Does not match the platform used previously: Win32 1> [CMake] Either remove the CMakeCache.txt file and CMakeFiles directory or choose a different binary directory.
若将architecture策略改为external,切换预设时无错误但CMake会取消生成。
解决方案
要实现依赖源码共享、构建输出按配置隔离,核心是让源码目录全局共用,同时为每个构建配置(架构、Debug/Release)分配独立的依赖构建目录,避免CMake缓存冲突。
步骤1:修改CMakeLists.txt,固定源码目录+隔离构建目录
无需修改FETCHCONTENT_BASE_DIR,直接通过FetchContent_Declare的SOURCE_DIR参数指定共享源码位置,再为每个配置生成唯一的构建目录:
cmake_minimum_required(VERSION 3.21) add_executable(FetchContentTest main.cpp) include(FetchContent) set(FETCHCONTENT_QUIET OFF) set(BUILD_SHARED_LIBS ON) # 所有构建配置共用的依赖源码根目录 set(SHARED_DEPS_ROOT "${CMAKE_SOURCE_DIR}/_shared_deps") set(FETCHCONTENT_SOURCE_DIR_SDL2 "${SHARED_DEPS_ROOT}/sdl2-src") FetchContent_Declare( sdl2 URL https://github.com/libsdl-org/SDL/releases/download/release-2.24.0/SDL2-2.24.0.zip SOURCE_DIR "${FETCHCONTENT_SOURCE_DIR_SDL2}" # 强制源码下载到共享位置 ) FetchContent_GetProperties(sdl2) if(NOT sdl2_POPULATED) FetchContent_Populate(sdl2) # 生成与当前构建配置绑定的依赖构建目录 set(SDL_BUILD_SUFFIX "") # 区分架构 if(CMAKE_SYSTEM_PROCESSOR) string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" SDL_ARCH_SUFFIX) set(SDL_BUILD_SUFFIX "${SDL_BUILD_SUFFIX}-${SDL_ARCH_SUFFIX}") endif() # 单配置生成器(如Ninja)区分Debug/Release if(NOT CMAKE_CONFIGURATION_TYPES) set(SDL_BUILD_SUFFIX "${SDL_BUILD_SUFFIX}-${CMAKE_BUILD_TYPE}") endif() set(SDL_BUILD_DIR "${CMAKE_BINARY_DIR}/_deps/sdl2-build${SDL_BUILD_SUFFIX}") add_subdirectory(${sdl2_SOURCE_DIR} ${SDL_BUILD_DIR}) target_link_libraries(FetchContentTest PRIVATE SDL2main SDL2) endif()
步骤2:保持CMakePresets原有配置
无需修改architecture.strategy(保持set即可),每个预设的binaryDir已经通过${presetName}隔离,依赖的构建目录会跟随主项目二进制目录,自动形成配置隔离。
关键说明
- 源码共享:通过
SOURCE_DIR强制FetchContent将依赖源码下载到项目根目录的_shared_deps下,所有构建配置共用一份源码,避免重复下载解压。 - 构建隔离:依赖的构建目录与主项目二进制目录绑定,并附加架构/配置后缀,确保32位/64位、Debug/Release的构建缓存完全独立,不会出现平台不匹配的错误。
- 对于Visual Studio这类多配置生成器,CMake会在依赖构建目录下自动生成Debug/Release子文件夹,无需手动处理;单配置生成器则通过
CMAKE_BUILD_TYPE区分。
内容的提问来源于stack exchange,提问作者yah_nosh
相关产品推荐
相关产品推荐

