`static_h`: the tree cannot be compiled with clang-cl — CMake's `/EHsc` is stripped and `hermes_update_cxx_flags` replaces it with GCC spellings clang-cl ignores
Building static_h on Windows with clang-cl (the LLVM that ships inside
Visual Studio 2022) fails to compile: every C++ translation unit ends up with
exceptions disabled, and the API layer throws.
Two lines interact to produce it. Both were read out of the tree and then
confirmed in the generated build.ninja, rather than inferred:
cmake/modules/Hermes.cmake:261-265strips CMake's own default exception flag underif (MSVC):if (MSVC) # Remove CMake's default exception handling flags to avoid D9025 warnings # when we set our own in hermes_update_cxx_flags() string(REPLACE "/EHsc" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") string(REPLACE "/EHsc" "" CMAKE_C_FLAGS "${CMAKE_C_FLAGS}")clang-cl is
MSVCas far as CMake is concerned, so the strip happens.hermes_update_cxx_flags(cmake/modules/Hermes.cmake:68-102) is then expected to set the replacement — but it testsGCC_COMPATIBLEbeforeMSVC:if (HERMES_ENABLE_EH) if (GCC_COMPATIBLE) list(APPEND flags -fexceptions) elseif (MSVC) list(APPEND flags /EHsc) endif () else () if (GCC_COMPATIBLE) list(APPEND flags -fno-exceptions) elseif (MSVC) list(APPEND flags /EHs-c-) endif () endif ()and
GCC_COMPATIBLEis set for clang-cl atcmake/modules/Hermes.cmake:17-19:elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CLANG 1) set(GCC_COMPATIBLE 1) if (CMAKE_CXX_SIMULATE_ID MATCHES "MSVC") set(CLANG_CL 1) endif ()So the GCC spellings are emitted — and clang-cl ignores them:
clang-cl: warning: unknown argument ignored in clang-cl: '-fno-exceptions' [-Wunknown-argument] clang-cl: warning: unknown argument ignored in clang-cl: '-fno-rtti' [-Wunknown-argument]
Net effect: /EHsc removed, replacement ignored, so every TU compiles at
clang-cl's MSVC-compatible default of exceptions off, and the build stops at
the first throw:
jsi.cpp(113,5): error: cannot use 'throw' with exceptions disabled (x11)
FAILED: static-hermes/jsi/CMakeFiles/jsi.dir/jsi.cpp.obj
RuntimeTaskRunner.cpp(56,7): error: cannot use 'throw' with exceptions disabled
extensions/Intrinsics.cpp(76,5) and (99,3): error: cannot use 'try' with exceptions disabled
extensions/JSIUtils.cpp(21,5), (28,5)
FAILED: static-hermes/API/hermes/CMakeFiles/hermesapi_obj.dir/...(Those paths carry a static-hermes/ prefix because the tree was consumed by
add_subdirectory from a downstream project; the file names and the diagnostics
are the tree's own.)
Two further notes that may be useful:
- The tree already knows it is clang-cl.
CLANG_CLis computed atcmake/modules/Hermes.cmake:21fromCMAKE_CXX_SIMULATE_ID, andhermes_update_cxx_flagssimply does not consult it. - Hermes v0.13.0 does not have this problem, by accident. The
/EHscstrip at:261-265is new onstatic_h; on the release branch nothing removes CMake's/EHsc, so-fno-exceptionsbeing ignored leaves the tree built with exceptions, which links and runs.
Repro
git clone https://github.com/facebook/hermes.git hermes-static
cd hermes-static
git checkout 5cee10abc93667ea5538caecaf0a457c66fa5bdc
call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat"
set CLANGCL=C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/Llvm/x64/bin/clang-cl.exe
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release ^
-DCMAKE_C_COMPILER="%CLANGCL%" -DCMAKE_CXX_COMPILER="%CLANGCL%" ^
-DHERMES_ENABLE_TEST_SUITE=OFF -DHERMES_ENABLE_NAPI=OFF(HERMES_ENABLE_TEST_SUITE=OFF and HERMES_ENABLE_NAPI=OFF only shorten the
build; neither is load-bearing for the failure below.) Then:
cmake --build build --target jsiExpected: compiles. Actual: eleven cannot use 'throw' with exceptions disabled
in API/jsi/jsi/jsi.cpp. Building hermesvm_a fails the same way a little
later, in API/hermes.
Confirming the cause without building: build/build.ninja for a VM object
carries /DWIN32 /D_WINDOWS ... with the /EHsc gone and a double space where
it was; the same file from a v0.13.0 build under the same compiler carries
/DWIN32 /D_WINDOWS /EHsc ....
Environment
Windows 11 Pro 10.0.26200, x86-64
CMake 3.31.6-msvc6 (the one Visual Studio 2022 ships), Ninja 1.13.2
Visual Studio 2022 Community
> clang-cl --version
clang version 19.1.5
Target: x86_64-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\Llvm\x64\binProposed fix (one line)
In hermes_update_cxx_flags, test MSVC before GCC_COMPATIBLE — or branch on
the CLANG_CL the tree already computes — so a clang-cl build gets /EHsc,
/EHs-c-, /GR and /GR- rather than the -f... spellings it ignores.
Related issues
- #1247 (2024): the maintainers' answer was that Static Hermes would support Windows "only via Clang", and that the tree needs to "figure out how to automatically detect this particular configuration - Clang on Windows with MSVC-compatible CLI". The
CLANG_CLvariable atcmake/modules/Hermes.cmake:21is that detection; this issue is about the one function that does not consult it. - #1627 (open): a different failure under the Visual Studio generator's
-T ClangCL(the boost-context MASM file); not the same defect. - #2174: the same compiler-ID mistake in
API/jsi/jsi/CMakeLists.txt, whichhermes_update_cxx_flagsnever reaches. - The Windows CI job (
.github/workflows/build-hermesc-windows.yml) buildshermescwith the Visual Studio generator and MSVC'scl, so a clang-cl configure is not exercised by CI — which is consistent with every failure here being CMake meeting that compiler for the first time.
Where this came from
Measured while embedding static_h as the second runtime of a native game host on Windows (the repository is private at the time of filing, so no links). No file under the Hermes checkout was edited — the workaround is a directory-scope add_compile_options("$<$<COMPILE_LANGUAGE:CXX>:/EHsc>") in the consuming project, before add_subdirectory, which is what lets the whole tree compile and is how every number in this report was reached.
Source: facebook/hermes