Protobuf overrides user-specified CMAKE_MSVC_RUNTIME_LIBRARY on MSVC, making it impossible to force /MD in Debug
#23173 opened on Aug 16, 2025
Description
When building Protobuf as a static library on Windows with MSVC via CMake, Protobuf’s CMakeLists.txt unconditionally sets CMAKE_MSVC_RUNTIME_LIBRARY (e.g., to MultiThreaded$<$CONFIG:Debug:Debug>DLL), overriding a value explicitly set by the parent project. This makes it impossible to enforce /MD in all configurations (including Debug) from the parent, and leads to runtime-library mismatches (e.g., LNK2038 MDd_DynamicDebug vs MD_DynamicRelease) when the consumer must use /MD even for Debug.
Some SDKs/libraries ship only /MD-compatible binaries (even for Debug). Currently I need to force /MD globally. If Protobuf overrides CMAKE_MSVC_RUNTIME_LIBRARY, Debug builds of libprotobuf/Abseil end up with /MDd, causing link errors.
Expected behavior If the parent project explicitly sets CMAKE_MSVC_RUNTIME_LIBRARY (e.g., via cache/toolchain or before add_subdirectory/FetchContent/CPM), Protobuf should not change it. Protobuf should only set a default when the variable is unset.
Actual behavior Protobuf sets CMAKE_MSVC_RUNTIME_LIBRARY inside its CMakeLists.txt based on protobuf_MSVC_STATIC_RUNTIME and configuration type, overriding the parent’s explicit value and leading to /MDd in Debug for Protobuf/Abseil targets.
cmake_minimum_required(VERSION 3.20)
project(repro LANGUAGES CXX)
cmake_policy(SET CMP0091 NEW)
# Parent wants /MD in ALL configs (no /MDd)
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL CACHE STRING "" FORCE)
include(FetchContent)
set(protobuf_MSVC_STATIC_RUNTIME OFF CACHE BOOL "" FORCE)
FetchContent_Declare(protobuf
GIT_REPOSITORY https://github.com/protocolbuffers/protobuf.git
GIT_TAG v32.0.0 # example
)
FetchContent_MakeAvailable(protobuf)
add_executable(app main.cpp)
target_link_libraries(app PRIVATE protobuf::libprotobuf)
What version of protobuf and what language are you using? Version: main Language: C++
What operating system (Linux, Windows, ...) and version? Windows 11
What runtime / compiler are you using (e.g., python version or gcc version) Visual Studio 2022
Workarounds tried:
- Toolchain file + CMAKE_PROJECT_INCLUDE_BEFORE to re-force /MD after Protobuf config
- Patching Protobuf’s CMakeLists.txt locally to avoid resetting CMAKE_MSVC_RUNTIME_LIBRARY
Both work, but are ugly and require plumbing or maintaining a patch.
One solution could be to only set CMAKE_MSVC_RUNTIME if it hasn't been set before:
if(NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY)
if (protobuf_MSVC_STATIC_RUNTIME)
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$<CONFIG:Debug>:Debug>)
else()
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$<CONFIG:Debug>:Debug>DLL)
endif()
endif()
Another solution could be to introduce a variable similar to protobuf_MSVC_STATIC_RUNTIME but instead of just switching between static and dynamic it could be used as a user defined overwrite for CMAKE_MSVC_RUNTIME_LIBRARY.
I know this might be an edge case, but it would really help me with project maintenance.
Thanks.