From 631f31cda763aea0fa40f9d92eb01fc3345d2a16 Mon Sep 17 00:00:00 2001 From: Branimir Karadzic Date: Wed, 12 Aug 2026 12:14:18 -0700 Subject: [PATCH 1/2] Build: enable /OPT:REF for MSVC RelWithDebInfo MSVC turns /OPT:REF and /OPT:ICF off whenever /DEBUG is passed, and CMake's default RelWithDebInfo link flags are "/debug /INCREMENTAL". The result is that RelWithDebInfo keeps every unreferenced COMDAT that made it into the static libraries, even though it is an optimized configuration. Turning incremental linking off and /OPT:REF on shrinks the Playground: Playground.exe RelWithDebInfo 11,212,800 -> 4,562,432 bytes (-59.3%) /OPT:ICF is deliberately left off: it measured zero additional bytes here, and folding identical functions makes stack traces ambiguous, which is the opposite of what RelWithDebInfo is for. Debug is untouched. Release and MinSizeRel already get /OPT:REF implicitly because they do not link with /DEBUG. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 88569c10-a7ff-4373-9a58-afa9c68b8c09 --- CMakeLists.txt | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index c83b87522..9c20e1a53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -373,6 +373,29 @@ if(MSVC) # Enable multiprocessor compilation for faster builds add_compile_options(/MP) + + # Strip unreferenced code from RelWithDebInfo binaries. + # + # MSVC turns /OPT:REF and /OPT:ICF off whenever /DEBUG is passed, and CMake's + # default RelWithDebInfo link flags are "/debug /INCREMENTAL". The effect is that + # RelWithDebInfo keeps every unreferenced COMDAT that made it into the static + # libraries. + # + # /OPT:REF alone captures the entire win (/OPT:ICF measured zero additional + # bytes), so identical functions are left unfolded and stack traces stay + # unambiguous. Incremental linking must be off because it is incompatible with + # /OPT:REF. Debug is left untouched, and Release/MinSizeRel already get /OPT:REF + # implicitly because they do not link with /DEBUG. + foreach(BABYLON_NATIVE_LINKER_FLAGS + CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO + CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO + CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO) + set(BABYLON_NATIVE_FLAGS "${${BABYLON_NATIVE_LINKER_FLAGS}}") + string(REPLACE "/INCREMENTAL:NO" "" BABYLON_NATIVE_FLAGS "${BABYLON_NATIVE_FLAGS}") + string(REPLACE "/INCREMENTAL" "" BABYLON_NATIVE_FLAGS "${BABYLON_NATIVE_FLAGS}") + string(REPLACE "/OPT:REF" "" BABYLON_NATIVE_FLAGS "${BABYLON_NATIVE_FLAGS}") + set(${BABYLON_NATIVE_LINKER_FLAGS} "${BABYLON_NATIVE_FLAGS} /INCREMENTAL:NO /OPT:REF") + endforeach() endif() if(NOT ENABLE_RTTI) From b66c234e1c529cb29a5f28c76d246f67ebe406a0 Mon Sep 17 00:00:00 2001 From: Branimir Karadzic Date: Wed, 12 Aug 2026 13:16:45 -0700 Subject: [PATCH 2/2] Build: use add_link_options with a config generator expression Replaces the string surgery on CMAKE_*_LINKER_FLAGS_RELWITHDEBINFO, which could corrupt a pre-existing /INCREMENTAL:YES by removing only the /INCREMENTAL prefix and leaving a dangling :YES. Verified through the generated Playground.vcxproj that CMake still folds these into the structured properties -- OptimizeReferences=true and LinkIncremental=false on RelWithDebInfo only, with nothing leaking into AdditionalOptions -- and that the size win is unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 88569c10-a7ff-4373-9a58-afa9c68b8c09 --- CMakeLists.txt | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c20e1a53..936029049 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -386,16 +386,7 @@ if(MSVC) # unambiguous. Incremental linking must be off because it is incompatible with # /OPT:REF. Debug is left untouched, and Release/MinSizeRel already get /OPT:REF # implicitly because they do not link with /DEBUG. - foreach(BABYLON_NATIVE_LINKER_FLAGS - CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO - CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO - CMAKE_MODULE_LINKER_FLAGS_RELWITHDEBINFO) - set(BABYLON_NATIVE_FLAGS "${${BABYLON_NATIVE_LINKER_FLAGS}}") - string(REPLACE "/INCREMENTAL:NO" "" BABYLON_NATIVE_FLAGS "${BABYLON_NATIVE_FLAGS}") - string(REPLACE "/INCREMENTAL" "" BABYLON_NATIVE_FLAGS "${BABYLON_NATIVE_FLAGS}") - string(REPLACE "/OPT:REF" "" BABYLON_NATIVE_FLAGS "${BABYLON_NATIVE_FLAGS}") - set(${BABYLON_NATIVE_LINKER_FLAGS} "${BABYLON_NATIVE_FLAGS} /INCREMENTAL:NO /OPT:REF") - endforeach() + add_link_options($<$:/INCREMENTAL:NO> $<$:/OPT:REF>) endif() if(NOT ENABLE_RTTI)