Enable browser-wasm runtime tests that require native library relinking - #131866
Enable browser-wasm runtime tests that require native library relinking#131866radekdoulik wants to merge 15 commits into
Conversation
WebAssembly has no dynamic library loading, so a runtime test that calls into its own native code cannot use the shared corerun. Each such test needs its own corerun with that code statically linked in. Export the pieces needed to relink corerun out of tree: a corerun_static archive, every archive corerun links in dependency order, the emscripten --js-library inputs, the headers the generated call tables include, and compile and link response files. The kit is installed next to the other coreclr artifacts as corerun-link/. Paths inside the response files use a !CORERUN_KIT_DIR! placeholder that the consumer substitutes, so the kit stays relocatable. '@' is a response-file include prefix and '%' collides with MSBuild item metadata, hence '!'. The link closure is computed by walking the CMake target graph rather than hardcoded, so it cannot drift from what corerun actually links. The walker resolves TARGET_NAME_IF_EXISTS and fails the build on any other generator expression rather than silently dropping a link input, and it keeps raw library paths and bare library names, which ICU and stdc++ arrive as. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
For a browser-wasm test project that builds its own native library, regenerate the P/Invoke, reverse P/Invoke and interpreter call tables with ManagedToNativeGenerator, compile them with em++, and link them together with the test's static library and the corerun link kit into a corerun.js next to the test assemblies. The generator is fed the runtime pack as well as the test's own assemblies, because the framework portion of the tables is derived from System.Private.CoreLib and the rest of the BCL. The result is byte-identical to the checked-in tables in src/coreclr/vm/wasm/browser apart from the test's own entries. CI builds managed test components once for all platforms and does the platform-specific work in a later copynativeonly pass, so the work is hooked after Build or after CopyAllNativeProjectReferenceBinaries depending on which pass is running, and skipped entirely during the managed-only allTargets pass. The whole kit payload is tracked as a build input, not just the response files. Those only carry relocatable path tokens, so their contents do not change when the runtime is rebuilt, and tracking them alone would leave a test silently linked against the previous runtime. Merged test runners copy only dynamic libraries, so a test that needs this must set RequiresProcessIsolation; the build fails with an explicit message rather than silently producing a test that cannot find its native code. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
Prefer a corerun.js sitting next to the test assemblies over the shared one from CORE_ROOT. CORE_ROOT is still passed with -c, because the test-specific corerun loads the same shared CLR assemblies; only the host binary differs. Test directories without their own native code contain no corerun.js and are unaffected. Export __TestNativeAssetsLinked from the same branch that makes the choice, so the signal cannot get out of step with which host is actually running. It is also set explicitly in the negative branch, so an ambient value cannot be inherited from outside the test process. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
PlatformDoesNotSupportNativeTestAssets was unconditionally true for browser and wasi. On browser the answer now differs per test in the same build, depending on whether that test got a corerun with its native code linked in, so take the answer from the run script rather than from the platform. This keeps the roughly 140 sites that consult the property untouched: a test whose native library is not built produces no corerun, so the signal stays unset and the test stays skipped. wasi behaviour is unchanged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
The test skipped sumTwoInts, sumTwoDoubles and writeToStdout on wasm because there was no way to link the test's native library into the host. There is now. writeToStdout was declared as returning int while pinvoke.cpp defines it as void. Elsewhere that only means the caller reads a garbage return value, but wasm type-checks indirect calls, so invoking a (i32)->() function through a (i32)->i32 signature traps. Match the declaration to the native definition. The missingLibrary imports are untouched and still assert that a P/Invoke to a library that was never linked in throws DllNotFoundException. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
Every native test library hardcoded SHARED. WebAssembly has no dynamic loading, so a shared library is of no use there and each test's native code has to be linked into the binary that runs it. Replace the SHARED keyword with the TEST_LIB_TYPE variable so the top level test CMakeLists can choose. No behaviour change: TEST_LIB_TYPE is SHARED everywhere today. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
The browser build opted a single directory into the native test build. Recurse over the whole tree like every other platform does, and select STATIC libraries so each test's native code can be linked into a test-specific corerun. Only the browser links those libraries into a corerun, so wasi keeps building just the one directory. Two sources needed adjusting to compile: GenericsNative.Vector*.cpp rejected any architecture it did not know. Let wasm take the plain-struct fallback already used by LOONGARCH64 and RISCV64. mono-embedding-api-test.c declared VoidVoidCallback inside a block excluded on wasm but used it outside, so hoist the typedef. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
A test merged into a runner assembly runs from the runner's directory, not its own, and the runner references the same CMake project, so its native code is already linked into the runner's corerun. Building a second one for the merged in project produced an unused binary, and the process isolation check rejected the project outright. Skip those, and narrow the check to projects that really do run from their own output directory. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
Some tests have a native interop surface the wasm P/Invoke generator or the wasm linker cannot handle yet: multi-field structs the signature mapper does not know, reverse P/Invoke delegates taking structs, deliberately missing entry points that a static call table turns into link errors, and module-name spellings that collide in the generated table. Those failures all happen while building the test-specific corerun, so an [ActiveIssue] on the test method cannot help - the generator walks the assembly's whole interop surface regardless of which tests xunit would run. Opt these tests out of the corerun instead of disabling them. They keep building and running against CORE_ROOT's corerun exactly as before, and their native-dependent methods skip through the existing PlatformDoesNotSupportNativeTestAssets gate. Profiler tests stay disabled: they spawn a second corerun process and load the profiler from a shared library path, neither of which exists on wasm. Tracked by dotnet#131811 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
The test-specific corerun is linked during copynativeonly, which is the first point in CI where the managed test assemblies, the native test archives and the runtime pack all coexist. That job only downloads and copies artifacts, so it is missing two things the link needs. em++ is absent because nothing in the job builds natively, and so nothing populates the shared wasm tool cache that eng/native/gen-buildsys.sh resolves; that helper only looks for an existing .complete stamp and never provisions. Emscripten is normally acquired by AcquireEmscriptenSdk as a dependency of BuildRuntime, which runs in the product build job instead. WasmAppBuilder is absent at the expected path because the test build sets Configuration from __BuildType, making TasksConfiguration Checked, while the downloaded artifacts only carry the product build's Release tasks. Both are covered by building the provision.emsdk and tasks subsets in the test configuration before the copy step runs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
The browser CoreCLR test build links each test's native library into a test-specific corerun. Nothing does that on the mono browser leg or on wasi, so configuring the whole tree there compiles every native test library for nothing. The tests build never told CMake which runtime flavor it was building for, so pass it the same way the product build does, and walk the full tree on wasm only when a corerun will actually consume the result. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
|
Azure Pipelines: Successfully started running 6 pipeline(s). 10 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
There was a problem hiding this comment.
Pull request overview
Enables previously-skipped browser-wasm CoreCLR runtime tests that depend on test-supplied native libraries by producing a per-test, statically-linked corerun.js/.wasm and wiring the test runner to prefer it when present.
Changes:
- Add a browser-wasm “corerun link kit” export from the CoreCLR
corerunbuild and a new MSBuild target (CLRTest.WasmCorerun.targets) to re-linkcorerunper test with generated P/Invoke tables + test native archives. - Flip test native libraries to build as
${TEST_LIB_TYPE}(static on wasm, shared elsewhere) and adjust test tree walking/runner gating for wasm flavor/OS. - Update browser run-test CI to provision Emscripten + build tasks, and update run scripts +
PlatformDetectionto enable native-asset-gated tests when a test-specific corerun is used.
Reviewed changes
Copilot reviewed 180 out of 180 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| eng/pipelines/common/templates/runtimes/run-test-job.yml | Provision provision.emsdk+tasks for browser run-test so per-test relink has em++ and matching tasks. |
| src/coreclr/hosts/corerun/CMakeLists.txt | Export browser-wasm corerun link kit and refactor corerun sources/options to support kit export. |
| src/coreclr/hosts/corerun/wasm/coreclr_compat.h | New compat header pre-included when compiling generated callhelpers-*.cpp out-of-tree. |
| src/coreclr/hosts/corerun/wasm/testkit.cmake | New CMake module that exports corerun’s link closure + response files for test relinking. |
| src/tests/CMakeLists.txt | Define TEST_LIB_TYPE (STATIC on wasm; SHARED otherwise) and gate full tree build based on wasm + runtime flavor. |
| src/tests/Common/CLRTest.Execute.Batch.targets | Prefer local corerun.js (when present) and set __TestNativeAssetsLinked for browser runs on Windows. |
| src/tests/Common/CLRTest.Execute.Bash.targets | Prefer local corerun.js (when present) and export __TestNativeAssetsLinked for browser runs on Unix. |
| src/tests/Common/CLRTest.WasmCorerun.targets | New MSBuild targets to generate call helpers and link a test-specific corerun.js/.wasm for browser CoreCLR tests with native archives. |
| src/tests/Common/CoreCLRTestLibrary/PlatformDetection.cs | Make browser/wasi native-test-asset gating depend on __TestNativeAssetsLinked. |
| src/tests/Common/hostpolicymock/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Directory.Build.targets | Ensure merged test runners copy *$(StaticLibSuffix) on browser so wrapper corerun can link native archives. |
| src/tests/JIT/Directed/Convert/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/PrimitiveABI/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/StructABI/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/StructABI/EmptyStructs.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/StructABI/StructABI.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/aliasing_retbuf/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/aliasing_retbuf/aliasing_retbuf.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/arglist/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/callconv/CMakeLists.txt | Build test native libraries as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/callconv/CdeclMemberFunction/CdeclMemberFunctionTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/callconv/EmptyThisCallTest/EmptyThisCallTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/callconv/PlatformDefaultMemberFunction/PlatformDefaultMemberFunctionTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/callconv/StdCallMemberFunction/StdCallMemberFunctionTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/callconv/ThisCall/ThisCallTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/Directed/pinvoke/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/pinning/object-pin/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Directed/tls/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Methodical/Methodical_others.csproj | Opt out of wasm test-specific corerun for merged runner with reverse-P/Invoke content. |
| src/tests/JIT/Methodical/gc_poll/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Methodical/structs/systemvbringup/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Regression/JitBlue/Runtime_101046/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Regression/JitBlue/Runtime_76194/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/Regression/VS-ia64-JIT/V1.2-M02/b108129/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/SIMD/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/JIT/SIMD/Vector3Interop_r.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/SIMD/Vector3Interop_ro.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/JIT/interpreter/Interpreter.cs | Fix P/Invoke signature (writeToStdout return type) and enable P/Invoke execution on wasm. |
| src/tests/Interop/ArrayMarshalling/BoolArray/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/ArrayMarshalling/SafeArray/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/BestFitMapping/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/COM/ComWrappers/MockReferenceTrackerRuntime/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/COM/ComWrappers/WeakReference/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/COM/Dynamic/Server/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/COM/NativeServer/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/COM/RuntimeAsync/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/DllImportAttribute/DllImportPath/CMakeLists.txt | Build test native libraries as ${TEST_LIB_TYPE}. |
| src/tests/Interop/DllImportAttribute/DllImportPath/DllImportPathTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DllImportAttribute/ExactSpelling/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/DllImportAttribute/ExactSpelling/ExactSpellingTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DllImportSearchPaths/NativeLibraryWithDependency/CMakeLists.txt | Build dependency/test native libraries as ${TEST_LIB_TYPE}. |
| src/tests/Interop/DisabledRuntimeMarshalling/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyDisabled.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeAssemblyEnabled.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_Disabled_NativeTypeInAssembly_ro.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DisabledRuntimeMarshalling/DisabledRuntimeMarshalling_NativeAssemblyDisabled.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DisabledRuntimeMarshalling/Native_Default/DisabledRuntimeMarshallingNative_Default.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/DisabledRuntimeMarshalling/Native_DisabledMarshalling/DisabledRuntimeMarshallingNative_DisabledMarshalling.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/ExecInDefAppDom/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/FuncPtrAsDelegateParam/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/GCBridge/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/ICustomMarshaler/ConflictingNames/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/ICustomMarshaler/Primitives/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/ICustomMarshaler/Primitives/ICustomMarshaler_TargetUnix.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/IJW/CopyConstructorMarshaler/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/IJW/IjwNativeCallingManagedDll/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/IJW/IjwNativeDll/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/IJW/NativeVarargs/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/IJW/ijwhostmock/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/Interop.csproj | Opt out of wasm test-specific corerun for merged wrapper due to unsupported interop surface. |
| src/tests/Interop/LayoutClass/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/MarshalAPI/FunctionPointer/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/MonoAPI/Native/mono-embedding-api-test/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/MonoAPI/Native/mono-embedding-api-test/mono-embedding-api-test.c | Move typedef to be visible on wasm build paths. |
| src/tests/Interop/NativeLibrary/Callback/CallbackStressTest_TargetUnix.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/NativeLibrary/Callback/CallbackTests.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/NativeLibrary/NativeLibraryToLoad/CMakeLists.txt | Build test native libraries as ${TEST_LIB_TYPE}. |
| src/tests/Interop/Object iveC/AutoReleaseTest/CMakeLists.txt | Build Objective-C test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/ObjectiveC/ObjectiveCMarshalAPI/CMakeLists.txt | Build Objective-C test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Array/MarshalArrayAsField/LPArrayNative/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Array/MarshalArrayAsParam/LPArrayNative/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/ArrayWithOffset/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/AsAny/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Attributes/LCID/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/BestFitMapping/Char/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/BestFitMapping/LPStr/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/CriticalHandles/ArrayTest/ArrayTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/PInvoke/CriticalHandles/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/CriticalHandles/StructTest/StructTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/PInvoke/CriticalHandles/Test/Test.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/PInvoke/CustomMarshalers/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/DateTime/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Decimal/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Decimal128/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Delegate/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Generics/CMakeLists.txt | Build generics native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector128B.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector128C.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector128D.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector128F.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector128L.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector128U.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector256B.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector256C.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector256D.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector256F.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector256L.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector256U.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector64B.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector64C.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector64D.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector64F.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector64L.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/Generics/GenericsNative.Vector64U.cpp | Treat TARGET_WASM like other non-xarch paths for vector typedefs/includes. |
| src/tests/Interop/PInvoke/IEnumerator/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Int128/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Miscellaneous/HandleRef/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Miscellaneous/MultipleAssembliesWithSamePInvoke/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/NativeCallManagedComVisible/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Primitives/Int/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Primitives/Pointer/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Primitives/RuntimeHandles/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/SafeHandles/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/SetLastError/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/SizeParamIndex/PInvoke/PassingByOut/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/SizeParamIndex/PInvoke/PassingByRef/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/SizeParamIndex/ReversePInvoke/PassingByOut/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/SizeParamIndex/ReversePInvoke/PassingByRef/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Varargs/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Variant/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PInvoke/Vector2_3_4/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PrimitiveMarshalling/Bool/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PrimitiveMarshalling/EnumMarshalling/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/PrimitiveMarshalling/UIntPtr/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/RefCharArray/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/SimpleStruct/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StringMarshalling/AnsiBSTR/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StringMarshalling/BSTR/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StringMarshalling/LPSTR/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StringMarshalling/LPTSTR/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StringMarshalling/UTF8/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StringMarshalling/VBByRefStr/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StructMarshalling/PInvoke/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StructMarshalling/PInvoke/MarshalStructAsLayoutSeq.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/StructMarshalling/PInvoke/NestedStruct.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/StructMarshalling/ReversePInvoke/MarshalExpStruct/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StructMarshalling/ReversePInvoke/MarshalSeqStruct/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/StructMarshalling/ReversePInvoke/MarshalSeqStruct/DelegatePInvoke/DelegatePInvokeTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/StructMarshalling/ReversePInvoke/MarshalSeqStruct/ReversePInvoke/ReversePInvokeTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/SuppressGCTransition/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/UnmanagedCallConv/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/UnmanagedCallersOnly/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Interop/UnmanagedCallersOnly/UnmanagedCallersOnlyTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Interop/UnmanagedCallersOnlyBasic/UnmanagedCallersOnlyBasicTest.csproj | Opt out of wasm test-specific corerun for this project (interop surface currently unsupported). |
| src/tests/Loader/NativeLibs/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Regressions/coreclr/GitHub_102887/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Regressions/coreclr/GitHub_111242/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/Regressions/coreclr/GitHub_117393/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/build.cmd | Forward CMAKE_BUILD_RUNTIME_FLAVOR into CMake args for tests. |
| src/tests/build.sh | Forward CMAKE_BUILD_RUNTIME_FLAVOR into CMake args for tests. |
| src/tests/nativeaot/SmokeTests/PInvoke/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
| src/tests/profiler/Directory.Build.props | Mark profiler tests unsupported on browser due to lack of process/dynamic loading. |
| src/tests/profiler/ijw/CMakeLists.txt | Build profiler test native library as ${TEST_LIB_TYPE}. |
| src/tests/profiler/native/CMakeLists.txt | Build profiler test native library as ${TEST_LIB_TYPE}. |
| src/tests/readytorun/tests/CMakeLists.txt | Build test native library as ${TEST_LIB_TYPE}. |
Suppressed comments (1)
src/tests/Common/CLRTest.WasmCorerun.targets:145
- Same
%24(...)issue here:%24(EMSDK_PATH)will be printed literally. Since this is describing an environment variable/property, the message is clearer if it just saysSet EMSDK_PATH(orSet $(EMSDK_PATH)if you intend the MSBuild property value).
<Error Condition="'$(_WasmCorerunSkip)' != 'true' and ('$(_WasmCorerunEmxx)' == '' or !Exists('$(_WasmCorerunEmxx)'))"
Text="Could not find em++ for the test-specific corerun. Set %24(EMSDK_PATH), or build the browser-wasm runtime first so that the Emscripten SDK is provisioned into '$(EmscriptenSdkCacheDir)'." />
The ICU archives reach corerun's link line as absolute paths built from CMAKE_ICU_DIR, which comes from MSBuild and so uses backslashes when the build runs on a Windows host. install() writes those paths into cmake_install.cmake as quoted strings, where CMake reads a backslash as an escape, so exporting the kit failed with "Invalid character escape". It also broke the basename the response file refers to them by, which would have produced an unlinkable kit even where the install succeeded. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 180 out of 180 changed files in this pull request and generated no new comments.
Suppressed comments (3)
src/coreclr/hosts/corerun/wasm/testkit.cmake:10
- The header comment points readers to
src/tests/Common/CLRTest.NativeRelink.targets, but this PR introducesCLRTest.WasmCorerun.targetsinstead. Keeping this reference accurate matters since it’s the primary breadcrumb for understanding how the kit is consumed.
# WASM has no dynamic library loading, so a runtime test that P/Invokes into its
# own native library cannot run against the prebuilt corerun.js -- the test's
# native code, and the call tables generated for it, have to be linked into the
# host itself. The runtime test build therefore re-links a test-specific corerun
# outside of CMake (see src/tests/Common/CLRTest.NativeRelink.targets).
src/tests/profiler/native/CMakeLists.txt:54
- This directory is now marked
CLRTestTargetUnsupportedfor browser, but its native CMake project still builds on wasm when the test tree is fully walked. Skipping this native target on wasm avoids spending build time on an unsupported test area and avoids pulling in non-wasm link dependencies (e.g., pthread/dl) for a target that will never run there.
src/tests/Common/CLRTest.WasmCorerun.targets:201 - The comment says MSBuild would reinterpret any '%xx' escapes when round-tripping the response-file text, but the guard only checks for the literal string '%25'. If the intent is to fail on any percent-escape sequence, the condition should check for '%' (and the error text should match).
<!-- The text round-trips through MSBuild properties and WriteLinesToFile, which would split on
';' and reinterpret '%xx'. testkit.cmake never emits either; fail loudly if that changes. -->
<Error Condition="$(_WasmCorerunCompileRspText.Contains(';')) or $(_WasmCorerunLinkRspText.Contains(';')) or
$(_WasmCorerunCompileRspText.Contains('%25')) or $(_WasmCorerunLinkRspText.Contains('%25'))"
Text="The corerun link kit response files must not contain ';' or '%25' - see src/coreclr/hosts/corerun/wasm/testkit.cmake." />
…or run The priority 1 test set brings in five more projects with native assets. Two of them fail to build a test-specific corerun, hitting the same generator and wasm-ld gaps the priority 0 opt-outs already cover, and three build one but fail at run time: BestFitMapping and FuncPtrAsDelegateParam call Marshal.GetFunctionPointerForDelegate, which needs dynamic entrypoint allocation that wasm does not support, and EnumTest traps with a function signature mismatch in its delegate p/invoke scenarios. Leave all five on CORE_ROOT/corerun.js so their native-dependent tests keep skipping, as they do today. PInvokeUIntPtrTest, the sixth new project, links and passes, so it keeps its own corerun. This matters beyond the priority 0 lanes: eng/pipelines/coreclr/ci.yml runs browser wasm runtime tests with testGroup outerloop, which maps to priority 1. Tracked by dotnet#131811 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
Fix a stale breadcrumb in testkit.cmake that pointed at a file name the kit never shipped under, and stop compiling the profiler test library on wasm. The profiler tree is already CLRTestTargetUnsupported for browser, but its native directory is picked up by the recursive globber in src/tests, so it built 30+ sources that nothing can ever link. Guard it the same way the sibling ijw directory guards itself, which drops the browser native test build from 118 static archives to 117. Also note why the '%24' and '%25' escapes in CLRTest.WasmCorerun.targets are deliberate: '%24' keeps a property name literal in an error message instead of expanding it, and '%25' is an escaped '%', so the response-file guard already rejects any percent escape. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 19490400-17c9-47ef-9240-064c65690470
|
Thanks for the review. Responses to the three suppressed comments, since I can't reply to those inline:
Correct, and this was real waste I introduced. Enabling
Verified rather than assumed: I've amended the comment in 2ffdb87 to spell out that
Note This comment was drafted with GitHub Copilot. |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 185 out of 185 changed files in this pull request and generated no new comments.
Suppressed comments (2)
src/tests/Common/CoreCLRTestLibrary/PlatformDetection.cs:107
- PlatformDoesNotSupportNativeTestAssets treats both Browser and WASI as gated by s_nativeTestAssetsLinked, but s_nativeTestAssetsLinked is computed via IsEnvironmentVariableTrue which currently returns false unless IsBrowser. That makes the WASI branch effectively always report "does not support" even if __TestNativeAssetsLinked is set, and is inconsistent with the new (IsBrowser || IsWasi) condition.
public static bool PlatformDoesNotSupportNativeTestAssets =>
OperatingSystem.IsIOS() || OperatingSystem.IsTvOS() || OperatingSystem.IsAndroid()
|| ((OperatingSystem.IsBrowser() || OperatingSystem.IsWasi()) && !s_nativeTestAssetsLinked);
private static readonly bool s_nativeTestAssetsLinked = IsEnvironmentVariableTrue("__TestNativeAssetsLinked");
src/coreclr/hosts/corerun/CMakeLists.txt:67
- The wasm-only pinvoke_override.cpp path is duplicated in both list(APPEND CORERUN_SOURCES ...) (for corerun_kit_export) and target_sources(...) (for the corerun target). Introducing a small variable avoids accidental drift if this list grows (e.g., adding another wasm-only source later).
if (CLR_CMAKE_TARGET_ARCH_WASM)
list(APPEND CORERUN_SOURCES ./wasm/pinvoke_override.cpp)
target_sources(corerun PRIVATE ./wasm/pinvoke_override.cpp)
target_include_directories(corerun PRIVATE ./wasm/)
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 185 out of 185 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/tests/Common/CLRTest.WasmCorerun.targets:329
- The link target produces both
corerun.jsandcorerun.wasm, butOutputsonly lists the.js. This means the target can be considered up-to-date even ifcorerun.wasmis missing (e.g., after a partial clean), leaving a broken test run without rebuilding.
<Target Name="_WasmLinkTestCorerun"
DependsOnTargets="_WasmResolveTestCorerunInputs"
Condition="'$(_WasmCorerunSkip)' != 'true'"
Inputs="@(_WasmCorerunGeneratedSource->'%(ObjectFile)');@(_WasmCorerunTestLib);@(_WasmCorerunKitLinkInput);$(_WasmCorerunLinkRsp)"
Outputs="$(_WasmCorerunJs)">
<Message Importance="High" Text="$(MSBuildProjectName) -> $(_WasmCorerunJs)" />
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
WebAssembly has no dynamic loading, so a runtime test that ships its own native library cannot
dlopenit the way every other platform does. Those tests are currently skipped on browser-wasm.This builds a test-specific
corerunfor each such test: the same object closure assrc/coreclr/hosts/corerun, statically linked together with the test's own native library and afreshly generated P/Invoke call table. It lands next to the test's other artifacts, and the
generated run script prefers it over
CORE_ROOT/corerun.js.This is deliberately separate from the wasm app-relink path — no SDK targets, no
BrowserWasmApp.CoreCLR.targets, noWasmApp.InTree.*. The only shared piece is theManagedToNativeGeneratortask assembly, which is reused as-is.How it works
src/coreclr/hosts/corerun/wasm/testkit.cmake) — the browser-wasm build walkscorerun's link closure and exports the objects and static libs to
artifacts/bin/coreclr/browser.wasm.<cfg>/corerun-link/.src/tests/Common/CLRTest.WasmCorerun.targets) — for a test with nativeproject references, runs
ManagedToNativeGeneratorover the test assembly plus the BCL to emitcallhelpers-*.cpp, thenem++-links kit + test.a+ generated sources into the test's owncorerun.js/corerun.wasm.CLRTest.Execute.Bash.targets) — uses the localcorerun.jswhen present andexports
__TestNativeAssetsLinked=true, which flipsPlatformDetection.PlatformDoesNotSupportNativeTestAssetsso the previously-skipped testsactually execute.
Native test libraries build as
${TEST_LIB_TYPE}—STATICon wasm,SHAREDeverywhere else — sono other platform changes behaviour.
src/tests/CMakeLists.txtnow usesADDSUBDIR_RECfor browserlike other platforms, which is what gets those libraries built at all.
The browser run-test job gains one step that builds the
provision.emsdkandtaskssubsets, sincethe link needs
em++and aWasmAppBuildermatching the test build'sTasksConfiguration, neitherof which that job previously had.
Coverage delta
+20 test methods newly executing on browser-wasm, 0 lost:
Interop/DllImportSearchPaths/DllImportSearchPathsTestInterop/ICustomMarshaler/ConflictingNames/MultipleALCsInterop/ICustomMarshaler/ConflictingNames/SameNameDifferentAssemblyInterop/SuppressGCTransition/SuppressGCTransitionTestSkipOnCoreClr, interpreter)Interop/UnmanagedCallConv/UnmanagedCallConvTestJIT/Directed/PrimitiveABI/PrimitiveABIJIT/Regression/JitBlue/Runtime_101046JIT/Regression/JitBlue/Runtime_76194JIT/interpreter/InterpreterTesterWhat stays opted out
34 projects set
WasmBuildTestCorerun=false— they still build and run, exactly as onmain;only their native-dependent test methods skip. Five pre-existing wasm interop gaps block a corerun
for them, all tracked in a single issue (#131811): unsupported multi-field structs in
SignatureMapper(WASM0067), reverse-P/Invoke delegates with struct parameters, deliberatelyundefined symbols in negative tests, duplicate generated entries from multiple module-name
spellings, and
NativeLibrary.Load/GetExportwhich route throughdlopen.The profiler tree is marked
CLRTestTargetUnsupportedfor browser. It spawns a child corerunprocess and loads the profiler from a shared-library path, so it cannot work here — and it never ran
on browser anyway (
main's browser Helix job has 74 work items, none of them profiler), so thisloses no coverage.
Validation
src/testsbrowser build: clean, 0 errors.__TestNativeAssetsLinkedgate was verified end-to-end by A/B-running every affected assemblyand observing the out-of-process skip status file — 7 of 9 flip from "all skipped" to "ran".
JIT/interpreteralong the way:writeToStdoutwas declaredintbut defined
void, which traps on wasm because indirect calls are type-checked.Notes for reviewers
copynativeonlyin the browser run-test job, which is the firstpoint in CI where the managed test assemblies, the native archives and the runtime pack all
coexist. That job previously only downloaded and copied artifacts, so it was missing both
em++and a
Checked-configurationWasmAppBuilder; the addedprovision.emsdk+tasksstep coversboth. Both gaps were confirmed against a real
mainbuild (1538732) rather than assumed — itsrun-test log has zero
emsdkhits across 31,562 lines, and its artifact listing carries onlyWasmAppBuilder/Release/.follow-up.
src/teststree is gated on runtime flavour, not just target OS, so the monobrowser leg keeps building
JIT/interpreteralone as it does today instead of compiling ~118static libs it has no way to link. The tests build did not pass a flavour to CMake at all, so
build.sh/build.cmdnow forwardCMAKE_BUILD_RUNTIME_FLAVORthe same way the product builddoes. Verified by building both flavours: mono produces 3 archives, CoreCLR still produces 118.
5e11891dfc1is a purely mechanicalSHARED→${TEST_LIB_TYPE}sweep over 111 files. It isisolated in its own commit and could be split into a separate PR if that is preferred, though the
rest of the change does not build without it.
Note
Parts of this pull request description were generated with GitHub Copilot.