Skip to content

Pre-load OMC shared libraries by absolute path in topological order#15

Merged
JKRT merged 2 commits into
OpenModelica:masterfrom
SVAGEN26:fix-dlopen-topological-order
Jun 13, 2026
Merged

Pre-load OMC shared libraries by absolute path in topological order#15
JKRT merged 2 commits into
OpenModelica:masterfrom
SVAGEN26:fix-dlopen-topological-order

Conversation

@SVAGEN26

Copy link
Copy Markdown
Contributor

Problem

Tests in JKRT/OM.jl PR #44 (and any other downstream consumer of OMRuntimeExternalC.jl on Linux CI) fail with:

could not load library ".../libModelicaStandardTables.so"
libModelicaIO.so: cannot open shared object file: No such file or directory

even though libModelicaIO.so exists next to libModelicaStandardTables.so in lib/ext/shared/x86_64-linux-gnu/. Knock-on effect is 8 errored tests under OMRuntimeExternalC API and 10+ errored / failed tests under externalBuiltinTests.jl and downstream IMTK simulate paths in JKRT/OM.jl CI.

Root cause

Every .so in the libs-v0.1.0 release zip has its DT_RUNPATH baked to the original build host:

$ readelf -d libModelicaStandardTables.so | grep RUNPATH
RUNPATH  /home/johti17/Projects/OpenModelica/build_cmake/OMCompiler/SimulationRuntime/ModelicaExternalC:...

That path does not exist on consumer machines, so ld.so cannot resolve inter-library DT_NEEDED references on its own. The previous __init__ only pre-loaded libModelicaCallbacks, libModelicaIO and libModelicaExternalC, leaving libOpenModelicaRuntimeC, libomcgc, libModelicaMatIO, libModelicaStandardTables and libSimulationRuntimeC unresolved.

The ENV["LD_LIBRARY_PATH"] mutation in the old __init__ is ineffective on Linux because glibc's ld.so caches LD_LIBRARY_PATH at process start.

Fix

Pre-load every shipped library by absolute path with RTLD_GLOBAL in a fixed topological order:

libModelicaCallbacks
libomcgc
libOpenModelicaRuntimeC
libModelicaMatIO
libModelicaIO
libModelicaStandardTables
libModelicaExternalC
libSimulationRuntimeC

ld.so reuses the already-loaded library when it sees the same SONAME on a dependent load, so DT_NEEDED references are satisfied without relying on RUNPATH or LD_LIBRARY_PATH. SONAMEs in the release zip match the DT_NEEDED entries verbatim, so reuse is guaranteed.

libModelicaCallbacks is still loaded first so its symbols win global resolution and override the default OMC setjmp/longjmp-based error handlers.

Test evidence

Reproduced with the libs-v0.1.0 release zip on Linux x86_64, Julia 1.12.6:

Before (upstream master):

Attempting dlopen of: .../libModelicaStandardTables.so
FAILED: could not load library ".../libModelicaStandardTables.so"
libModelicaIO.so: cannot open shared object file: No such file or directory

After this PR:

Attempting dlopen of: .../libModelicaStandardTables.so
OK, handle = Ptr{Nothing}(0x0000000025f84850)

Identical error string in the before-state to what JKRT/OM.jl PR #44 CI emits.

Follow-ups not in this PR

  • The release-side fix (rebuild the prebuilt libs with -Wl,-rpath,'$ORIGIN' -Wl,--enable-new-dtags) is still worth doing eventually so the package does not have to babysit ld.so. This PR makes the Julia-side correct regardless.
  • The libs-v0.1.0 release ships libomcgc.so but pathSetup.jl does not track it; the new __init__ locates it by name from libdir, which keeps the change minimal. Tracking it in pathSetup.jl can come later if anything else needs to reference the path.
  • The 404 for x86_64-linux-gnu-callbacks.tar.gz in build.jl is a separate, pre-existing release-artifact gap (local fallback handles it but should be cleaned up).

Refs JKRT/OM.jl#44

The prebuilt .so files shipped in the libs-v0.1.0 release have RUNPATH
baked to the original build host (/home/johti17/Projects/OpenModelica/
build_cmake/...), so ld.so cannot resolve inter-library DT_NEEDED
entries on consumer machines. The previous __init__ only dlopen'd
libModelicaCallbacks, libModelicaIO and libModelicaExternalC, leaving
libOpenModelicaRuntimeC, libomcgc, libModelicaMatIO,
libModelicaStandardTables and libSimulationRuntimeC unresolved. As a
result loading libModelicaStandardTables.so fails with
"libModelicaIO.so: cannot open shared object file" whenever an external
Modelica function is invoked, even though libModelicaIO.so sits next to
it on disk. The ENV["LD_LIBRARY_PATH"] mutation in the old __init__ is
ineffective on Linux because glibc's ld.so caches LD_LIBRARY_PATH at
process start.

Dlopen every shipped library by absolute path with RTLD_GLOBAL in a
fixed topological order. ld.so reuses the already-loaded library when
it sees the same SONAME on a dependent load, so DT_NEEDED references
are satisfied without relying on RUNPATH or LD_LIBRARY_PATH. The
libModelicaCallbacks shim is still loaded first so its symbols win
global resolution and override the default OMC setjmp/longjmp-based
error handlers.

Verified with the libs-v0.1.0 zip on Linux: dlopen of
libModelicaStandardTables.so now succeeds where it previously failed
with the same error observed in JKRT/OM.jl#44 CI.

Refs JKRT/OM.jl#44

Co-Authored-By: JKRT_CLAUDE <247156613+SVAGEN26@users.noreply.github.com>
@SVAGEN26 SVAGEN26 marked this pull request as ready for review June 13, 2026 20:01
Co-Authored-By: JKRT_CLAUDE <247156613+SVAGEN26@users.noreply.github.com>
@JKRT JKRT merged commit 5df73ee into OpenModelica:master Jun 13, 2026
4 checks passed
@JKRT JKRT self-requested a review June 13, 2026 20:56
SVAGEN26 added a commit to SVAGEN26/OM.jl that referenced this pull request Jun 14, 2026
The OMRuntimeExternalC.jl libs-v0.1.0 Linux zip ships the OMC libraries
but not their system dependencies. libSimulationRuntimeC.so has
DT_NEEDED entries for liblapack.so.3, libblas.so.3 and libgfortran.so.5,
which ubuntu-24.04 runners do not provide out of the box. The Julia
__init__ pre-load (OpenModelica/OMRuntimeExternalC.jl#15) loads every
shipped OMC library correctly, then fails on libSimulationRuntimeC with
"liblapack.so.3: cannot open shared object file", taking down every MSL,
Spice3 and external-builtin test that goes through structural_simplify
or the OMC nonlinear solver.

Install liblapack3, libblas3 and libgfortran5 before julia-actions/
setup-julia runs. The Windows x86_64-mingw32 zip is self-contained
(libgfortran-5.dll, libgcc_s_seh-1.dll, libopenblas.dll, libstdc++-6.dll
and friends are all bundled), so no install step is needed there.

Refs JKRT#44, OpenModelica/OMRuntimeExternalC.jl#15

Co-Authored-By: JKRT_CLAUDE <247156613+SVAGEN26@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants