From 80f3b758ebac728a15112355e30ca59078b72377 Mon Sep 17 00:00:00 2001 From: cfis Date: Sun, 4 Jan 2026 01:43:46 -0800 Subject: [PATCH 1/2] Lots of changes based on OpenCV learnings. --- CMakePresets.json | 126 ++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 65cba539..3352fa47 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -6,7 +6,11 @@ "hidden": true, "generator": "Ninja", "binaryDir": "${sourceDir}/build/${presetName}", - "installDir": "${sourceDir}/install/${presetName}" + "installDir": "${sourceDir}/install/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_CXX_FLAGS": "-Wall -Wno-unused-private-field -ftemplate-backtrace-limit=0 -fvisibility=hidden -fvisibility-inlines-hidden" + } }, { "name": "linux-debug", @@ -14,7 +18,7 @@ "displayName": "Linux Debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -Og" + "CMAKE_CXX_FLAGS_DEBUG": "-ggdb3 -O0 -fno-omit-frame-pointer -fno-inline -fno-optimize-sibling-calls" }, "condition": { "type": "equals", @@ -28,7 +32,9 @@ "displayName": "Linux Release", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", - "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -O3 -DNDEBUG" + "CMAKE_CXX_FLAGS_RELEASE": "-O3 -DNDEBUG", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON", + "CMAKE_SHARED_LINKER_FLAGS_RELEASE": "-Wl,--exclude-libs,ALL -Wl,--strip-all" }, "condition": { "type": "equals", @@ -42,7 +48,7 @@ "displayName": "macOS Debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_CXX_FLAGS": "-Wall -Wno-unused-private-field -ftemplate-backtrace-limit=0 -Og" + "CMAKE_CXX_FLAGS_DEBUG": "-g3 -Og -fno-omit-frame-pointer -fno-inline -gsplit-dwarf" }, "condition": { "type": "equals", @@ -56,7 +62,9 @@ "displayName": "macOS Release", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", - "CMAKE_CXX_FLAGS": "-Wall -Wno-unused-private-field -ftemplate-backtrace-limit=0 -O3 -DNDEBUG" + "CMAKE_CXX_FLAGS_RELEASE": "-O3 -DNDEBUG", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON", + "CMAKE_SHARED_LINKER_FLAGS_RELEASE": "-Wl,-dead_strip -Wl,-x" }, "condition": { "type": "equals", @@ -65,99 +73,117 @@ } }, { - "name": "windows", - "hidden": true, + "name": "mingw-debug", + "inherits": "base", + "displayName": "Mingw x64 Debug", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_COMPILER": "g++.exe", + "CMAKE_CXX_FLAGS": "-Wall -Wno-unused-private-field -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -fvisibility=hidden -fvisibility-inlines-hidden", + "CMAKE_CXX_FLAGS_DEBUG": "-g3 -Og -fno-omit-frame-pointer -fno-inline -gsplit-dwarf" + }, + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } + }, + { + "name": "mingw-release", "inherits": "base", + "displayName": "Mingw x64 Release", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_CXX_COMPILER": "g++.exe", + "CMAKE_CXX_FLAGS": "-Wall -Wno-unused-private-field -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -fvisibility=hidden -fvisibility-inlines-hidden", + "CMAKE_CXX_FLAGS_RELEASE": "-O3 -DNDEBUG", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON", + "CMAKE_SHARED_LINKER_FLAGS_RELEASE": "-Wl,--exclude-all-symbols" + }, "condition": { "type": "equals", "lhs": "${hostSystemName}", "rhs": "Windows" + } + }, + { + "name": "windows-base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "installDir": "${sourceDir}/install/${presetName}", + "toolchainFile": "$env{VCPKG_ROOT}\\scripts\\buildsystems\\vcpkg.cmake", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON", + "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE" }, - "toolchainFile": "$env{VCPKG_ROOT}\\scripts\\buildsystems\\vcpkg.cmake" + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Windows" + } }, { "name": "msvc-debug", - "inherits": "windows", + "inherits": "windows-base", "displayName": "MSVC x64 Debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "CMAKE_CXX_COMPILER": "cl.exe", - "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE", - "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT": "EditAndContinue" + "CMAKE_CXX_FLAGS_DEBUG": "/Od", + "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT": "ProgramDatabase" } }, { "name": "msvc-release", - "inherits": "windows", + "inherits": "windows-base", "displayName": "MSVC x64 Release", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", "CMAKE_CXX_COMPILER": "cl.exe", - "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /O2 /DNDEBUG /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE", + "CMAKE_CXX_FLAGS_RELEASE": "/O2 /DNDEBUG", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON", "CMAKE_MSVC_DEBUG_INFORMATION_FORMAT": "ProgramDatabase" } }, + { "name": "clang-windows-debug", - "inherits": "windows", + "inherits": "windows-base", "displayName": "Clang Windows Debug", "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug", "CMAKE_CXX_COMPILER": "clang-cl.exe", - "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field" + "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field", + "CMAKE_CXX_FLAGS_DEBUG": "/Od /Zi" } }, { "name": "clang-windows-release", - "inherits": "windows", + "inherits": "windows-base", "displayName": "Clang Windows Release", "cacheVariables": { "CMAKE_BUILD_TYPE": "Release", "CMAKE_CXX_COMPILER": "clang-cl.exe", - "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /O2 /DNDEBUG /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field" - } - }, - { - "name": "mingw-debug", - "inherits": "base", - "displayName": "Mingw x64 Debug", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Debug", - "CMAKE_CXX_COMPILER": "g++.exe", - "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -Og" - }, - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" - } - }, - { - "name": "mingw-release", - "inherits": "base", - "displayName": "Mingw x64 Release", - "cacheVariables": { - "CMAKE_BUILD_TYPE": "Release", - "CMAKE_CXX_COMPILER": "g++.exe", - "CMAKE_CXX_FLAGS": "-Wall -ftemplate-backtrace-limit=0 -Wa,-mbig-obj -O3 -DNDEBUG" - }, - "condition": { - "type": "equals", - "lhs": "${hostSystemName}", - "rhs": "Windows" + "CMAKE_CXX_FLAGS": "/EHs /W4 /bigobj /utf-8 /D_CRT_SECURE_NO_DEPRECATE /D_CRT_NONSTDC_NO_DEPRECATE /clang:-Wno-unused-private-field", + "CMAKE_CXX_FLAGS_RELEASE": "/O2 /DNDEBUG", + "CMAKE_INTERPROCEDURAL_OPTIMIZATION": "ON" } } ], + "buildPresets": [ { "name": "linux-debug", "displayName": "Build Linux Debug", - "configurePreset": "linux-debug" + "configurePreset": "linux-debug", + "jobs": 6 }, { "name": "linux-release", "displayName": "Build Linux Release", - "configurePreset": "linux-release" + "configurePreset": "linux-release", + "jobs": 6 }, { "name": "macos-debug", @@ -200,4 +226,4 @@ "configurePreset": "mingw-release" } ] -} +} \ No newline at end of file From 8f93c3acaf94cdbd9c7a8ccc4702b46bdb5eb696 Mon Sep 17 00:00:00 2001 From: cfis Date: Sun, 4 Jan 2026 01:47:37 -0800 Subject: [PATCH 2/2] Update build settings based on compiling opencv-ruby bindings. --- docs/packaging/build_settings.md | 50 ++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/docs/packaging/build_settings.md b/docs/packaging/build_settings.md index d77893c2..ebab7fd3 100644 --- a/docs/packaging/build_settings.md +++ b/docs/packaging/build_settings.md @@ -71,3 +71,53 @@ This instructs the linker to ignore all unresolved symbols during linking. The s ### Windows On Windows, no special linker flags are required. The extension links directly against the Ruby library (e.g., `x64-vcruntime140-ruby320.lib`), which provides the necessary symbols at link time. + +## Link Time Optimization (LTO) + +Link Time Optimization is **highly recommended** for Rice extensions, especially for release builds. Rice makes extensive use of C++ templates, which can result in significant code duplication across translation units. LTO allows the linker to deduplicate template instantiations and perform whole-program optimizations. + +### Why LTO Matters for Rice + +Rice's template-heavy design means that each `.cpp` file that uses Rice generates its own copies of template instantiations. Without LTO, these duplicate instantiations remain in the final binary, dramatically increasing its size. LTO enables the linker to: + +- Deduplicate identical template instantiations across object files +- Inline functions across translation unit boundaries +- Remove dead code more effectively + +### Build Size Comparison + +The following table shows the impact of LTO on a real-world Rice extension (opencv-ruby bindings): + +| Platform | Debug | Release (with LTO) | Size Reduction | +|----------|--------|--------------------|----------------| +| MSVC | 140 MB | 70 MB | 50% | +| macOS | 324 MB | 164 MB | 50% | +| MinGW | 1.4 GB | 200 MB | 86% | + +As shown, LTO provides substantial size reductions across all platforms, with MinGW benefiting the most dramatically. + +Rice's `CMakePreset.json` automatically enables LTO by setting `CMAKE_INTERPROCEDURAL_OPTIMIZATION` to `ON`. + +If you are using `extconf.rb (Mkmf)` then: + +```ruby +$CXXFLAGS << " -flto" +$LDFLAGS << " -flto" +``` + +For MSVC: + +```ruby +$CXXFLAGS << " /GL" +$LDFLAGS << " /LTCG" +``` + +### Debug Symbol Splitting (GCC/Clang) + +For debug builds with GCC or Clang, consider using `-gsplit-dwarf` to separate debug information into `.dwo` files. This keeps the main binary smaller while preserving full debug capability: + +```cmake +set(CMAKE_CXX_FLAGS_DEBUG "-g -gsplit-dwarf") +``` + +This is particularly useful for g++ where debug builds can exceed 1 GB without it.