Skip to content

Commit 08d229f

Browse files
authored
Extensions: make loading of extensions independent of what packages are in the sysimage (JuliaLang#52841)
When triggers of extension are in the sysimage it is easy to end up with cycles in package loading. Say we have a package A with exts BExt and CExt and say that B and C is in the sysimage. - Upon loading A, we will immidiately start to precompile BExt (because the trigger B is "loaded" by virtue of being in the sysimage). - BExt will load A which will cause CExt to start precompiling (again because C is in the sysimage). - CExt will load A which will now cause BExt to start loading and we get a cycle. This is fixed in this PR by instead of looking at what modules are loaded, we look at what modules are actually `require`d and only use that to drive the loading of extensions. Fixes JuliaLang#52132.
1 parent 9669eec commit 08d229f

File tree

6 files changed

+40
-3
lines changed

6 files changed

+40
-3
lines changed

base/Base.jl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,7 @@ function __init__()
627627
init_load_path()
628628
init_active_project()
629629
append!(empty!(_sysimage_modules), keys(loaded_modules))
630+
empty!(explicit_loaded_modules)
630631
if haskey(ENV, "JULIA_MAX_NUM_PRECOMPILE_FILES")
631632
MAX_NUM_PRECOMPILE_FILES[] = parse(Int, ENV["JULIA_MAX_NUM_PRECOMPILE_FILES"])
632633
end

base/loading.jl

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1354,7 +1354,7 @@ function _insert_extension_triggers(parent::PkgId, extensions::Dict{String, Any}
13541354
# TODO: Better error message if this lookup fails?
13551355
uuid_trigger = UUID(weakdeps[trigger]::String)
13561356
trigger_id = PkgId(uuid_trigger, trigger)
1357-
if !haskey(Base.loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
1357+
if !haskey(explicit_loaded_modules, trigger_id) || haskey(package_locks, trigger_id)
13581358
trigger1 = get!(Vector{ExtensionId}, EXT_DORMITORY, trigger_id)
13591359
push!(trigger1, gid)
13601360
else
@@ -1986,6 +1986,11 @@ function __require_prelocked(uuidkey::PkgId, env=nothing)
19861986
# After successfully loading, notify downstream consumers
19871987
run_package_callbacks(uuidkey)
19881988
else
1989+
m = get(loaded_modules, uuidkey, nothing)
1990+
if m !== nothing
1991+
explicit_loaded_modules[uuidkey] = m
1992+
run_package_callbacks(uuidkey)
1993+
end
19891994
newm = root_module(uuidkey)
19901995
end
19911996
return newm
@@ -2000,6 +2005,8 @@ PkgOrigin() = PkgOrigin(nothing, nothing, nothing)
20002005
const pkgorigins = Dict{PkgId,PkgOrigin}()
20012006

20022007
const loaded_modules = Dict{PkgId,Module}()
2008+
# Emptied on Julia start
2009+
const explicit_loaded_modules = Dict{PkgId,Module}()
20032010
const loaded_modules_order = Vector{Module}()
20042011
const module_keys = IdDict{Module,PkgId}() # the reverse
20052012

@@ -2023,6 +2030,7 @@ root_module_key(m::Module) = @lock require_lock module_keys[m]
20232030
end
20242031
push!(loaded_modules_order, m)
20252032
loaded_modules[key] = m
2033+
explicit_loaded_modules[key] = m
20262034
module_keys[m] = key
20272035
end
20282036
nothing

test/loading.jl

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1113,6 +1113,24 @@ end
11131113
cmd_proj_ext = addenv(cmd_proj_ext, "JULIA_LOAD_PATH" => join([joinpath(proj, "HasExtensions.jl"), joinpath(proj, "EnvWithDeps")], sep))
11141114
run(cmd_proj_ext)
11151115
end
1116+
1117+
# Sysimage extensions
1118+
# The test below requires that LinearAlgebra is in the sysimage and that it has not been loaded yet.
1119+
# if it gets moved out, this test will need to be updated.
1120+
# We run this test in a new process so we are not vulnerable to a previous test having loaded LinearAlgebra
1121+
sysimg_ext_test_code = """
1122+
uuid_key = Base.PkgId(Base.UUID("37e2e46d-f89d-539d-b4ee-838fcccc9c8e"), "LinearAlgebra")
1123+
Base.in_sysimage(uuid_key) || error("LinearAlgebra not in sysimage")
1124+
haskey(Base.explicit_loaded_modules, uuid_key) && error("LinearAlgebra already loaded")
1125+
using HasExtensions
1126+
Base.get_extension(HasExtensions, :LinearAlgebraExt) === nothing || error("unexpectedly got an extension")
1127+
using LinearAlgebra
1128+
haskey(Base.explicit_loaded_modules, uuid_key) || error("LinearAlgebra not loaded")
1129+
Base.get_extension(HasExtensions, :LinearAlgebraExt) isa Module || error("expected extension to load")
1130+
"""
1131+
cmd = `$(Base.julia_cmd()) --startup-file=no -e $sysimg_ext_test_code`
1132+
cmd = addenv(cmd, "JULIA_LOAD_PATH" => join([proj, "@stdlib"], sep))
1133+
run(cmd)
11161134
finally
11171135
try
11181136
rm(depot_path, force=true, recursive=true)

test/project/Extensions/HasDepWithExtensions.jl/Manifest.toml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This file is machine-generated - editing it directly is not advised
22

3-
julia_version = "1.10.0-DEV"
3+
julia_version = "1.10.0"
44
manifest_format = "2.0"
55
project_hash = "d523b3401f72a1ed34b7b43749fd2655c6b78542"
66

@@ -19,11 +19,16 @@ version = "0.1.0"
1919
path = "../HasExtensions.jl"
2020
uuid = "4d3288b3-3afc-4bb6-85f3-489fffe514c8"
2121
version = "0.1.0"
22-
weakdeps = ["ExtDep", "ExtDep2"]
2322

2423
[deps.HasExtensions.extensions]
2524
Extension = "ExtDep"
2625
ExtensionFolder = ["ExtDep", "ExtDep2"]
26+
LinearAlgebraExt = "LinearAlgebra"
27+
28+
[deps.HasExtensions.weakdeps]
29+
ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c"
30+
ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
31+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
2732

2833
[[deps.SomePackage]]
2934
path = "../SomePackage"

test/project/Extensions/HasExtensions.jl/Project.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ version = "0.1.0"
55
[weakdeps]
66
ExtDep = "fa069be4-f60b-4d4c-8b95-f8008775090c"
77
ExtDep2 = "55982ee5-2ad5-4c40-8cfe-5e9e1b01500d"
8+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
89

910
[extensions]
1011
Extension = "ExtDep"
1112
ExtensionFolder = ["ExtDep", "ExtDep2"]
13+
LinearAlgebraExt = "LinearAlgebra"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module LinearAlgebraExt
2+
3+
end

0 commit comments

Comments
 (0)