Skip to content

Commit 4a83470

Browse files
authored
LazyLibrary: Make add_dependency! always ephemeral to a given process (#59233)
Like many registration / hook-like functions in Julia, this function is somewhat dangerous to use at (pre)compile-time. Depending on whether the `LazyLibrary` you are adding dependencies to was constructed in a separate pre-compilation process or not, your dependencies may or may not persist. This change errs on the side of consistency, and makes it so that `add_dependency!` is always an ephemeral operation that does not persist beyond the lifetime of the process, which makes it safe to temporarily register dependencies, e.g., during a sysimage build. (originally for JuliaLang/LinearAlgebra.jl#1407)
1 parent d9ae7fd commit 4a83470

File tree

2 files changed

+16
-5
lines changed

2 files changed

+16
-5
lines changed

base/libdl.jl

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,11 @@ libfoo = LazyLibrary(BundledLazyLibraryPath("libfoo.so.1.2.3"))
358358
"""
359359
BundledLazyLibraryPath(subpath) = LazyLibraryPath(PrivateShlibdirGetter(), subpath)
360360

361+
# Small helper struct to initialize a LazyLibrary with its initial set of dependencies
362+
struct InitialDependencies
363+
dependencies::Vector{Any}
364+
end
365+
(init::InitialDependencies)() = convert(Vector{LazyLibrary}, init.dependencies)
361366

362367
"""
363368
LazyLibrary(name, flags = <default dlopen flags>,
@@ -377,7 +382,11 @@ mutable struct LazyLibrary
377382
const flags::UInt32
378383

379384
# Dependencies that must be loaded before we can load
380-
dependencies::Vector{LazyLibrary}
385+
#
386+
# The OncePerProcess is introduced here so that any registered dependencies are
387+
# always ephemeral to a given process (instead of, e.g., persisting depending
388+
# on whether they were added in the process where this LazyLibrary was created)
389+
dependencies::Base.OncePerProcess{Vector{LazyLibrary}, InitialDependencies}
381390

382391
# Function that get called once upon initial load
383392
on_load_callback
@@ -390,7 +399,9 @@ mutable struct LazyLibrary
390399
return new(
391400
path,
392401
UInt32(flags),
393-
collect(dependencies),
402+
Base.OncePerProcess{Vector{LazyLibrary}}(
403+
InitialDependencies(collect(dependencies))
404+
),
394405
on_load_callback,
395406
Base.ReentrantLock(),
396407
C_NULL,
@@ -402,7 +413,7 @@ end
402413
# such as LBT needing to have OpenBLAS_jll added as a dependency dynamically.
403414
function add_dependency!(ll::LazyLibrary, dep::LazyLibrary)
404415
@lock ll.lock begin
405-
push!(ll.dependencies, dep)
416+
push!(ll.dependencies(), dep)
406417
end
407418
end
408419

@@ -418,7 +429,7 @@ function dlopen(ll::LazyLibrary, flags::Integer = ll.flags; kwargs...)
418429
# Check to see if another thread has already run this
419430
if ll.handle == C_NULL
420431
# Ensure that all dependencies are loaded
421-
for dep in ll.dependencies
432+
for dep in ll.dependencies()
422433
dlopen(dep; kwargs...)
423434
end
424435

test/stdlib_dependencies.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ try
214214
prop = getproperty(m, prop_name)
215215
if isa(prop, Libdl.LazyLibrary)
216216
lib_path = dlpath(prop)
217-
lazy_lib_deps = strip_soversion.(basename.(dlpath.(prop.dependencies)))
217+
lazy_lib_deps = strip_soversion.(basename.(dlpath.(prop.dependencies())))
218218
real_lib_deps = filter(!is_system_lib, get_deps_objectfile(lib_path))
219219

220220
# See if there are missing dependencies in the lazy library deps

0 commit comments

Comments
 (0)