I’m using FetchContent to manage third-party dependencies, and I ran into an issue when trying to deduplicate the sub-builds generated for different build configurations. Below is a minimal working example that replicates the issue:
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})
This is combined with CMake presets in the following way:
{
"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
}
]
}
The intended result is that FetchContent downloads and unpacks the sources to a shared location, since this is meant to be agnostic to the project build configuration, and the build output is then directed to a subfolder corresponding to the CMake preset (thus we would separate 32 and 64 bit builds, debug from release, etc.)
When I open this in Visual Studio with a clean project (i.e nothing was generated yet), the initial configuration (e.g 32 bit) works correctly, no errors. Once I switch to a different configuration, I get the following error:
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.
This appears to be due to a conflict with the architecture strategy setting in CMakePresets. If I change it from “set” to “external”, I don’t get the error when switching presets, instead CMake just cancels generation.
How can I make the FetchContent source and sub-build location agnostic to the build configuration, assuming it is possible?