Pin gcc to keep SOCRATES shim symbols exported on macOS CI - #865
Merged
Merged
Conversation
Log which libSOCRATES_C.so exports PS_real_kind_bytes, which file Julia's Libdl resolves and opens, and any other libSOCRATES_C* copies under the Julia depot or the restored SOCRATES tree that could shadow the intended shim, ahead of building a fix for the precompile-ordering mismatch on macOS Integration CI. The step is gated behind a new shim-diagnostics input (default false) so it runs only where a caller opts in, currently the nightly integration-tier job on both OS legs, rather than on every setup-proteus caller. It also sets JULIA_DEBUG=loading on that job's pytest step. The step can never fail the job: every external command that can plausibly fail falls back to an explanatory echo.
Log gfortran's version, the SOCRATES tree revision against the tools/get_socrates.sh pin, the content of RAD_DIR/bin/Mk_cmd if present, a direct grep for PS_real_kind_bytes in Utilities_CF.f90, and an unfiltered (no -U) nm scan of Utilities_CF.o and libSOCRATES_C.so for any real_kind symbol under a mangled name.
nm_check now captures nm's exit code inside the if condition instead of a bare command substitution, since a failed nm would otherwise abort the whole step under GitHub Actions' default -eo pipefail. The verbose relink dump and each relink_probe's piped tail now tolerate a failing link the same way. Gate the step to runner.os == 'macOS': it currently runs unconditionally on both matrix legs, and GNU nm on ubuntu-latest may not support the same flags as the macOS toolchain. Extend the Julia probe to call dlsym(PS_real_kind_bytes) directly, matching AGNI's own load path instead of only checking dlopen/dlpath.
Extracts the exact linker symbol name for PS_real_kind_bytes from nm -g output on the object file, with a literal fallback when no match is found, then reproduces the SOCRATES Makefile link recipe with -Wl,-exported_symbols_list,<file> as a fifth relink probe alongside the existing baseline, -ld_classic, -exported_symbol, and -export_dynamic probes. The verbose gfortran -shared -v dump is kept in full for this probe, unlike the others, since it needs full inspection for the auto-injected linker flags GitHub's toolchain adds. The symbol extraction guards its command substitution so a no-match result reaches the fallback branch instead of aborting the step under GitHub Actions' default -eo pipefail.
…uild Homebrew's gcc 16.2 Darwin driver stops exporting SOCRATES's Julia shim symbol PS_real_kind_bytes as external, so any AGNI build step that rebuilds libSOCRATES_C.so breaks Julia's dlsym lookup. 16.1 is the last release without that regression. Formulae must live in a tap, so the historical 16.1.0 formula is fetched into a throwaway local tap and installed by tap-qualified name; pinned before netcdf-fortran so its gcc dependency resolves to the pinned keg instead of upgrading it. Unlink any gcc the runner image already ships before installing the pinned keg, since a pre-existing keg under the same formula name would otherwise conflict with linking the tap-qualified one.
brew pin took the plain formula name, which two taps now define (homebrew-core and the throwaway pinned-toolchain tap holding the 16.1.0 formula), so it risks a tap-ambiguity error instead of pinning the installed keg. Use the same tap-qualified name already used for the install two lines above.
Drop the opt-in "Log AGNI shim diagnostics" step, since it was scaffolding for tracking down the PS_real_kind_bytes export bug, and it duplicates what the guard below now checks unconditionally. Add a hard-failing guard that checks libSOCRATES_C.so's export table with nm -gU on every macOS job, placed after "Build AGNI (Pkg.instantiate)" rather than right after the SOCRATES-build cache step. get_socrates.sh only produces radlib.a, never socrates/julia/lib/libSOCRATES_C.so, per the note at get_socrates.sh:204-208; that file is deps/build.jl's own output, and build.jl runs unconditionally, on every job, regardless of any cache hit or miss. Checking for it any earlier would fail every SOCRATES cache-miss run, before AGNI even builds the shim. Remove the now-unused shim-diagnostics input, its ci-nightly.yml pass-through, and the JULIA_DEBUG env var on the integration job that only that step read.
The new post-build guard piped nm -gU straight into grep -q under set -o pipefail. Once grep -q found its first match it exited and closed the pipe, so nm received SIGPIPE and exited non-zero; pipefail then reported that as the pipeline's own status, so the guard failed even when the symbol was present. A dispatched CI run on macOS hit this today: the guard reported PS_real_kind_bytes missing, but its own diagnostic fallback line, printed one step later from a second nm call, showed the symbol correctly exported as external. That confirmed the failure was the guard's own plumbing, not a real regression in the shim. Capture nm's output into a variable first, then grep the variable with a here-string instead of a live pipe. Nothing downstream can close early on nm anymore, so there is no writer left to receive SIGPIPE, and the check can only fail when the symbol is truly absent. Verified locally: the original form reproduces a false failure against a finite fixture with the symbol present, and the revised form reports it found under the same fixture.
…heck Pin the gcc formula fetch to the full 40-char homebrew-core commit SHA instead of a 7-char short SHA, so the fetch stays unambiguous, and note in the comment that this commit provides gcc 16.1.0. Reword the pin comment to describe the current reason for the pin (this driver exports SOCRATES's dlsym-visible shim symbols, a newer gcc drops them) instead of narrating the migration that produced it. Replace the prefix-match version gate with a token-and-linkage check. `brew unlink` does not remove a runner image's pre-existing gcc keg, so once a second keg coexists, `brew list --versions gcc` prints both versions on one line in Cellar order and the old prefix match fails even though the pinned version is installed. Check the version as its own token and confirm it is the linked keg. Separate the nm capture from its failure check in the shim symbol-export guard. Under set -euo pipefail, a failing nm previously aborted the step before the custom diagnostic could print, so a real nm failure looked identical to an empty result. The existing SIGPIPE-safe here-string grep for the symbol-absent case is unchanged.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #865 +/- ##
==========================================
- Coverage 93.24% 91.50% -1.75%
==========================================
Files 112 113 +1
Lines 16746 18437 +1691
Branches 2996 3411 +415
==========================================
+ Hits 15615 16870 +1255
- Misses 1125 1485 +360
- Partials 6 82 +76
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
nichollsh
approved these changes
Sep 9, 2026
Member
|
If I'm not mistaken, this issue was already solved through FormingWorlds/SOCRATES#29 and FormingWorlds/SOCRATES#30. The version upper bound shouldn't be necessary anymore. |
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.
Description
On macOS CI, a newer Homebrew gcc Darwin driver drops the SOCRATES shim's dlsym-visible symbols (
PS_real_kind_bytes,PS_create_StrDim, ...) fromlibSOCRATES_C.so's export table, so Julia'sdlsymlookup in AGNI fails at runtime and the Integration and Slow tiers fail withcould not load symbol.This pins gcc to the homebrew-core formula revision whose Darwin driver exports those symbols, installed through a throwaway tap and verified to be both present and the linked keg before the dependent packages install. It also adds a macOS step that runs
nm -gUon the freshly rebuilt shim and fails fast ifPS_real_kind_bytesis no longer exported, so a future toolchain regression is caught at setup rather than deep in a test run.Validation of changes
I dispatched the full nightly science validation workflow against this branch (run 34328401618): all 21 jobs pass, including the macOS Integration tier and every Slow tier shard that previously failed on the
dlsymlookup. The version gate and the shim symbol check were exercised on the GitHub-hosted macOS runner image.Checklist