diff --git a/CMakeLists.txt b/CMakeLists.txt index b9e529d43..9bafb0ea9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -164,8 +164,20 @@ option(BABYLON_NATIVE_EMBEDDING_APPLE "Build the Apple (iOS / macOS / visionOS) # Sanitizers option(ENABLE_SANITIZERS "Enable AddressSanitizer and UBSan" OFF) +# RTTI +# Babylon Native does not use dynamic_cast or typeid anywhere in Core, Plugins, +# Polyfills, Embedding or Apps, but compilers emit RTTI records for every +# polymorphic class by default. Disabling it is a pure size win. UBSan's vptr +# check is the only thing that needs RTTI, so it is derived from the sanitizer +# switch rather than exposed as an option of its own. +# +# Deliberately a plain variable and not a cache entry: a cached ENABLE_RTTI +# would persist ON in any build directory that was configured with +# -DENABLE_SANITIZERS=ON even once, so re-configuring that directory without +# sanitizers would silently keep emitting RTTI and lose the size win. +set(ENABLE_RTTI ${ENABLE_SANITIZERS}) + if(ENABLE_SANITIZERS) - set(ENABLE_RTTI ON CACHE BOOL "" FORCE) if(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU") set(SANITIZERS "address,undefined") # Check for Clang since vptr and fdsan are Clang-specific @@ -363,6 +375,29 @@ if(MSVC) add_compile_options(/MP) endif() +if(NOT ENABLE_RTTI) + # Applied to C++ only: /GR- and -fno-rtti are not valid for C sources. + # OBJCXX is listed explicitly so Objective-C++ (.mm) sources are covered on + # Apple regardless of whether CMake classifies them as CXX or OBJCXX. + if(MSVC) + add_compile_options($<$:/GR->) + else() + add_compile_options($<$:-fno-rtti>) + endif() +endif() + +# Re-enables RTTI for a single target. Needed by dependencies that genuinely +# require it; see the call sites for the specific reason in each case. +# Call sites gate on the configuration that provides the target, so an +# unresolved name is a mistake and target_compile_options reports it. +function(babylon_native_force_rtti target) + if(MSVC) + target_compile_options(${target} PRIVATE $<$:/GR>) + else() + target_compile_options(${target} PRIVATE $<$:-frtti>) + endif() +endfunction() + if(APPLE) # Create scheme for installation and other targets set(CMAKE_XCODE_GENERATE_SCHEME TRUE) diff --git a/Dependencies/CMakeLists.txt b/Dependencies/CMakeLists.txt index 17989e3ff..43add7607 100644 --- a/Dependencies/CMakeLists.txt +++ b/Dependencies/CMakeLists.txt @@ -273,6 +273,27 @@ endif() # -------------------------------------------------- FetchContent_MakeAvailable_With_Message(JsRuntimeHost) +# Two JsRuntimeHost targets cannot be built without RTTI: +# v8inspector - includes asio, whose headers use typeid() unconditionally +# (any_executor.hpp, service_registry.hpp, handler_work.hpp). +# Clang and GCC reject this outright; MSVC only warns. +# Only defined for V8 with the inspector enabled +# (JsRuntimeHost Core/AppRuntime/CMakeLists.txt). +# jsi - Hermes (fetched by JsRuntimeHost) builds its API/hermes +# targets with RTTI, and their vtables reference "typeinfo for +# facebook::jsi::*" which only jsi.cpp emits. Compiling jsi +# without RTTI drops those definitions and the link fails. +# The same target name is used by Node-API-JSI for V8JSI. +# Each call is gated on the engine that defines the target, so a target that +# stops existing upstream fails configuration instead of silently going by. +if(NAPI_JAVASCRIPT_ENGINE STREQUAL "V8" AND JSRUNTIMEHOST_CORE_APPRUNTIME AND JSRUNTIMEHOST_CORE_APPRUNTIME_V8_INSPECTOR) + babylon_native_force_rtti(v8inspector) +endif() + +if(NAPI_JAVASCRIPT_ENGINE STREQUAL "JSI" OR NAPI_JAVASCRIPT_ENGINE STREQUAL "Hermes") + babylon_native_force_rtti(jsi) +endif() + # -------------------------------------------------- # metal-cpp # --------------------------------------------------