Native Windows (MSVC) support - #154
Merged
Merged
Conversation
Advances the pinned submodule six commits: kernel speed improvements (RandBLAS#173), lazy submatrix sampling for SparseSkOp (RandBLAS#174), sparse sketching speedups (RandBLAS#176), Windows/MSVC portability (RandBLAS#179), and two documentation updates. The Windows support about to be added here requires a RandBLAS that already compiles under MSVC, which the old pin (May 2026) predates.
RandLAPACK's library headers already compile under MSVC; the blockers were at the edges. Tests: rename __PRETTY_FUNCTION__ (GCC/Clang-only) to the __RANDBLAS_PRETTY_FUNCTION__ portability macro that RandBLAS's comparison.hh now provides -- every affected file already includes that header. Benchmarks: replace the repository's only two C variable-length arrays (gejsv iwork workspaces) with heap allocations, freeing a pre-existing workspace leak in find_test_mat_spectrum along the way. CMake: warning flags and benchmark -g become compiler-conditional (MSVC gets /W4); the header-only target exports /utf-8 to MSVC consumers because several headers carry non-ASCII characters in string literals; SANITIZE_ADDRESS learns the MSVC spelling; new rl_runtime_dlls.cmake stages imported dependency DLLs beside test executables (gtest_discover_tests runs them at build time) -- named with the rl_ prefix because a module literally called RuntimeDLLs.cmake shadows RandBLAS's identically-named module through the shared CMAKE_MODULE_PATH and breaks the submodule configure; the lapackpp_DIR recorded in the installed package config is normalized with TO_CMAKE_PATH so native Windows backslash paths do not arrive as escape sequences in downstream find_package calls; the template-heavy test translation units get /bigobj.
windows-2022 + MSVC + oneMKL from vcpkg, ILP64 and sequential -- required because RandBLAS's MKL sparse backend static-asserts that its int64_t indices match MKL_INT. BLAS++ and LAPACK++ build from the BallisticLA fork branches carrying the two one-line MSVC fixes (upstream blaspp PR #132 and lapackpp PR #87 are still open). All five dependencies cache between runs, keyed on the setup script. The build is serial (no OpenMP) for now: rl_rpchol.hh uses an OpenMP collapse(2) clause that MSVC only accepts under /openmp:llvm, while RandBLAS's build system pins MSVC OpenMP to /openmp:experimental. RandLAPACK guards all OpenMP use, so serial builds are fully functional. The job is named build-windows, distinct from the required check 'build', so it can prove itself before anyone makes it required. .github/scripts/windows/run-ci.ps1 -Task Core -SetupDependencies reproduces the CI job locally from an MSVC developer prompt.
Thin companion to install.sh for MSVC users: builds or reuses the dependency stack (oneMKL through vcpkg, or -MklRoot for an existing oneAPI install), then configures, builds, installs, and tests RandLAPACK, mirroring install.sh's sibling RandNLA-project layout. The dependency logic lives in the CI setup script so there is exactly one copy of the recipe. INSTALL.md gains a native-Windows section.
rl_hqrrp.hh and three BQRRP benchmarks kept dead #ifdef LAPACK_FORTRAN_STRLEN_END blocks (contents commented out) inside the argument lists of LAPACK_dlarfb/dlarf/dgeqrf/dgejsv calls. Those names are function-like macros in lapackpp's fortran.h, and a preprocessor directive inside a macro invocation is undefined behavior: GCC and Clang tolerate it, MSVC rejects it (C2121), which broke every test translation unit in the first core-windows run. The blocks were dead on all platforms -- lapackpp's variadic macros append the hidden string-length arguments themselves.
Runs install.ps1 end-to-end on windows-2022 plus an idempotent re-run, completing the per-OS two-lane structure (hand-written recipe in the core workflow, installer contract in this one). The job shares the cached dependency stack with core-windows; install.ps1 gains a -DependencyRoot option so CI can point it at that shared location instead of rebuilding dependencies under the project directory.
Measured before this change: core-linux 10-12 min, core-windows 12-16. Four fixes: - BLAS++/LAPACK++/Random123 installs are cached in core-linux and core-macos (they were rebuilt from scratch on every run; the installer workflow has cached them since it was introduced). - make -j2 -> -j(all cores) on Linux and macOS. - The RandBLAS submodule's ~450 tests no longer build and run inside every RandLAPACK job (-DBUILD_TESTS=OFF in the three core recipes): the pinned commit is already tested by RandBLAS's own CI. The installer lanes keep them, preserving what a user's install builds. - The Debug/ASan build ran sequentially inside the same job as the Release build; it is now its own parallel job (build-asan) on both Linux and macOS. The required-check job name 'build' is unchanged.
install.sh and install.ps1 now live in an install/ directory instead of cluttering the repository root. A two-line wrapper stays at the root so the documented `bash install.sh` one-liner keeps working; the CI installer lanes invoke the wrapper on purpose so it is under test too. Both scripts learn their new location (the repo root is one directory up), and all workflow/documentation references are updated.
Four workflows, eight jobs, three cache families, a deliberate canary, and dependency clones pointing at fork branches -- enough moving parts that newcomers (and future us) need the map: what each job validates, which checks are required and why the rest are not yet, what is deliberately red or disabled, where the caches live and how to bust them, and how to reproduce each lane locally.
TestCQRRP.CQRRT_large_full_rank's Frobenius orthogonality metric came in at 4.4e-11 on Windows CI (vcpkg oneMKL, sequential) against atol = eps^0.7 = 1.1e-11, deterministically across runners. The metric depends on the BLAS build's accumulation order, and eps^0.7 leaves no headroom for that; eps^0.65 (2.7e-10) still asserts orthogonality to ten digits.
The umbrella header RandLAPACK.hh sits at the repository root, not inside the RandLAPACK/ source directory; the check tested a path that has never existed, so install.ps1 refused to run anywhere -- the install-windows job has been failing on this line since it was added, masked first by the STRLEN compile error and then by the CQRRT tolerance failure in the sibling jobs.
rileyjmurray
pushed a commit
to BallisticLA/RandBLAS
that referenced
this pull request
Aug 6, 2026
Follow-up to the Windows portability work in #179. **What #179 did:** made RandBLAS build natively with MSVC, including the CMake logic that selects an MSVC OpenMP mode. It chose `/openmp:experimental`, the minimum needed for RandBLAS itself: plain `/openmp` cannot compile the `omp simd` directive in the sparse kernels. **What this PR changes:** the selected mode becomes `/openmp:llvm`. The experimental mode is still OpenMP 2.0 underneath, which only allows signed 32-bit loop indices and has no `collapse` clause. RandLAPACK parallelizes loops with `int64_t` indices and uses `collapse(2)`, so with the experimental mode pinned here, RandLAPACK's native Windows builds (BallisticLA/RandLAPACK#154) have to disable OpenMP entirely. The LLVM mode supports 64-bit indices, `collapse`, and everything the experimental mode provided, including `omp simd` — so RandBLAS keeps compiling as before and downstream consumers stop being blocked. **Also fixed along the way:** the re-stamp of `OpenMP::OpenMP_CXX` after `find_package` hardcoded the mode string, so a user passing `-DOpenMP_CXX_FLAGS=...` at configure time was silently overridden. The requested flags are now captured before the find and re-applied afterward, in both the build tree (`CMake/OpenMP.cmake`) and the installed package config (`RandBLASConfig.cmake.in`). **Validation:** the Windows CI matrix from #179 (openmp-release leg, 459 tests) is the gate — it exercises the sparse kernels' `omp simd` under the new mode. Serial and ASan legs are unaffected. **Downstream plan:** once this merges, RandLAPACK bumps its submodule pin and adds an OpenMP leg to its own Windows CI.
Advances the pin one commit to pick up RandBLAS #184, which selects MSVC's /openmp:llvm mode (64-bit loop indices and the collapse clause, which RandLAPACK's parallel loops need) and compiles the sparse kernels' omp simd directive only where OpenMP actually implements it.
With RandBLAS on /openmp:llvm, RandLAPACK's OpenMP code (int64 loop indices, the collapse clause in rl_rpchol) compiles under MSVC for the first time. The workflow becomes a two-leg matrix (serial + openmp), mirroring RandBLAS's own Windows CI; run-ci.ps1 gains an -OpenMP switch. INSTALL.md's 'OpenMP is disabled on MSVC' caveat retires.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Native Windows (MSVC) support, mirroring the recipe RandBLAS PR #179 validated: Visual Studio 2022, Intel oneMKL from vcpkg with ILP64 + sequential linking (RandBLAS's MKL sparse backend requires 64-bit
MKL_INT), and BLAS++/LAPACK++ built from the BallisticLA branches that carry the two one-line MSVC fixes still open upstream (blaspp PR #132, lapackpp PR #87).An audit of the whole tree found the library headers need zero code changes for MSVC — every blocker was at the edges. Four commits:
__PRETTY_FUNCTION__(GCC/Clang-only) → the__RANDBLAS_PRETTY_FUNCTION__macro RandBLAS'scomparison.hhnow provides (36 sites; every affected file already includes that header).gejsvinteger workspaces) become heap allocations; a pre-existing workspace leak infind_test_mat_spectrumis freed along the way.-gbecome compiler-conditional (MSVC gets/W4); the header-only target exports/utf-8to MSVC consumers (several headers carry non-ASCII characters in string literals);SANITIZE_ADDRESSlearns the MSVC spelling; newCMake/rl_runtime_dlls.cmakestages dependency DLLs beside test executables (gtest_discover_testsruns them at build time); thelapackpp_DIRrecorded in the installed package config is normalized withTO_CMAKE_PATHso Windows backslash paths don't arrive as escape sequences downstream; the template-heavy test translation units get/bigobj.core-windowsworkflow: windows-2022 runner, cached dependency stack via a composite action, Ninja build, full ctest (standard ABRIK exclusion). The job is namedbuild-windows, deliberately distinct from the required checkbuild, so it can prove itself before being made required. (RandBLAS's own tests ran inside this job in the first CI rounds; item 7 turns them off.)install.ps1: thin companion toinstall.sh— reuses the CI dependency script (so the recipe exists exactly once), supports-MklRootfor oneAPI installs instead of vcpkg, and mirrors the..\RandNLA-projectlayout. INSTALL.md gains a native-Windows section.OpenMP is off on native Windows for now:
rl_rpchol.hhuses an OpenMPcollapse(2)clause that MSVC only accepts under/openmp:llvm, while RandBLAS's build system pins MSVC OpenMP to/openmp:experimental. All OpenMP use is guarded, so serial builds are fully functional; reconciling the two runtimes is a RandBLAS-side follow-up.Also catalogued but deliberately not fixed here (they never touch ILP64 BLAS calls): the
long-typed timing fields overflow at ~35.8 minutes per timer on Windows (LLP64), andrl_memory_tracker.hh's byte arithmetic overflows at 2 GiB working sets — diagnostics-only issues, queued for post-1.0 cleanup.Verified on Linux after all changes: clean build, 785/786 tests (the one failure is a documented machine-local GPU issue predating this work). The first Windows execution is this PR's own CI run.
Added after the first CI round:
rl_hqrrp.hhand three BQRRP benchmarks kept dead#ifdef LAPACK_FORTRAN_STRLEN_ENDblocks inside LAPACK macro invocations — undefined behavior that GCC/Clang tolerate and MSVC rejects (C2121). Pure deletion; the lapackpp variadic macros append the string-length arguments themselves.install-windowsCI job, filling the slot reserved in the installer workflow: runsinstall.ps1end-to-end plus an idempotent re-run, sharing the cached dependency stack withcore-windows(new-DependencyRootinstaller option).-j2; the RandBLAS submodule's ~450 tests no longer build and run inside every RandLAPACK job (-DBUILD_TESTS=OFF— the pinned commit is already tested by RandBLAS's own CI; the installer lanes keep them for user parity); and the Debug/ASan build+suite is a parallelbuild-asanjob instead of running sequentially insidebuild. The required-check job namebuildis unchanged.install/(install/install.sh,install/install.ps1), with a two-line wrapper kept at the root sobash install.shkeeps working — the CI installer lanes call the wrapper on purpose so it stays under test.docs/CI.md: a map of the CI setup — what each of the eight jobs validates, which checks are required, what is deliberately red (the core-macos canary) or disabled (submodule tests, Windows OpenMP), cache keys and how to bust them, and per-OS local-reproduction commands./openmp:llvm(post-RandBLAS#184) and an OpenMP matrix leg in core-windows: with RandBLAS selecting MSVC's LLVM OpenMP runtime, RandLAPACK's OpenMP code (64-bit loop indices, thecollapse(2)in rl_rpchol) compiles under MSVC for the first time. The workflow becomes serial + openmp, mirroring RandBLAS's own Windows matrix; the "OpenMP disabled on MSVC" caveat retires from INSTALL.md.RandLAPACK/RandLAPACK.hh; the umbrella header sits at the repo root), so the install-windows job had never gotten past it.