Installer overhaul: pins, provenance, a run-not-just-link BLAS check, backend selection, and docs - #162
Merged
Merged
Conversation
Contributor
Author
|
Test suite result, as promised: 313/313 pass, 0 failed on the build this installer produced (Linux, gcc 15.2, oneAPI MKL, ILP64, For the record, since the run took a while and it is the slow tests that matter here: |
This was referenced Aug 13, 2026
…kend selection Brings the Unix installer up to the standard install.ps1 reached in #156, and in line with the RandBLAS installer. The Windows script already pinned every dependency, recorded provenance and validated the BLAS before building; this one did none of that. Eleven defects, all verified against main before changing anything: * Three `git clone` calls with no ref (:336,339,342) -- blaspp, lapackpp and random123 all tracked upstream default branches, so two runs of the same script could build different source. Now pinned to the refs this repository's own Windows provisioner already validated, fetched one commit deep, with a provenance stamp on each install and each source tree. * No BLAS validation at all. The installer now compiles, links and *runs* a program against the finished install, through BLAS++ and LAPACK++ rather than raw dgemm_ (that is how RandLAPACK reaches them), checking a gemm result and a gesdd factorization numerically. The gesdd call is deliberate. It is the routine Apple's legacy Accelerate computes incorrectly, so a broken SVD surfaces at install time rather than in someone's RSVD output. And the run-it-not-just-link-it part matters for a reason peculiar to integer width: BLAS++/LAPACK++ guard the int64_t downcast and throw rather than truncate, but that guard keys off sizeof(blas_int) as declared by the *header*. If the headers say 64-bit while the loaded library is LP64, the guard compiles out and 64-bit values reach routines reading 32 bits -- which shows up not as wrong numbers but as an absurd workspace size and a run that dies in allocation or never finishes. Nothing catches that by inspection. * /opt/homebrew hardcoded in eight places, which hard-fails on Intel macOS and any custom HOMEBREW_PREFIX. Now `brew --prefix`. * The script moved the user's own clone into <project>/lib/RandLAPACK, breaking git worktrees. It now works in place and puts a symlink there instead, so the layout still reads as complete and the path CI invokes still resolves. * The log was truncated on every run (:211), destroying the previous run's output at exactly the moment you want it. Now appended with a run header. * The libdir search omitted lib/aarch64-linux-gnu. * No --prefix; extras and benchmarks had no way to be skipped. Both added, with extras and benchmarks still built by DEFAULT (--no-extras / --no-benchmarks to opt out): unlike RandBLAS's examples they need nothing this script has not already built, so default-on costs only time. Backend selection is new: --blas=auto|openblas|mkl|accelerate|custom, --blas-int, --blas-libraries. Integer width is requested per backend and then READ BACK from BLAS++'s generated blas/defines.h rather than assumed, because BLAS++ probes int32 before int64 while blas_int only filters library *names* -- so for MKL the request genuinely selects mkl_intel_ilp64, but for OpenBLAS there is only -lopenblas and an LP64 build passes the int32 probe and is accepted. Trusting the request would stamp LP64 installs as ILP64. macOS deliberately keeps Homebrew OpenBLAS as the default rather than moving to Accelerate. Apple's legacy Accelerate has a broken divide-and-conquer gesdd and RandLAPACK calls gesdd in rl_rsvd, rl_abrik, rl_revd2, rl_preconditioners and rl_util, so Accelerate would quietly return wrong singular values across most of the SVD-based drivers -- which is what #157's quarantine of TestQB.Polynomial_Decay_general1 is about. --blas=accelerate is allowed and warns, citing #159. The provenance stamp includes the GPU setting, and the dependency install directories now carry the backend and GPU configuration in their names (blaspp-mkl-cpu-install). Both matter, and the second one for a reason outside this project: RandBLAS's installer uses the same RandNLA-project layout and named its BLAS++ install identically. Sharing that name meant this script would rebuild over RandBLAS's BLAS++ (their stamp is a different file, so it never matched ours), and RandBLAS's next run would reuse an artifact we had replaced underneath it while its own stamp still described the original. Distinct names make that impossible; cross-project sharing is instead explicit, via BLASPP_INSTALL_DIR, with the conftest confirming the result works. Also adds the three progress tiers from the RandBLAS installer -- determinate, parsed from Ninja's "[12/34]" and Make's "[ 42%]" -- with tier 0 (redirected output) byte-identical to the plain step list, and a CI assertion that redirected output contains no escape sequence or carriage return. CI: the install-script lanes globbed rather than hardcoded for the new dependency directory names, so they are not coupled to that naming, and the discovery assertion updated to the text the new script prints. Verified on Linux (gcc 15.2, oneAPI MKL): fresh MKL build; idempotent re-run; full default run with extras and benchmarks (13/13 steps); switching --no-gpu to --gpu correctly invalidating the BLAS++ provenance and rebuilding; dependency discovery reducing to 3 steps; running from a git worktree with the clone left in place; redirected output escape-free; and RandBLAS-then-RandLAPACK into one shared RANDNLA_PROJECT_DIR leaving both projects' dependencies intact, plus RandLAPACK reusing RandBLAS's BLAS++ when pointed at it explicitly.
…nvironment Brings the Windows installer's location handling in line with install.sh, which is what makes the shared RandNLA-project convention actually work on both platforms. RANDNLA_PROJECT_DIR was read nowhere in this script. Its precedence is now identical to install.sh's -- the flag, then the environment variable, then a sibling of the clone -- so a machine that has already installed one RandNLA project does not scatter a second tree somewhere else. -ModifyEnvironment persists that variable for the user with [Environment]::SetEnvironmentVariable(..., "User"), the Windows equivalent of install.sh's --modify-rc and the only mechanism that survives opening a new shell; setting $env: alone would last for the current process. Opt-in, matching install.sh: the default touches nothing and prints the setx command instead. -Prefix installs RandLAPACK itself somewhere other than <ProjectDir>\install\RandLAPACK-install, for a module tree or any prefix a site wants to own. Dependencies stay in the project directory. Also moved the project-directory length warning to after path resolution. It was guarded on `$ProjectDir -ne ""`, so it only ever fired for an explicitly passed -ProjectDir -- never for the default, which is the common case and is derived from wherever the clone happens to sit, so the more likely one to be long. Verified on Windows 11 under Windows PowerShell 5.1 with VS 2022 Build Tools: all three precedence cases resolve as intended (sibling default, environment variable honoured, flag beating the variable), and the User-scope environment write round-trips. The oneMKL discovery, BLAS link check and space-free import library staging from #156 were all observed still working along the way.
…tions The guide described a script that no longer exists in several respects. Four changes. The documented flag list predated backend selection entirely. It now covers --blas, --blas-int, --blas-libraries, --prefix, --no-extras, --no-benchmarks and --no-progress, and states that extras and benchmarks are built by default with opt-outs -- deliberately unlike RandBLAS's examples, which are opt-in because they pull in dependencies RandBLAS itself does not need. The directory-structure diagram said the script would MOVE your clone into lib/. It no longer does -- that broke git worktrees -- and lib/RandLAPACK is a symlink. The diagram also now shows the install/ tree, whose dependency directories carry the backend and GPU configuration in their names. "What the Script Does" described cloning dependencies from their default branches and moving the RandLAPACK directory. It now describes the pinned fetches, the provenance stamps that make reuse configuration-aware, and the verification step -- including why that step runs a program rather than only linking one. New section 6 covers what the earlier guide had nowhere: a tested-configuration table drawn from the CI lanes, the per-backend integer width with the reason OpenBLAS is the awkward case, whether LP64 actually limits RandLAPACK (rarely, and loudly -- with the genuinely silent header/library mismatch called out separately), and why macOS defaults to Homebrew OpenBLAS rather than Accelerate. Section 6 is placed before the GPU-benchmark appendix so the numbered sections stay contiguous.
RandBLAS main has moved three commits since 04f2018: the vcpkg manifest fix
(#185), the CMake hygiene pass (#186), and the installer scripts (#187).
None of them touch RandBLAS/ headers -- the library code is byte-identical.
Everything in the range is build machinery, and two pieces of it matter here:
* RandBLAS's CMake floor moved from 3.12 to 3.21. RandLAPACK already declares
3.21, so nothing to do, but the submodule now enforces what RandLAPACK
already required.
* RandBLAS now exports randblas_stage_runtime_dlls() from its installed
package and prints a configuration summary. As a subproject under
RandLAPACK, which configures it with BUILD_TESTS=OFF, that summary reports
the tests as deliberately skipped rather than warning.
RandLAPACK_RandBLAS_PIN is updated in the same commit, which CMakeLists.txt
requires and enforces: the cross-check compares the variable against
`git ls-tree HEAD RandBLAS`, so a staged-but-uncommitted bump fails configure
until the two land together.
mmelnich
force-pushed
the
randlapack-install-sh
branch
from
August 13, 2026 20:40
ecb3f47 to
f455462
Compare
mmelnich
added a commit
that referenced
this pull request
Aug 29, 2026
Brings in the six commits main gained since the 2026-08-05 refresh (5da0674): 1cbe9e0 Native Windows (MSVC) support (#154) 4cc72a8 TEMPORARY: quarantine the macOS Accelerate gesdd test (#157) e4e8565 Windows installation overhaul (#156) 26eaed6 CI: fix the broken oneMKL cache path and drop a dead ctest exclusion (#161) ab05872 Installer overhaul: pins, provenance, run-not-just-link BLAS check (#162) d4ee721 Include the GPU layer from RandLAPACK.hh, guarded on __CUDACC__ (#169) Two conflicts, both in test/, both from main's MSVC work colliding with branch test infrastructure. Neither is library code. test/CMakeLists.txt: kept BOTH sides. Main adds /bigobj and randlapack_stage_runtime_dlls(RandLAPACK_tests); the branch adds PROPERTIES TIMEOUT 300 to gtest_discover_tests. The ordering is forced rather than stylistic: the DLL staging must precede gtest_discover_tests, because that command runs the test binary at build time to enumerate cases and on Windows that run needs the DLLs already staged. test/drivers/test_cqrrt.cc: both sides made the same code change, atol from eps^0.7 to eps^0.65, and differed only in the justification comment. Merged the comment to credit both backends. Two unrelated BLAS implementations independently put norm_0/sqrt(n) over the tighter bound on this case, vcpkg oneMKL sequential on Windows at 4.4e-11 and Apple Accelerate on macOS at ~1.7e-11. That it was found twice independently is what says the bound was wrong, not the backends. Three things worth recording. 1. 26eaed6 removed the dead ctest exclusion --exclude-regex "^TestABRIK\.ABRIK_catch_instability" that this branch was still carrying in six places across three workflow files, so the branch no longer needs to. One correction to that PR's description, which states there is no history of the test under that name: edab935^ contains four such tests (_prelim, _good, _bad, _worse) and the regex was unanchored on the right, so it matched all four until edab935 deleted them on 2026-02-02. The exclusion was live once, not always inert. 2. Main's 4cc72a8 quarantines TestQB.Polynomial_Decay_general1 on macOS, while this branch's 5a6b6d3 fixed that same test on Apple Silicon by switching its reference SVD from gesdd to gesvd. Both survive the merge, so the quarantine's own "if this passes, delete the suppression" warning will now fire on every macOS run. Left in place deliberately: 4cc72a8 is a temporary main-side commit pinned to two open upstream PRs, and reverting it here would fight main. Flagged for the PR thread instead. 3. install.sh shrinks by 484 lines because ab05872 turned it into a wrapper delegating to install/install.sh. Nothing was lost, and the branch's own cluster-install optimisation from 2ca557e survives there as -Dbuild_tests=OFF for both blaspp and lapackpp, using those projects' actual lowercase option name rather than the branch's BUILD_TESTING. The RandBLAS submodule advances from 8417f4b (1.1.0-32) to 952251c (1.1.0-42).
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.
Problem
RandLAPACK's two installers had drifted apart.
install/install.ps1was rebuilt in #156 and pins every dependency, checksums downloads, records provenance and link-and-run validates the BLAS before building anything.install/install.shdid none of that, and the documentation described a script that no longer existed in several respects.Eleven defects, all verified against
mainbefore touching anything:install.sh:336,339,342git clonewith no ref — blaspp, lapackpp, random123 all tracked upstream default branches/opt/homebrewhardcoded, 8 places — hard-fails on Intel macOS and customHOMEBREW_PREFIXinstall.sh:331mv "$REPO_DIR"relocated the user's own clone, breaking git worktreesinstall.sh:211: > "$LOG"truncated the log, destroying the previous run's outputinstall.sh:247lib/aarch64-linux-gnu--prefix; extras and benchmarks unconditional with no way to skipinstall.ps1RANDNLA_PROJECT_DIR, no--modify-rcequivalentINSTALL_SCRIPT.mdThe two things most worth reviewing
Integer width is read back, not assumed
BLAS++ probes
int32beforeint64, andblas_intonly filters which library names to try. For MKL that is a real choice —mkl_intel_lp64andmkl_intel_ilp64are different libraries. For OpenBLAS there is only-lopenblas, so a successfulblas_int=int64configure proves nothing: an LP64 build passes theint32probe and is accepted. The resolved width therefore comes from BLAS++'s generatedblas/defines.hafter the build. Trusting the request would stamp LP64 installs as ILP64 and have every later run reuse them believing otherwise.Verification runs the program, and that is the point
The conftest compiles, links and runs against the finished install — through BLAS++ and LAPACK++ rather than raw
dgemm_, since that is how RandLAPACK reaches them — checking agemmresult and agesddfactorization numerically.gesddis chosen because it is the routine Apple's legacy Accelerate computes incorrectly.Running it rather than only linking matters for a reason specific to integer width. BLAS++ and LAPACK++ do guard the
int64_tdowncast —to_blas_int(blaspp/src/blas_internal.hh:16-22) throws rather than truncates — but that guard keys offsizeof(blas_int)as declared by the header. If the headers say 64-bit while the library actually loaded is LP64, the guard compiles out and 64-bit values reach routines reading 32 bits. That surfaces not as wrong numbers but as nonsense control values: a misread workspace query becomes an absurdlwork, and the run dies in allocation or never finishes. Nothing catches it by inspection.A cross-project collision, found while testing
Dependency install directories now carry backend and GPU in their names (
blaspp-mkl-cpu-install). That is not cosmetic.RandBLAS's installer uses the same
RandNLA-projectlayout and named its BLAS++ install identically (blaspp-<backend>-install), with a different stamp filename. With a sharedRANDNLA_PROJECT_DIR, this script would rebuild over RandBLAS's BLAS++ — their stamp never matches ours — and RandBLAS's next run would reuse an artifact we had replaced underneath it, while its own stamp still described the original. Distinct names make it impossible; sharing is instead explicit viaBLASPP_INSTALL_DIR, verified by the conftest.Everything else
gesdd, and RandLAPACK callsgesddinrl_rsvd.hh:146,rl_abrik.hh:692,rl_revd2.hh:208,rl_preconditioners.hh:355andrl_util.hh:413. That is what TEMPORARY: quarantine the macOS Accelerate gesdd test (revert after Mark's BLAS++/LAPACK++ review) #157's quarantine is about.--blas=acceleratewarns, citing Revert the macOS Accelerate quarantine (PR #157) once the upstream Accelerate PRs are approved #159. The hardcoded/opt/homebrewis fixed regardless.--no-extras/--no-benchmarks), unlike RandBLAS's examples — they need nothing this script has not already built.install.ps1now honoursRANDNLA_PROJECT_DIRwith the same precedence asinstall.sh, gains-ModifyEnvironment(User-scope, the only thing that survives a new shell) and-Prefix, and its path-length warning now checks the resolved path rather than only an explicitly passed one.INSTALL_SCRIPT.mdrewritten: current flags, corrected layout diagram, and a new section 6 with a tested-configuration table drawn from the CI lanes, the per-backend integer width, whether LP64 actually limits RandLAPACK, and why macOS is on OpenBLAS.Verification
Local Linux (gcc 15.2, oneAPI MKL, NVIDIA GPU present):
--no-gpublas/defines.h--no-gpu→--gpuRANDNLA_PROJECT_DIRWindows 11, Windows PowerShell 5.1, VS 2022 Build Tools: all three
-ProjectDirprecedence cases resolve as intended, and the User-scope environment write round-trips.RandBLAS submodule bump
Also bumps the vendored RandBLAS from
04f2018to952251c(RandBLAS main), andRandLAPACK_RandBLAS_PINwith it.The three commits in that range are #185 (vcpkg manifest fix), #186 (CMake hygiene) and #187 (installer scripts). None of them touch
RandBLAS/headers — the library code is byte-identical, and everything in the range is build machinery. Two pieces of it matter here:randblas_stage_runtime_dlls()from its installed package and prints a configuration summary. As a subproject under RandLAPACK, which configures it withBUILD_TESTS=OFF, that summary reports tests as deliberately skipped rather than warning.CMakeLists.txtenforces that the pin variable and the submodule move together, and it means it: the cross-check compares the variable againstgit ls-tree HEAD RandBLAS, so a staged-but-uncommitted bump fails configure until both land in one commit. Worth knowing if you ever bump this iteratively — it is not satisfiable before committing.Verified: clean build against the bumped submodule, and the full suite re-run.
Notes for reviewers
main. The tree is byte-identical to the state tested and green as three separate PRs.-ModifyEnvironmentis not verified end to end. It runs at the end of a successful install, and I could not reach it: the clone sits on a\\wsl.localhostpath and Windowsgitrefuses it withdubious ownership. Precedence and the User-scope write are each verified directly, but not together in one completed run.