From bfefb8f0ecdc4e059bb8705e914a22c87002772e Mon Sep 17 00:00:00 2001 From: Fedor Chelnokov Date: Tue, 20 Oct 2026 12:37:59 +0300 Subject: [PATCH 1/5] Windows wheels, NuGet payload, Rust and Java natives from the clang-cl CMake build The wheel job of pip-build.yml builds MeshLib the way the clang-cl jobs of build-test-windows.yml do: CMake + Ninja with the image's clang-cl and lld-link, x64 on the 14.4 toolset with the vs2022 vcpkg triplet and CUDA 12.0.1, arm64 on VS2026 with CUDA 13.4.1; MSBuild leaves that job. The NuGet payload (DotNetPatchArchiveWindows-*, DotNetDllXml) now comes from the clang-cl jobs, so the C# bindings are generated and tested there too; the MSBuild VS2026 jobs keep generating and testing them, and keep shipping the C++ developer distribution. The Rust crate natives and the Maven natives jars are cut from the NuGet package, so they follow. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/build-test-windows.yml | 15 ++++---- .github/workflows/pip-build.yml | 47 ++++++++++++++---------- 2 files changed, 35 insertions(+), 27 deletions(-) diff --git a/.github/workflows/build-test-windows.yml b/.github/workflows/build-test-windows.yml index 32b6a32904a0..95b03ed5686a 100644 --- a/.github/workflows/build-test-windows.yml +++ b/.github/workflows/build-test-windows.yml @@ -45,15 +45,16 @@ jobs: actions: read # This is required for wait-for-job env: - BUILD_C_SHARP: ${{ matrix.cxx_compiler == 'msvc-2026' && matrix.build_system == 'MSBuild' }} + # The C# bindings are generated and tested on the MSBuild VS2026 jobs and on the clang-cl jobs; + # the NuGet payload (the native DLLs, MRDotNet2.dll and its XML) comes from the clang-cl ones. + BUILD_C_SHARP: ${{ matrix.cxx_compiler == 'msvc-2026' && matrix.build_system == 'MSBuild' || matrix.cxx_compiler == 'clang-cl' }} PYTEST_C_SHARP_ARGS: --run-c-sharp-samples --csharp-sample-dir=..\source\${{ matrix.arch || 'x64' }}\${{ matrix.config }} VCPKG_DEFAULT_TRIPLET: ${{ matrix.vcpkg_triplet || 'x64-windows-meshlib' }} # Upload a developer distributive per Visual Studio toolchain and target # architecture so update-win-version can repackage each into # MeshLibDistVS{19,22,26}[-arm64].zip. - # VS2019/VS2022 ship the CMake build; VS2026 ships the MSBuild build - # (which also produces the C#/.NET components). VS_TAG keeps the archive - # names distinct. + # VS2019/VS2022 ship the CMake build; VS2026 ships the MSBuild build. + # VS_TAG keeps the archive names distinct. job_upload_artifact: ${{ inputs.upload_artifacts && ( matrix.cxx_compiler == 'msvc-2026' && matrix.build_system == 'MSBuild' || matrix.cxx_compiler != 'msvc-2026' && matrix.cxx_compiler != 'clang-cl' && matrix.build_system == 'CMake' ) }} # Only VS2026 has an arm64 leg, so the suffix separates it from the x64 VS26 archive VS_TAG: ${{ format('{0}{1}', fromJSON('{"msvc-2019":"VS19","msvc-2022":"VS22"}')[matrix.cxx_compiler] || 'VS26', matrix.arch == 'arm64' && '-arm64' || '') }} @@ -489,7 +490,7 @@ jobs: compression-level: 0 - name: Create and fix fake Wheel for NuGet - if: ${{ inputs.nuget_build && matrix.cxx_compiler == 'msvc-2026' && matrix.config == 'Release' && env.BUILD_C_SHARP == 'true' }} + if: ${{ inputs.nuget_build && matrix.cxx_compiler == 'clang-cl' && matrix.config == 'Release' && env.BUILD_C_SHARP == 'true' }} run: | py -3 -m venv wheel_venv wheel_venv\Scripts\Activate @@ -497,7 +498,7 @@ jobs: py -3 ./scripts/nuget_patch/patch_library_deps.py ./patched_content/ ./source/${{ env.MR_ARCH }}/Release/MeshLibC2.dll ./source/${{ env.MR_ARCH }}/Release/MeshLibC2Cuda.dll - name: Upload NuGet files to Artifacts - if: ${{ inputs.nuget_build && matrix.cxx_compiler == 'msvc-2026' && matrix.config == 'Release' && env.BUILD_C_SHARP == 'true' }} + if: ${{ inputs.nuget_build && matrix.cxx_compiler == 'clang-cl' && matrix.config == 'Release' && env.BUILD_C_SHARP == 'true' }} uses: actions/upload-artifact@v7 with: name: DotNetPatchArchiveWindows-${{ env.MR_ARCH }} @@ -508,7 +509,7 @@ jobs: - name: Upload NuGet library DLL and XML to Artifacts # These are netstandard2.0 and carry no architecture, so take them from the x64 # leg only; the arm64 one would only overwrite them with equivalent assemblies. - if: ${{ inputs.nuget_build && matrix.cxx_compiler == 'msvc-2026' && matrix.config == 'Release' && env.BUILD_C_SHARP == 'true' && matrix.arch != 'arm64' }} + if: ${{ inputs.nuget_build && matrix.cxx_compiler == 'clang-cl' && matrix.config == 'Release' && env.BUILD_C_SHARP == 'true' && matrix.arch != 'arm64' }} uses: actions/upload-artifact@v7 with: name: DotNetDllXml diff --git a/.github/workflows/pip-build.yml b/.github/workflows/pip-build.yml index f17829848f83..1b22539a5eb6 100644 --- a/.github/workflows/pip-build.yml +++ b/.github/workflows/pip-build.yml @@ -462,11 +462,12 @@ jobs: matrix: platform: [x64, arm64] include: + # Both build with the image's clang-cl through CMake, as the clang-cl jobs of build-test-windows.yml: + # x64 on the 14.4 (VS2022) toolset, which CUDA 12 needs, arm64 on VS2026. - platform: x64 runner: windows-2025 - vcpkg-triplet: x64-windows-meshlib - msbuild-platform: x64 - msbuild-architecture: x86 + vcpkg-triplet: x64-windows-vs2022-meshlib + vcvars-ver: '14.4' vs-dev-args: -arch=amd64 -host_arch=x86 plat-name: win-amd64 msys2-env: clang64 @@ -475,12 +476,10 @@ jobs: cuda-version: '12.0.1' cuda-major: '12' cuda-minor: '0' - cuda-platform-toolset: v143 - platform: arm64 runner: windows-11-vs2026-arm vcpkg-triplet: arm64-windows-meshlib - msbuild-platform: ARM64 - msbuild-architecture: arm64 + vcvars-ver: '14.5' vs-dev-args: -arch=arm64 -host_arch=arm64 plat-name: win-arm64 msys2-env: clangarm64 @@ -489,7 +488,6 @@ jobs: cuda-version: '13.4.1' cuda-major: '13' cuda-minor: '4' - cuda-platform-toolset: '' permissions: id-token: write # This is required for requesting the JWT contents: read # This is required for actions/checkout @@ -499,9 +497,8 @@ jobs: CUDA-MAJOR: ${{ matrix.cuda-major }} CUDA-MINOR: ${{ matrix.cuda-minor }} VCPKG_DEFAULT_TRIPLET: ${{ matrix.vcpkg-triplet }} - VCVARS_VER: '14.5' - PLATFORM_TOOLSET: v145 - CUDA_PLATFORM_TOOLSET: ${{ matrix.cuda-platform-toolset }} + VCVARS_VER: ${{ matrix.vcvars-ver }} + CMAKE_COMPILER_ARGS: -DCMAKE_CXX_COMPILER="C:/Program Files/LLVM/bin/clang-cl.exe" -DCMAKE_C_COMPILER="C:/Program Files/LLVM/bin/clang-cl.exe" -DCMAKE_LINKER_TYPE=LLD MSYS2_ENV: ${{ matrix.msys2-env }} steps: - name: Checkout @@ -543,16 +540,7 @@ jobs: with: cuda-major: ${{ env.CUDA-MAJOR }} cuda-minor: ${{ env.CUDA-MINOR }} - - - name: Add msbuild to PATH - uses: microsoft/setup-msbuild@30375c66a4eea26614e0d39710365f22f8b0af57 # v3.0.0 - with: - # an x86 MSBuild would make the VC props pick an x86 host compiler, whose address - # space is too small for our PCH when targeting ARM64 - msbuild-architecture: ${{ matrix.msbuild-architecture }} - - - name: Build - run: msbuild -m source\MeshLib.sln -p:Configuration=Release -p:Platform=${{ matrix.msbuild-platform }} -p:VcpkgTriplet=${{ env.VCPKG_DEFAULT_TRIPLET }} -p:PlatformToolset=${{ env.PLATFORM_TOOLSET }} -p:MRCudaPlatformToolset=${{ env.CUDA_PLATFORM_TOOLSET }} -p:MR_PCH_USE_EXTRA_HEADERS=ON -p:MRVOXELS_UNITY_BUILD=ON -p:MESHLIB_BUILD_MCP=OFF + install-vs-integration: false - name: Install MSYS2 for MRBind uses: ./.github/actions/install-msys2-mrbind @@ -567,6 +555,25 @@ jobs: extra-cache-key: ${{ hashFiles(format('scripts/mrbind/msys2_package_hashes{0}.txt', matrix.msys2-pkgs)) }} msys2-env: ${{ matrix.msys2-env }} + - name: Build + shell: cmd + env: + GETTEXT_ROOT: C:\msys64\clang64 + VCPKG_ROOT: C:\vcpkg + VCPKG_TARGET_TRIPLET: ${{ matrix.vcpkg-triplet }} + # The CMake branch of the Build step of build-test-windows.yml, Release only; see the notes there + # on `|| exit /b 1` and on the serial z-applocal pass. + run: | + call "${{ env.VC_PATH }}\Common7\Tools\VsDevCmd.bat" ${{ matrix.vs-dev-args }} -vcvars_ver=${{ env.VCVARS_VER }} || exit /b 1 + cmake --version || exit /b 1 + cmake -B source\TempOutput -GNinja -DCMAKE_BUILD_TYPE=Release %CMAKE_COMPILER_ARGS% -DVCPKG_TARGET_TRIPLET=%VCPKG_TARGET_TRIPLET% -DVCPKG_APPLOCAL_DEPS=OFF -DMESHLIB_BUILD_GENERATED_C_BINDINGS=OFF -DMESHLIB_BUILD_MRCUDA=${{ matrix.cuda-version != '' && 'ON' || 'OFF' }} -DMESHLIB_BUILD_MCP=OFF -DMR_PCH_USE_EXTRA_HEADERS=ON -DMRVOXELS_UNITY_BUILD=ON || exit /b 1 + cmake --build source\TempOutput -j || exit /b 1 + for %%b in (source\TempOutput\bin\*.exe source\TempOutput\bin\*.dll) do ( + %VCPKG_ROOT%\vcpkg.exe z-applocal --target-binary="%%b" --installed-bin-dir="%VCPKG_ROOT%\installed\%VCPKG_TARGET_TRIPLET%\bin" >nul || exit 1 + ) + if not exist source\${{ matrix.platform }} mkdir source\${{ matrix.platform }} || exit /b 1 + xcopy source\TempOutput\bin\* source\${{ matrix.platform }}\Release\* /s /e /i /Y || exit /b 1 + - name: Generate and build MRBind bindings shell: cmd env: From b227a6246f1c0f152752161a95d70d26dbaa1b70 Mon Sep 17 00:00:00 2001 From: Fedor Chelnokov Date: Tue, 20 Oct 2026 13:05:36 +0300 Subject: [PATCH 2/5] pip-build: the z-applocal loop uses the project's vcpkg, not the VS-bundled one VsDevCmd puts in VCPKG_ROOT Co-Authored-By: Claude Fable 5.1 --- .github/workflows/pip-build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pip-build.yml b/.github/workflows/pip-build.yml index 1b22539a5eb6..855ab1c4b708 100644 --- a/.github/workflows/pip-build.yml +++ b/.github/workflows/pip-build.yml @@ -562,14 +562,16 @@ jobs: VCPKG_ROOT: C:\vcpkg VCPKG_TARGET_TRIPLET: ${{ matrix.vcpkg-triplet }} # The CMake branch of the Build step of build-test-windows.yml, Release only; see the notes there - # on `|| exit /b 1` and on the serial z-applocal pass. + # on `|| exit /b 1` and on the serial z-applocal pass. VsDevCmd.bat replaces VCPKG_ROOT with the + # VS-bundled vcpkg, whose path has a space, so the project's one is kept aside for the loop. run: | + set "PROJ_VCPKG_ROOT=%VCPKG_ROOT%" call "${{ env.VC_PATH }}\Common7\Tools\VsDevCmd.bat" ${{ matrix.vs-dev-args }} -vcvars_ver=${{ env.VCVARS_VER }} || exit /b 1 cmake --version || exit /b 1 cmake -B source\TempOutput -GNinja -DCMAKE_BUILD_TYPE=Release %CMAKE_COMPILER_ARGS% -DVCPKG_TARGET_TRIPLET=%VCPKG_TARGET_TRIPLET% -DVCPKG_APPLOCAL_DEPS=OFF -DMESHLIB_BUILD_GENERATED_C_BINDINGS=OFF -DMESHLIB_BUILD_MRCUDA=${{ matrix.cuda-version != '' && 'ON' || 'OFF' }} -DMESHLIB_BUILD_MCP=OFF -DMR_PCH_USE_EXTRA_HEADERS=ON -DMRVOXELS_UNITY_BUILD=ON || exit /b 1 cmake --build source\TempOutput -j || exit /b 1 for %%b in (source\TempOutput\bin\*.exe source\TempOutput\bin\*.dll) do ( - %VCPKG_ROOT%\vcpkg.exe z-applocal --target-binary="%%b" --installed-bin-dir="%VCPKG_ROOT%\installed\%VCPKG_TARGET_TRIPLET%\bin" >nul || exit 1 + "%PROJ_VCPKG_ROOT%\vcpkg.exe" z-applocal --target-binary="%%b" --installed-bin-dir="%PROJ_VCPKG_ROOT%\installed\%VCPKG_TARGET_TRIPLET%\bin" >nul || exit 1 ) if not exist source\${{ matrix.platform }} mkdir source\${{ matrix.platform }} || exit /b 1 xcopy source\TempOutput\bin\* source\${{ matrix.platform }}\Release\* /s /e /i /Y || exit /b 1 From 745ae54a48fb4b87624762bfb44777b1d13e1393 Mon Sep 17 00:00:00 2001 From: Fedor Chelnokov Date: Tue, 20 Oct 2026 13:45:58 +0300 Subject: [PATCH 3/5] C# tests: accept the results of builds with FMA instructions clang-cl keeps /fp:precise as -ffp-contract=on, and on arm64 FMA is baseline, so three tests saw slightly different exact results than the cl builds: the multiway ICP pair count, the split of the precise edge-triangle intersections and the edge chosen to represent a projected point. The tests now accept both result sets, as MRMeshBooleanTests.cpp already does, and check the projected point through mesh.triPoint instead of its edge id. Co-Authored-By: Claude Fable 5.1 --- source/MRDotNet2Test/src/ICPTests.cs | 9 +++++---- source/MRDotNet2Test/src/MeshCollideTests.cs | 13 +++++++------ source/MRDotNet2Test/src/MeshTests.cs | 16 ++++++++++------ 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/source/MRDotNet2Test/src/ICPTests.cs b/source/MRDotNet2Test/src/ICPTests.cs index 490e4e0fabb7..540806007ee5 100644 --- a/source/MRDotNet2Test/src/ICPTests.cs +++ b/source/MRDotNet2Test/src/ICPTests.cs @@ -33,14 +33,15 @@ public void TestMultiwayICP() icp.setParams(iCPProperties); icp.updateAllPointPairs(); - Assert.That(icp.getNumActivePairs(), Is.EqualTo((nuint)1748)); - Assert.That(icp.getNumSamples(), Is.EqualTo((nuint)1748)); + // 1744 pairs with FMA instructions (clang-cl on arm64), 1748 without + Assert.That((long)icp.getNumActivePairs(), Is.InRange(1744, 1748)); + Assert.That((long)icp.getNumSamples(), Is.InRange(1744, 1748)); Assert.That(icp.getMeanSqDistToPoint(), Is.EqualTo(0.00254).Within(1e-5)); Console.WriteLine("Calculating transformations..."); var xfs = icp.calculateTransformations(); - Assert.That(icp.getNumActivePairs(), Is.EqualTo((nuint)1748)); - Assert.That(icp.getNumSamples(), Is.EqualTo((nuint)1748)); + Assert.That((long)icp.getNumActivePairs(), Is.InRange(1744, 1748)); + Assert.That((long)icp.getNumSamples(), Is.InRange(1744, 1748)); Assert.That(icp.getMeanSqDistToPoint(), Is.EqualTo(0).Within(1e-5)); } diff --git a/source/MRDotNet2Test/src/MeshCollideTests.cs b/source/MRDotNet2Test/src/MeshCollideTests.cs index 251194d30b2d..08562cec4058 100644 --- a/source/MRDotNet2Test/src/MeshCollideTests.cs +++ b/source/MRDotNet2Test/src/MeshCollideTests.cs @@ -26,16 +26,17 @@ public void TestMeshCollidePrecise() else edgeBTriACount++; } - Assert.That(edgeATriBCount, Is.EqualTo(80)); - Assert.That(edgeBTriACount, Is.EqualTo(72)); + // the second values are with FMA instructions (clang-cl on arm64), as in the C++ test of MRMeshBooleanTests.cpp + Assert.That(edgeATriBCount, Is.EqualTo(80).Or.EqualTo(76)); + Assert.That(edgeBTriACount, Is.EqualTo(72).Or.EqualTo(76)); var contours = orderIntersectionContours(meshA.topology, meshB.topology, intersections); Assert.That(contours.size(), Is.EqualTo((nuint)4)); - Assert.That(contours[0].size(), Is.EqualTo((nuint)71)); - Assert.That(contours[1].size(), Is.EqualTo((nuint)7)); - Assert.That(contours[2].size(), Is.EqualTo((nuint)69)); - Assert.That(contours[3].size(), Is.EqualTo((nuint)9)); + Assert.That(contours[0].size(), Is.EqualTo((nuint)71).Or.EqualTo((nuint)69)); + Assert.That(contours[1].size(), Is.EqualTo((nuint)7).Or.EqualTo((nuint)9)); + Assert.That(contours[2].size(), Is.EqualTo((nuint)69).Or.EqualTo((nuint)71)); + Assert.That(contours[3].size(), Is.EqualTo((nuint)9).Or.EqualTo((nuint)7)); var aConts = new Std.Vector_MROneMeshContour(); getOneMeshIntersectionContours(meshA, meshB, contours, aConts, null, conv); Assert.That(aConts.size(), Is.EqualTo((nuint)4)); diff --git a/source/MRDotNet2Test/src/MeshTests.cs b/source/MRDotNet2Test/src/MeshTests.cs index 383d6f8e8cf4..567d60b8deaa 100644 --- a/source/MRDotNet2Test/src/MeshTests.cs +++ b/source/MRDotNet2Test/src/MeshTests.cs @@ -321,9 +321,12 @@ public void TestProjection() Assert.That(projRes.proj.point.y, Is.EqualTo(0.507).Within(1e-3)); Assert.That(projRes.proj.point.z, Is.EqualTo(0.803).Within(1e-3)); - Assert.That(projRes.mtp.e.id, Is.EqualTo(1640)); - Assert.That(projRes.mtp.bary.a, Is.EqualTo(0.053).Within(1e-3)); - Assert.That(projRes.mtp.bary.b, Is.EqualTo(0.946).Within(1e-3)); + // which edge of the triangle represents the point differs with FMA instructions (clang-cl on arm64) + Assert.That(mesh.topology.left(projRes.mtp.e).id, Is.EqualTo(904)); + var mtpPoint = mesh.triPoint(projRes.mtp); + Assert.That(mtpPoint.x, Is.EqualTo(0.310).Within(1e-3)); + Assert.That(mtpPoint.y, Is.EqualTo(0.507).Within(1e-3)); + Assert.That(mtpPoint.z, Is.EqualTo(0.803).Within(1e-3)); var xf = AffineXf3f.translation(Vector3f.diagonal(1.0f)); projRes = findProjection(p, mesh, float.MaxValue, xf); @@ -333,9 +336,10 @@ public void TestProjection() Assert.That(projRes.proj.point.y, Is.EqualTo(1.439).Within(1e-3)); Assert.That(projRes.proj.point.z, Is.EqualTo(1.895).Within(1e-3)); - Assert.That(projRes.mtp.e.id, Is.EqualTo(1898)); - Assert.That(projRes.mtp.bary.a, Is.EqualTo(0.5).Within(1e-3)); - Assert.That(projRes.mtp.bary.b, Is.EqualTo(0.0).Within(1e-3)); + mtpPoint = mesh.triPoint(projRes.mtp); // in mesh space, before xf + Assert.That(mtpPoint.x, Is.EqualTo(0.000).Within(1e-3)); + Assert.That(mtpPoint.y, Is.EqualTo(0.439).Within(1e-3)); + Assert.That(mtpPoint.z, Is.EqualTo(0.895).Within(1e-3)); } [Test] From a08afd0e2f10205c1c207f751683bffc0b1438f4 Mon Sep 17 00:00:00 2001 From: Fedor Chelnokov Date: Tue, 20 Oct 2026 18:48:51 +0300 Subject: [PATCH 4/5] MRVoxels: do not link gdcmMEXD gdcm builds every module with the same GDCM_EXPORT macro, so gdcmMEXD.dll re-exports 153 gdcmDSED symbols (DataSet, DataElement, Tag...). CMake orders the link line with gdcmMEXD.lib before gdcmDSED.lib, so MRVoxels resolved them from gdcmMEXD and the CMake Windows packages shipped gdcmMEXD.dll plus its socket++ dependency, two DLLs the MSBuild packages never had (vcpkg autolink lists the libs alphabetically, DSED first). MRVoxels uses only the MSFF and DICT modules; MEXD is the DICOM network module. Co-Authored-By: Claude Fable 5.1 --- source/MRVoxels/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/MRVoxels/CMakeLists.txt b/source/MRVoxels/CMakeLists.txt index 578baa0a9c09..4a122e7758ec 100644 --- a/source/MRVoxels/CMakeLists.txt +++ b/source/MRVoxels/CMakeLists.txt @@ -39,7 +39,7 @@ ENDIF() IF(NOT MRVOXELS_NO_DICOM) find_package(GDCM CONFIG REQUIRED) - target_link_libraries(${PROJECT_NAME} PRIVATE gdcmIOD gdcmDICT gdcmDSED gdcmMEXD gdcmMSFF) + target_link_libraries(${PROJECT_NAME} PRIVATE gdcmIOD gdcmDICT gdcmDSED gdcmMSFF) ENDIF() IF(MR_PCH) From b5b28cc4889cc86efce113e1c022f1f8310f8626 Mon Sep 17 00:00:00 2001 From: Fedor Chelnokov Date: Tue, 20 Oct 2026 18:52:28 +0300 Subject: [PATCH 5/5] CI: the C# bindings are built and tested on the clang-cl jobs only Nothing shipped uses the MSBuild-built C bindings any more, so the MSBuild VS2026 jobs stop generating and testing the C# bindings. Co-Authored-By: Claude Fable 5.1 --- .github/workflows/build-test-windows.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-test-windows.yml b/.github/workflows/build-test-windows.yml index 95b03ed5686a..6884b727994c 100644 --- a/.github/workflows/build-test-windows.yml +++ b/.github/workflows/build-test-windows.yml @@ -45,9 +45,9 @@ jobs: actions: read # This is required for wait-for-job env: - # The C# bindings are generated and tested on the MSBuild VS2026 jobs and on the clang-cl jobs; - # the NuGet payload (the native DLLs, MRDotNet2.dll and its XML) comes from the clang-cl ones. - BUILD_C_SHARP: ${{ matrix.cxx_compiler == 'msvc-2026' && matrix.build_system == 'MSBuild' || matrix.cxx_compiler == 'clang-cl' }} + # The C# bindings are generated and tested on the clang-cl jobs, which also produce the NuGet + # payload (the native DLLs, MRDotNet2.dll and its XML) + BUILD_C_SHARP: ${{ matrix.cxx_compiler == 'clang-cl' }} PYTEST_C_SHARP_ARGS: --run-c-sharp-samples --csharp-sample-dir=..\source\${{ matrix.arch || 'x64' }}\${{ matrix.config }} VCPKG_DEFAULT_TRIPLET: ${{ matrix.vcpkg_triplet || 'x64-windows-meshlib' }} # Upload a developer distributive per Visual Studio toolchain and target