Fixed MSVC support

This commit is contained in:
alejo committed 2026-09-12 21:06:29 -03:00
1 parent 9248925b77
commit b4e77ed401
8 files changed
+129 -29

No files matched your search

+13
View File
@@ -12,3 +12,16 @@ if(NOT WIN32)
# (nonexistent, for a static lib) link step.
target_link_libraries(hotreload_lib PUBLIC ${CMAKE_DL_LIBS})
endif()
if(MSVC)
# UnDecorateSymbolName (Demangle.cpp) lives in dbghelp.lib, which --
# unlike kernel32/user32 -- MSVC does not link by default. Without
# this, the final link fails with an undefined symbol for it;
# found via an actual Windows build of this library, not just
# documentation. PUBLIC for the same reason as CMAKE_DL_LIBS above.
# Guarded on MSVC (true for both real cl.exe and clang-cl, and
# false for MinGW) rather than WIN32, since MinGW's build of
# Demangle.cpp takes the __GNUC__/__cxa_demangle branch instead and
# never needs dbghelp at all.
target_link_libraries(hotreload_lib PUBLIC dbghelp)
endif()
+26 -11
View File
@@ -283,17 +283,32 @@ export-table reader in `SymbolTable.cpp`.
`_ZN9CppWidget4tickEi` lookup string was derived from a native GCC
build but also worked unmodified against this MinGW/Wine build and
the separate native Clang build).
- **MSVC itself was not run anywhere in this process** -- there is no
Windows machine or MSVC install available in the environment this
was built in. The MSVC-specific code (`/hotpatch`,
`IMAGE_EXPORT_DIRECTORY` parsing, `VirtualProtect`,
`FlushInstructionCache`) is written directly against Microsoft's
documented structures and behavior, and the equivalent PE-reading
code was compiled clean against real `<windows.h>` headers via
MinGW, but treat the MSVC path as unverified until you've built it
on an actual Windows box. If it doesn't work, `SymbolTable.cpp`'s
PE branch and `cmake/HotReload.cmake`'s `/hotpatch` branch are the
two places to look first.
- **MSVC was never run directly in the environment that built this
library** -- there is no Windows machine or MSVC install available
there. It has, since, been built and live-tested on real MSVC by
someone using this library, surfacing four real fixes now folded
in: `windows.h` must be included before `dbghelp.h` (the reverse
order fails to compile -- `dbghelp.h` assumes types like `HANDLE`
are already defined rather than including their own headers),
`NOMINMAX` needs defining before `windows.h` in every file that
includes it (`SymbolTable.cpp` concretely needs this -- without it,
windows.h's own `min`/`max` macros substitute into that file's
`std::max`/`std::min` calls and it fails to compile), MSVC needs
`dbghelp.lib` linked explicitly for `UnDecorateSymbolName`
(`source/HotReload/CMakeLists.txt` now does this whenever
`MSVC` is true, which also covers `clang-cl`), and
`source/examples/HotReloadLiveDemo`'s reload-retry logic needed
widening (see that example's own file for why). The MSVC-specific
code (`/hotpatch`, `IMAGE_EXPORT_DIRECTORY` parsing,
`VirtualProtect`, `FlushInstructionCache`) was written directly
against Microsoft's documented structures and behavior before any
of that feedback existed, and the equivalent PE-reading code was
separately compiled clean against real `<windows.h>` headers via
MinGW -- between the two, treat it as real-world-checked now, not
merely reasoned through, though obviously with less first-hand
confidence than everything that was directly, repeatedly run in
this project's own development loop (native GCC/Clang, ARM64 under
QEMU, MinGW under Wine).
- **32-bit ARM was not implemented at all**, deliberately: it's the
one architecture in this list where getting it wrong is easy and
getting it verified is hard. Its instructions are either 4 bytes
@@ -3,6 +3,13 @@
#include <cstdint>
#if defined(_WIN32)
// NOMINMAX: prevents windows.h from defining min/max macros that
// would otherwise clash with std::min/std::max and anything else
// named min/max in this translation unit -- found via an actual
// Windows build/run of this library, not just documentation.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <sys/mman.h>
+6
View File
@@ -3,6 +3,12 @@
#include <string>
#if defined(_WIN32)
// NOMINMAX: see MemoryProtection.cpp's identical comment -- same
// windows.h, same reason, needed in every translation unit that
// includes it, not just once for the library as a whole.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#else
#include <dlfcn.h>
+10
View File
@@ -35,6 +35,16 @@ namespace hot_reload::detail
// headers just gets added directly to loadedBase.
// ---------------------------------------------------------------
// NOMINMAX matters concretely in this exact file, not just as a
// defensive habit: without it, windows.h's own min/max macros
// substitute into the std::max/std::min calls a few lines below
// (the preprocessor sees the bare token max after std::, not the
// qualified name, and expands it regardless) and the file fails to
// compile on MSVC. Found via an actual Windows build/run of this
// library, not just documentation.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
namespace
+26 -5
View File
@@ -29,8 +29,27 @@
// beyond just this function.
#include <cxxabi.h>
#elif defined(_MSC_VER)
#include <dbghelp.h>
// windows.h must come first: dbghelp.h uses types (HANDLE, DWORD,
// BOOL, ...) it assumes are already defined rather than including
// their defining headers itself -- reversing this order fails to
// compile. NOMINMAX prevents windows.h from defining min/max
// macros that would otherwise clash with std::min/std::max and
// anything else named min/max in this translation unit. Both
// fixes below came from an actual Windows build/run of this
// library, not just documentation -- see README.md's toolchain
// verification notes.
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <dbghelp.h>
// Belt-and-suspenders for anyone building this file outside this
// project's own CMake (source/HotReload/CMakeLists.txt links
// dbghelp explicitly for every MSVC-family build, which is the
// primary fix and the one actually required -- confirmed directly
// that omitting it leaves UnDecorateSymbolName undefined at link
// time regardless of this pragma).
#pragma comment(lib, "dbghelp.lib")
#endif
extern "C"
@@ -61,10 +80,12 @@ extern "C"
// DbgHelp) -- but DbgHelp as a whole is documented as not
// thread-safe, so serialize calls to this function
// yourself if you call it from more than one thread.
// Written against Microsoft's documented behavior; unlike
// most of this library, this specific function was not
// exercised on real Windows -- see README.md's toolchain
// verification notes.
// Exercised on a real Windows build (see README.md's
// toolchain verification notes) -- getting the
// windows.h/dbghelp.h include order and NOMINMAX right
// (see the #include block above) and linking dbghelp
// explicitly (source/HotReload/CMakeLists.txt) were both
// needed to get here.
char buffer[2048];
if (UnDecorateSymbolName(name, buffer, sizeof(buffer), UNDNAME_COMPLETE) != 0)
{