Early experiences with MSVC_DEBUG_INFORMATION_FORMAT and CMP0141

I’ve been updating some projects and other material to account for the new MSVC_DEBUG_INFORMATION_FORMAT target property and the associated CMAKE_MSVC_DEBUG_INFORMATION_FORMAT variable. I wanted to share some experiences from that, as it has highlighted that these may be having the opposite effect to what they were intended to achieve.

In vcpkg, the default Windows toolchain file hard-codes adding /Z7 to the CMAKE_<LANG>_FLAGS_DEBUG and CMAKE_<LANG>_FLAGS_RELEASE variables. If any of the projects that vcpkg provides a port for are updated to expect CMP0141 to be set to NEW, vcpkg is going to have to either patch those projects or set CMAKE_POLICY_DEFAULT_CMP0141 to OLD in their toolchain file for all projects to avoid causing multiple debug-related flags to be added to the compiler command line. Vcpkg will be stuck with the OLD behavior until it can check/update every one of its ports (of which there are about 2000) to handle the NEW behavior. I can’t speak for the vcpkg project, but this would seem like a very non-trivial task. But it extends further than that, and this is where things really start to bite. Anyone maintaining their own vcpkg registry or using their own custom toolchain file is going to have to do the same. All parties involved will have to move to the NEW behavior eventually to avoid deprecation warnings. But the path to doing that could be harder than most typical policy changes.

In a different scenario, I have some code that adds support for Ccache to the build. That code is meant to be general-purpose, able to be applied to any project. Ccache recently gained support for the MSVC toolchain, but it comes with restrictions. If the /Zi or /ZI flags are present, caching is disabled, so the code forces those flags to /Z7 instead (ignore the merits of that, you can assume people are aware of this and accept it as part of using this particular code). Because this code cannot make assumptions about the project it is being added to, it has to account for both the CMAKE_<LANG>_FLAGS... variables and the CMAKE_MSVC_DEBUG_INFORMATION_FORMAT variable to achieve this. The new abstraction has doubled the complexity of that code. I expect this situation will only get even more complex once the more generalised abstraction discussed in issue 23898 is eventually implemented.

At this point, I wanted to take a step back and look at the goals of the new MSVC_DEBUG_INFORMATION_FORMAT. My understanding is that at least one of those goals was to simplify things for developers and projects, giving them a way to specify a particular type of debug info format without having to know the exact flags involved, perform string-based substitutions of those flags, etc. While it has achieved that for a simple project used on its own, this seems to be coming at the cost of making other scenarios considerably more complex. Furthermore, any project which may find itself used by other projects as a dependency or made available by package managers cannot rely on the new behavior being active, even if their own policy settings are such that it should be (as demonstrated by the vcpkg scenario above). This seems to be having the opposite effect of the goal to simplify things.

I don’t have a proposal for how things could be changed to improve the situation. It does seem that the new abstraction doesn’t sufficiently replace the existing flag mechanism, it only adds a new layer without fully freeing the project from having to deal with the old one. The policy meant to switch between the two behaviours is more likely than usual to be driven by things outside the project in this case, which is what makes this a more prominent problem.

I realise that the two example scenarios I detailed above are not things that every developer will face. The purpose of this post is to raise awareness and perhaps prompt some further discussion around this area. The more general abstraction in issue 23898 is only going to exacerbate the situation further, and I do not look forward to when that lands and I have to deal with the fallout of that making things even more complicated.

Tagging a few folks who may be interested in this topic: @Neumann-A @Lectem @tambre

vcpkg relies on all relevant flags to be present in CMAKE_<LANG>_FLAGS(_<CONFIG>)? to pass them on to other buildsystems. So switching CMAKE_POLICY_DEFAULT_CMP0141 to NEW is not really an option. In addition to that /Zi cannot really be used by static libraries unless you tell the compiler to write all debug info into a common file destroying any parallelism. (and /ZI doesn’t even make sense for vcpkg)

Personally I think that MSVC_DEBUG_INFORMATION_FORMAT tried to solve the wrong problem. The problem here is simply that people are reluctant to use a CMAKE_TOOLCHAIN_FILE for easy stuff like a small change of the debug flag. The same applies to MSVC_RUNTIME_LIBRARY. So instead of fleshing out a whole target property it would probably have been better to just provide a cmake option() in the platform header to switch the flag.

All parties involved will have to move to the NEW behavior eventually to avoid deprecation warnings.

Yes. Policies are not meant to be feature toggles, and the OLD behavior is deprecated by design, so we should not rely on setting CMP0141 to OLD as a long-term path forward for any use case.

Environments that want to add the MSVC debug info flags themselves can tell CMake not to add such flags by setting CMAKE_MSVC_DEBUG_INFORMATION_FORMAT to the empty string. Similarly for CMAKE_MSVC_RUNTIME_LIBRARY. Then one can add the flags to CMAKE_<LANG>_FLAGS(_<CONFIG>)? as before.