[emscripten] Fix emdawnwebgpu_tests_jspi

GTest/GMock's CMake files don't seem to have any support for compiling
without exceptions. The previous fix [1] stopped working at some point
(probably a googletest roll), because it doesn't affect whether their
CMake files set -fexceptions. This new workaround works, though it will
be a little sensitive to future internal changes in GTest/GMock.

[1]: https://dawn-review.googlesource.com/c/dawn/+/213394

Fixed: 417768359
Change-Id: I1dd1e631cf6f0b9410ae60254569f26abe232c8b
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/247996
Commit-Queue: Kai Ninomiya <kainino@chromium.org>
Auto-Submit: Kai Ninomiya <kainino@chromium.org>
Reviewed-by: Loko Kung <lokokung@google.com>
diff --git a/src/emdawnwebgpu/CMakeLists.txt b/src/emdawnwebgpu/CMakeLists.txt
index d9155af..9f0bf2c 100644
--- a/src/emdawnwebgpu/CMakeLists.txt
+++ b/src/emdawnwebgpu/CMakeLists.txt
@@ -312,7 +312,7 @@
         set(emdawnwebgpu_test_deps
             dawn::dawn_wgpu_utils
             emdawnwebgpu_cpp
-            gmock_main
+            gmock_main_wasmsafe
         )
 
         add_executable(emdawnwebgpu_tests_asyncify ${emdawnwebgpu_test_sources})
diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt
index 627d362..a311314 100644
--- a/third_party/CMakeLists.txt
+++ b/third_party/CMakeLists.txt
@@ -89,16 +89,34 @@
     set(gtest_force_shared_crt ON CACHE BOOL "Controls whether a shared run-time library should be used even when Google Test is built as static library" FORCE)
     if (EMSCRIPTEN)
         # For Emscripten builds, we need to disable pthreads.
+        # https://discourse.cmake.org/t/set-definitions-for-external-sub-directory/1136
         set(gtest_disable_pthreads ON)
     endif()
 
-    # We don't use exceptions, so we don't need gtest to handle them. Emscripten
-    # builds in particular, with JSPI enabled, crash without this enabled.
-    # There doesn't seem to be an option to tell the gtest build files to do
-    # this, so we set it globally. (This seems to be the intended usage.)
-    add_definitions(-DGTEST_HAS_EXCEPTIONS=0)
-
     add_subdirectory(${DAWN_GOOGLETEST_DIR} "${CMAKE_CURRENT_BINARY_DIR}/googletest" EXCLUDE_FROM_ALL)
+
+    # The CMake target GTest::gmock_main always sets -fexceptions, which is
+    # incompatible with WASM JSPI (though works with Asyncify). The only way to
+    # avoid this is to define our own custom CMake rule for it.
+    # (This is based on GMock's internal `gmock_main_no_exception` target.)
+    add_library(gmock_main_wasmsafe
+        "${gtest_SOURCE_DIR}/src/gtest-all.cc"
+        "${gmock_SOURCE_DIR}/src/gmock-all.cc"
+        "${gmock_SOURCE_DIR}/src/gmock_main.cc"
+    )
+    target_compile_options(gmock_main_wasmsafe
+        PUBLIC
+            "-fno-exceptions"
+            "-fno-rtti"
+    )
+    target_include_directories(gmock_main_wasmsafe SYSTEM
+        PRIVATE
+            "${gtest_SOURCE_DIR}"
+            "${gmock_SOURCE_DIR}"
+        PUBLIC
+            "${gtest_SOURCE_DIR}/include"
+            "${gmock_SOURCE_DIR}/include"
+    )
 endif()
 ################################################################################
 # End of Emscripten enabled third party directories