Skip to content
23 changes: 23 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,26 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
string(REGEX REPLACE "([/-])EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
endif()

# MSVC: force the MS STL off its checked-iterator debug mode in every
# target of this build (engine, tests, vendored dependencies). CMake's
# default MSVC Debug flags define _DEBUG, which makes the STL default to
# _ITERATOR_DEBUG_LEVEL=2: in that mode every STL container instance
# gets a heap-allocated iterator-proxy object in its constructor, so the
# engine's zero-allocation invariants (the M1-ECS-03 churn test, the
# M1-HEAD-01 headless run test) would measure a windows-msvc-only
# baseline that the other P0 platforms never enable — GCC/Clang/AppleClang
# compile without checked iterators by default. The define is build-wide
# (not per-target) because the MS STL enforces one _ITERATOR_DEBUG_LEVEL
# per linked binary: mixing engine targets compiled with 0 against
# GTest objects compiled with 2 fails the link (LNK2038). Disabling it
# build-wide makes the Windows Debug build measure the same allocation
# behavior as the rest of the P0 matrix. The proxies are an STL debug
# aid, not engine behavior — they are allocated in container setup,
# never on hot paths.
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
add_compile_definitions(_ITERATOR_DEBUG_LEVEL=0)
endif()

# Both the static (default) and shared (LAIGE_BUILD_SHARED) library variants
# are position-independent so they link identically into games and tools
# (NFR-8.9).
Expand Down Expand Up @@ -141,6 +161,9 @@ laige_deps_verify_lock()
# yvals.h _TRY_BEGIN/_CATCH) on the _HAS_EXCEPTIONS macro, not on the /EH
# flags — with /EHs- alone it would still emit catch blocks that the
# compiler cannot unwind (cl C4530, fatal under /WX).
# _ITERATOR_DEBUG_LEVEL=0 (see the MSVC block above) keeps the Windows
# Debug build's STL container allocation behavior aligned with the other
# P0 platforms.
#
# The warning/language flags are PRIVATE: they govern this target's own
# translation units and must not leak into consumers (CPP-010) — a game
Expand Down
25 changes: 24 additions & 1 deletion tools/run/laige-run.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,10 @@
#include <string_view>
#include <utility>

#if defined(_MSC_VER)
#include <share.h> // _SH_DENYNO: plain-fopen sharing for the _fsopen below
#endif

#include "laige/errors.h"
#include "laige/json.h"
#include "laige/logging.h"
Expand Down Expand Up @@ -112,11 +116,30 @@ bool parseTicks(std::string_view text, std::uint64_t* out) {
return true;
}

// Portable config-file open (CPP-009 compile-time platform boundary —
// the logging.cpp precedent). MSVC's CRT deprecates plain `fopen`
// (C4996, fatal under the engine's /WX policy); `fopen_s` cannot be
// used here: it opens with the `_SH_SECURE` sharing mode, which denies
// re-opening of the file (the windows-msvc CI runs of M0-CORE-02 read
// back an empty file for exactly that reason). `_fsopen(path, mode,
// _SH_DENYNO)` is the CRT's documented way to open with plain-`fopen`
// sharing semantics, which every other supported compiler's `fopen`
// provides.
#if defined(_MSC_VER)
inline std::FILE* openConfigFile(const char* path, const char* mode) {
return ::_fsopen(path, mode, _SH_DENYNO);
}
#else
inline std::FILE* openConfigFile(const char* path, const char* mode) {
return std::fopen(path, mode);
}
#endif

// Reads the config file into a bounded buffer (the 1 MiB ADR 0003
// bound). Returns the error Status; on success the document is in
// `out`.
laige::Status readConfigFile(const std::string& path, std::string* out) {
std::FILE* file = std::fopen(path.c_str(), "rb");
std::FILE* file = openConfigFile(path.c_str(), "rb");
if (file == nullptr) {
return laige::ErrorCode::IoError;
}
Expand Down
Loading