The problem is/was that M$ snprintf() and friends were not C99 compliant as the referenced article says. They seem to have fixed that now, _snprintf() still behaving the old M$ way and snprintf() the C99 way. Problem is that we cannot really be sure against which runtime library we will be executing, so I fear that for the time being our ms_snprintf(), which should have been called c99_snprintf() is the only reliable way around
Pushed fixes that renames this function and make sure it is defined everywhere.
If you’d rather, feel free to ignore my PRs related to the warnings (or even delete them). The same list of warnings is already in the document I sent by email.
I think all your PRs and messages have been dealt with. The main thing useful is to complete the MSVC section in cmake/BuildType.cmake such that just using -DCMAKE_BUILD_TYPE=... does the job rather than having to add additional options for C/CXXFLAGS, etc. The toolchain should probably not be part of this as people might want to use something different and it might be installed elsewhere. Could you do that?
I don’t think you need these anyway. If you use the right cmd.exe or PowerShell for running the 64 bit version of MSVC and the vcpkg.cmake toolchain these are probably default. We definitely do not want -A x64 and this will probably also build on arm64.
I think the release build is actually fine. It would be nice if the other build types work as
These all set CMAKE_C_FLAGS_<type> and CXXMAKE_C_FLAGS_<type> to get the desired build. Most of it should be a fairly trivial copy/paste from one of the other compilers and update the actual flags. The other compilers use mostly the same flags. MSVC will be quite different here.
Example created by ChatGPT (not Claude this time), just trying to figure out if I am headed in the right direction. The example below has not been tested and is in a reveal section so that Google and such will not index it for search results.
cmake/BuildType.cmake (click triangle to expand)
elseif(MSVC)
# Common MSVC flags
set(_SWI_MSVC_C_COMMON "/nologo")
set(_SWI_MSVC_CXX_COMMON "/nologo /EHsc") # /EHsc for consistent C++ exception semantics
# Debug flags: no optimization + full symbols + SWI debug macros
set(CMAKE_C_FLAGS_DEBUG
"${_SWI_MSVC_C_COMMON} /D_DEBUG /DO_DEBUG /DO_DEBUG_ATOMGC /Od /Zi"
CACHE STRING "CFLAGS for a Debug build" FORCE)
set(CMAKE_CXX_FLAGS_DEBUG
"${_SWI_MSVC_CXX_COMMON} /D_DEBUG /DO_DEBUG /DO_DEBUG_ATOMGC /Od /Zi $ENV{CXXFLAGS}"
CACHE STRING "CXXFLAGS for a Debug build" FORCE)
# RelWithDebInfo: optimization + symbols
set(CMAKE_C_FLAGS_RELWITHDEBINFO
"${_SWI_MSVC_C_COMMON} /O2 /Zi"
CACHE STRING "CFLAGS for a RelWithDebInfo build" FORCE)
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
"${_SWI_MSVC_CXX_COMMON} /O2 /Zi $ENV{CXXFLAGS}"
CACHE STRING "CXXFLAGS for a RelWithDebInfo build" FORCE)
# Release: optimization, no debug macros
set(CMAKE_C_FLAGS_RELEASE
"${_SWI_MSVC_C_COMMON} /O2"
CACHE STRING "CFLAGS for a Release build" FORCE)
set(CMAKE_CXX_FLAGS_RELEASE
"${_SWI_MSVC_CXX_COMMON} /O2 $ENV{CXXFLAGS}"
CACHE STRING "CXXFLAGS for a Release build" FORCE)
# MinSizeRel: size-oriented optimization
set(CMAKE_C_FLAGS_MINSIZEREL
"${_SWI_MSVC_C_COMMON} /O1"
CACHE STRING "CFLAGS for a MinSizeRel build" FORCE)
set(CMAKE_CXX_FLAGS_MINSIZEREL
"${_SWI_MSVC_CXX_COMMON} /O1 $ENV{CXXFLAGS}"
CACHE STRING "CXXFLAGS for a MinSizeRel build" FORCE)
# Optional: Sanitize build type (if you intend to support it on MSVC)
# MSVC uses /fsanitize=address (requires installed VS components).
set(CMAKE_C_FLAGS_SANITIZE
"${_SWI_MSVC_C_COMMON} /D_DEBUG /DO_DEBUG /Od /Zi /fsanitize=address"
CACHE STRING "CFLAGS for a Sanitize build" FORCE)
set(CMAKE_CXX_FLAGS_SANITIZE
"${_SWI_MSVC_CXX_COMMON} /D_DEBUG /DO_DEBUG /Od /Zi /fsanitize=address $ENV{CXXFLAGS}"
CACHE STRING "CXXFLAGS for a Sanitize build" FORCE)
# Optional: linker flags for sanitize (sometimes needed to avoid incremental link issues)
set(CMAKE_EXE_LINKER_FLAGS_SANITIZE
"/INCREMENTAL:NO"
CACHE STRING "LDFLAGS for a Sanitize build" FORCE)
set(CMAKE_SHARED_LINKER_FLAGS_SANITIZE
"/INCREMENTAL:NO"
CACHE STRING "LDFLAGS for a Sanitize build" FORCE)
Makes a lot of sense. I’m not familiar with most of the MSVC flags, so you might be better to judge from your experience. Also figuring out the right optimization level might be useful. For example, up till GCC 14, -O2 was typically best on GCC. As of GCC 14 -O3 produces significantly faster code, so the default is switched.
Ideally you’d support PGO (Profile Guided Optimization) if MSVC can. Also there it is unclear. It doesn’t help noticeable for Clang, but does help significantly on GCC.
If you want me to ask a question just let me know.
Note: Not sure if ChatGPT shared links update when more content is added so will need feedback to know.
The shared link should have section at the end starting with
PGO (Profile-Guided Optimization) is a two-phase build:
build an instrumented binary
run representative workloads to collect profile data
rebuild using that profile to guide inlining, code layout, branch prediction, indirect call promotion, etc.
What Jan is flagging is that your CMake “PGO” build type currently only exists for GCC, and even there it’s only “flags”, not the workflow. Extending PGO support to MSVC is possible, but the mechanics differ a lot by compiler.
If you do use the link and can not see that let me know. I can paste it all here but it is long.
While working on updates in cmake/BuildType.cmake—specifically the elseif(MSVC) section—I had to step back and re-examine the CMake configuration phase of the build. In testing different CMake configurations for MSVC on Windows, it became clear that many apparent successes or failures were determined before CMake ever ran.
On Windows using MSVC, starting the build from the “x64 Native Tools Command Prompt” should be treated as the first step of any supported build process.
To work correctly, the tools require several specific environment variables to be set. These variables are used to add the tools to the path, and to set the locations of include files, library files, and SDKs. To make it easy to set these environment variables, the installer creates customized command files , or batch files, during installation. You can run one of these command files to set a specific host and target build architecture, Windows SDK version, and platform toolset. For convenience, the installer also creates shortcuts in your Start menu. The shortcuts open developer command prompt windows by using these command files for specific combinations of host and target. These shortcuts ensure all the required environment variables are set and ready to use.
If there are questions or concerns about this requirement, I’m happy to clarify or provide additional detail.
I inserted the suggestions by ChatGPT, which seems a good start. I also updated boot/build_home.pl to facilitate multi-config generators in general. That now also works on Linux using -G "Ninja Multi-Config". Hope I didn’t break anything for Windows. Note that PGO building requires more. I tried to include that into the Ninja multi config, but that does not work. Might be possible to fix, might also not be so easy. Not interesting enough …
If you means me, I don’t know. I used that, but there might be alternatives. I don’t feel at home facing a Windows desktop
OK, found the cmake/BuildType.cmake changes, hiding as More boolean types..
The ChatGPT share/link I provided most likely did not give the remainder of the ChatGPT conversation, spent a few hours and checking things and learned lots.
I have not done PGO with MSVC but will be following up on that hopefully in the next few days.
I am more than happy to try the alternatives, just let me know, need details like the command line or combinations you would like tried.
Same for me using macOS, not so bad using Ubuntu.
Here is a little table that ChatGPT created which helped me, maybe it will help others.
In my own testing I instinctively start from the x64 Native Tools Command Prompt for VS, but that isn’t a realistic “first-time user” scenario—many people won’t know to do that as an initial step.
What would you expect others to do by default, and what would you try yourself? If you can suggest one or more concrete variations of the three CMake/CTest commands (configure, build, test), I can run them and report back.
I also expect some users will want the generated .sln / .vcxproj files, so I’ll note how to obtain those as part of the results. In addition, I’ll try the variations implied by the updated cmake/BuildType.cmake. This will likely take most, if not all, of the day.
Cross-compile from Linux Preferably on a real Linux machine, but using WSL probably does the job as well. Builds several times faster and the result performs about twice as good Well, unless the latest MSVC made some big steps. From the data points I have, GCC made a lot more progress over the last 15 years than MSVC did. My Windows development setup:
Linux host (Fedora 43)
Docker image for building SWI-Prolog in the same source directory I also use for developing the Linux version. That allows me to test Windows and Linux builds in various configurations from the same source, so I do not need to synchronize sources.
Partial testing by running it under Wine (ctest works fine). Most issues reproduce under Wine. Some not and debugging is lousy, so plan B …
VirtualBox VM running Windows 11 with access to the source directory as shared folder can be used to run the system under Windows without installing. MSYS-2 gdb can be used for debugging (the debugging experience is not great, so that is a last resort for Windows specific bugs).
Still the work on such a port is useful. It may help people who, for some reason, need to stick with Microsoft native tool chains (I met them), it found some bugs and it generalized some code and build tooling. So, thanks!
I’ll proceed with the builds using my current workflow, along with a few variations I picked up yesterday, and document the commands used with additional notes for anyone who wants to reproduce the results.
While starting the first build, I ran into a linker warning. I’m having Claude work on a PR for that issue as I write this.