Export the generated and core wrapper symbols as public for GCC 16.2 - #30
Conversation
GCC 16.2.0 (PR126872) gives a PRIVATE module procedure bound to C hidden ELF visibility even though its binding label gives it external linkage, so dlsym() can no longer find it. #29 fixed real_kind_bytes in UTILITIES_CF, the first symbol the Julia wrapper resolves, but the same bare PRIVATE remains in two other places and hides the other 125 entry points, so the failure moves one step later instead of going away. GenFortranWrappers.jl writes PRIVATE into every module it generates, hiding 108 symbols across the 24 generated wrappers, PS_create_StrDim among them. SOCRATES_C.f90 carries its own bare PRIVATE, hiding the 20 radiative transfer entry points including PS_radiance_calc and PS_read_spectrum. Both kinds of module exist only to expose their bind(C) procedures, so PUBLIC is the appropriate default. Built with GCC 16.2.0 on macOS arm64: libSOCRATES_C.so exports all 128 PS_ symbols with none left local, where main exports 3 of 128.
|
Thanks for this, @egpbos. I thought that my last change to SOCRATES had resolved the problem - apparently it did not - but what you describe here makes sense to me. Have you tested these SOCRATES updates by running AGNI (standalone) and AGNI+PROTEUS (coupled) locally? You mention above that the tests pass, but I just want to be sure that using the model 'as intended' also passes with this patch. Bumping to 2603.10 is fine. |
|
Apologies for the mega ultra long Claude PR summary, I clearly need to tune my chatty bot much better still 😅 I think my Ponytail actually got lost in my laptop migration... Anyway. Yes, AGNI on my laptop (in a Pixi env btw, which is what I'm testing currently; seems to work) fails tests without these two fixes and passes with. My pixi-testing session initially had three fixes, but indeed you already caught one of them 😄 The setup was done on a clean PROTEUS clone of a few days ago. |
|
That's fantastic, thanks for clarifying. I am happy to merge this PR, then. I will then delete the SOCRATES cache from both PROTEUS and AGNI repos. I will then also re-run the AGNI Could you then make a PR on the PROTEUS side to update the SOCRATES hash in its |
Done: FormingWorlds/PROTEUS#863 However, it's blocking on AGNI pins, so we need to resolve them both. |
PR Summary
Sci/Tech Reviewer: @nichollsh
Code Reviewer:
Follow-up to #29. That PR fixed the first symptom of the GCC 16.2 symbol
visibility regression, but 125 of the 128 C binding symbols are still hidden,
so AGNI remains unable to load the library.
The compiler behaviour
GCC 16.2.0 (GCC PR126872) gives a
PRIVATEmodule procedure bound to C hiddenELF visibility, even though its binding label gives it external linkage. As a
result
dlsym()can no longer resolve it. Any wrapper module that relies onthe binding label alone, without naming the procedure in a
PUBLICstatement,stops being reachable from Julia.
Why #29 is not sufficient on its own
real_kind_bytesis the first symbol the Julia layer resolves: it is the RealKprecision probe at
julia/src/SOCRATES.jl:15, executed while the module isbeing loaded. So it is the first thing to fail and the natural thing to fix.
The same bare
PRIVATEappears in two further places, however, so fixing onlyUTILITIES_CFmoves the failure one step later rather than removing it.Counting
PS_symbols injulia/lib/libSOCRATES_C.so, built with GCC 16.2.0on macOS arm64:
T)t)PS_real_kind_bytesPS_create_StrDimWhat each line does
julia/src/GenFortranWrappers.jlwritesprivateinto the header of everymodule it generates. That hides 108 symbols across the 24 generated wrappers,
including
PS_create_StrDim, which is the next symbol AGNI resolves after theprecision probe, via
julia/gen/StrDim_JL.jl:9.julia/src/SOCRATES_C.f90carries its own bareprivate, which hides the 20radiative transfer entry points:
PS_radiance_calc,PS_read_spectrum,PS_set_spectrum,PS_diff_planck_sourceand thePS_allocate_*andPS_deallocate_*families. These are the calls that do the actual work, soeven once structure construction succeeded, nothing would run.
Both kinds of module exist solely to expose their
bind(C)procedures. Nothingin them is intended to be internal, so
PUBLICis the appropriate default, andit matches the treatment #29 gave
UTILITIES_CF.versiongoes from 2603.9 to 2603.10, mirroring what #29 did. Happy to dropthat hunk if it interferes with the release flow.
Downstream failures this fixes
Against current main, AGNI fails to precompile and then raises at runtime:
These PROTEUS tests fail against main and pass on this branch:
tests/integration/test_integration_agni_transparent_limit.py::test_transparent_greygas_olr_equals_blackbody_emissiontests/integration/test_integration_agni_transparent_limit.py::test_transparent_greygas_olr_scales_with_surface_emissivitytests/integration/test_integration_agni_transparent_limit.py::test_transparent_banded_olr_recovers_blackbody_emissiontests/integration/test_integration_agni_greygas_interior.py::test_agni_greygas_dummy_interior_couplingThe first three assert an analytic result, that outgoing longwave radiation
equals the surface blackbody emission in the transparent limit. They therefore
confirm that radiative transfer returns correct values, not merely that the
library loads.
PROTEUS pins SOCRATES by commit SHA and is still on 2603.8, so it will need its
pin bumped past this change to pick the fix up.
Code Quality Checklist
readability of the code
The change is one keyword in each of two locations, so no new comments were
warranted. The wrapper build reports the same pre-existing warnings as before
it (unused variables in
Utilities_CF.f90, a maybe-uninitialized inSOCRATES_C.f90) and no new ones.Testing
stem suites
acceptable (eg. kgo changes)
tests, unit tests, etc.)
The two source changes are confined to the
julia/wrapper layer, which the UMand LFRic Apps builds do not compile, so rose stem does not exercise them. No
test was added here because the behaviour is covered by the PROTEUS AGNI
coupling tests listed above; a SOCRATES-side equivalent would need a Julia test
harness this repository does not currently have.
Verification performed, all on macOS arm64 with GCC 16.2.0, netCDF-Fortran
4.6.4, Julia 1.12.7:
./configure && ./build_codeat this branch head, completing withAll compiled OK.julia generate_wrappers.jlfollowed bymakeinjulia/lib, thennm libSOCRATES_C.so, giving 128 exportedPS_symbols and none local.RAD_DIR:4 passed.
only these two source hunks: 4 failed, at
PS_create_StrDim.trac.log
Not applicable; this change was not tested through trac. The measurements above
stand in for it.
Security Considerations
The change widens Fortran module accessibility for procedures that already
carried C binding labels and were already intended to be called externally. It
exposes no new functionality.
Performance Impact
performance measurements have been conducted
Symbol visibility only. No effect on generated code paths or numerics.
AI Assistance and Attribution
of Claude Code (Claude Opus) and I have followed the
Simulation Systems AI policy
(including attribution labels)
The diagnosis, the two source changes and the verification runs above were
produced with Claude Code and reviewed by the author.
Documentation
confirmed that it builds correctly
No documented interface changes; the affected symbols were already part of the
intended Julia-facing API.