|
| 1 | +#[[ |
| 2 | +Regression test for #155: WASM builds were broken because |
| 3 | +cmake/Emscripten.cmake combined two flags that newer Emscripten releases |
| 4 | +reject in the same translation unit: |
| 5 | +
|
| 6 | + * -fwasm-exceptions (set via add_compile_options / add_link_options) |
| 7 | + * -sASYNCIFY=1 (set via target_link_options on each WASM target) |
| 8 | +
|
| 9 | +The link step ended in `wasm-opt` with |
| 10 | +`Fatal: Module::getFunction: __asyncify_get_call_index does not exist` |
| 11 | +because the legacy Asyncify transformation is incompatible with native |
| 12 | +WebAssembly exception handling. |
| 13 | +
|
| 14 | +Per the issue ("Prefer the modern replacement features") the project |
| 15 | +should use JSPI (JavaScript Promise Integration) instead, which is the |
| 16 | +upstream-recommended replacement for legacy Asyncify and works alongside |
| 17 | +-fwasm-exceptions. |
| 18 | +
|
| 19 | +This test simulates an EMSCRIPTEN configuration, stubs the CMake commands |
| 20 | +that touch real targets, includes Emscripten.cmake, and asserts that: |
| 21 | +
|
| 22 | + 1. The legacy `-sASYNCIFY=1` flag is NOT emitted (regression guard). |
| 23 | + 2. The legacy `-sASYNCIFY_STACK_SIZE` flag is NOT emitted (irrelevant |
| 24 | + for JSPI). |
| 25 | + 3. The modern `-sJSPI=1` flag IS emitted on the WASM target. |
| 26 | + 4. `-fwasm-exceptions` is still active on the global compile/link |
| 27 | + options so native EH continues to be used. |
| 28 | +]] |
| 29 | + |
| 30 | +cmake_minimum_required(VERSION 3.21) |
| 31 | + |
| 32 | +set(EMSCRIPTEN TRUE) |
| 33 | + |
| 34 | +# Use the real source tree so EXISTS checks against the shell template pass |
| 35 | +# and Emscripten.cmake's input templates resolve correctly. |
| 36 | +set(CMAKE_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") |
| 37 | + |
| 38 | +# Caller (CTest) supplies an out-of-tree scratch dir via -DTEST_TMP_DIR=...; |
| 39 | +# fall back to the platform temp dir when the script is invoked manually. |
| 40 | +if(NOT DEFINED TEST_TMP_DIR OR TEST_TMP_DIR STREQUAL "") |
| 41 | + set(TEST_TMP_DIR "$ENV{TMPDIR}") |
| 42 | + if(TEST_TMP_DIR STREQUAL "") |
| 43 | + set(TEST_TMP_DIR "/tmp") |
| 44 | + endif() |
| 45 | + set(TEST_TMP_DIR "${TEST_TMP_DIR}/cmake_template_test_emscripten_modern_async") |
| 46 | +endif() |
| 47 | +set(CMAKE_BINARY_DIR "${TEST_TMP_DIR}") |
| 48 | +file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}") |
| 49 | + |
| 50 | +set(CAPTURE_FILE "${CMAKE_BINARY_DIR}/captured_options.txt") |
| 51 | +file(WRITE "${CAPTURE_FILE}" "") |
| 52 | + |
| 53 | +# Capture global compile / link options emitted at module-include time. |
| 54 | +function(add_compile_options) |
| 55 | + file(APPEND "${CAPTURE_FILE}" "ADD_COMPILE_OPTIONS:${ARGN}\n") |
| 56 | +endfunction() |
| 57 | + |
| 58 | +function(add_link_options) |
| 59 | + file(APPEND "${CAPTURE_FILE}" "ADD_LINK_OPTIONS:${ARGN}\n") |
| 60 | +endfunction() |
| 61 | + |
| 62 | +# Capture per-target link options. Drop the leading <target> <scope> args |
| 63 | +# so the captured payload is easy to grep. |
| 64 | +function(target_link_options) |
| 65 | + set(_args "${ARGN}") |
| 66 | + list(REMOVE_AT _args 0 1) |
| 67 | + file(APPEND "${CAPTURE_FILE}" "TARGET_LINK_OPTIONS:${_args}\n") |
| 68 | +endfunction() |
| 69 | + |
| 70 | +# Stub out the rest of the target-affecting commands so script mode |
| 71 | +# doesn't try to look up a real CMake target. |
| 72 | +function(target_compile_definitions) |
| 73 | +endfunction() |
| 74 | + |
| 75 | +function(get_target_property var target prop) |
| 76 | + set(${var} "${target}" PARENT_SCOPE) |
| 77 | +endfunction() |
| 78 | + |
| 79 | +function(set_target_properties) |
| 80 | +endfunction() |
| 81 | + |
| 82 | +function(add_custom_command) |
| 83 | +endfunction() |
| 84 | + |
| 85 | +function(configure_file) |
| 86 | +endfunction() |
| 87 | + |
| 88 | +function(set_property) |
| 89 | +endfunction() |
| 90 | + |
| 91 | +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/Emscripten.cmake") |
| 92 | + |
| 93 | +myproject_configure_wasm_target( |
| 94 | + fake_wasm_target |
| 95 | + TITLE "Fake" |
| 96 | + DESCRIPTION "Fake WASM target for regression test #155") |
| 97 | + |
| 98 | +file(READ "${CAPTURE_FILE}" captures) |
| 99 | +message(STATUS "Captured Emscripten options:\n${captures}") |
| 100 | + |
| 101 | +if(captures MATCHES "ASYNCIFY=1") |
| 102 | + message( |
| 103 | + FATAL_ERROR |
| 104 | + "Legacy -sASYNCIFY=1 must not be emitted: it is incompatible with " |
| 105 | + "-fwasm-exceptions and breaks WASM linking (#155). Captured:\n${captures}") |
| 106 | +endif() |
| 107 | + |
| 108 | +if(captures MATCHES "ASYNCIFY_STACK_SIZE") |
| 109 | + message( |
| 110 | + FATAL_ERROR |
| 111 | + "-sASYNCIFY_STACK_SIZE is only meaningful for legacy Asyncify and " |
| 112 | + "should be removed alongside -sASYNCIFY=1 (#155). Captured:\n${captures}") |
| 113 | +endif() |
| 114 | + |
| 115 | +if(NOT captures MATCHES "-sJSPI=1") |
| 116 | + message( |
| 117 | + FATAL_ERROR |
| 118 | + "Expected modern -sJSPI=1 flag (replacement for legacy Asyncify) on " |
| 119 | + "the WASM target (#155). Captured:\n${captures}") |
| 120 | +endif() |
| 121 | + |
| 122 | +if(NOT captures MATCHES "-fwasm-exceptions") |
| 123 | + message( |
| 124 | + FATAL_ERROR |
| 125 | + "-fwasm-exceptions must remain enabled for WASM builds; the fix " |
| 126 | + "for #155 should switch async support, not disable native EH. " |
| 127 | + "Captured:\n${captures}") |
| 128 | +endif() |
0 commit comments