Skip to content

Commit f55307c

Browse files
authored
[backports 1.11] precompile: improve precision of extension dependencies (#56624)
This is a slimmed-down version of #55910, without any of the re-factoring. This improves the parallelism of the pre-compile job and fixes a correctness bug, where unconditionally injecting a dependency after its parent could be in conflict with dependencies in between triggers, causing false extension cycles. Without this fix, adding `AMDGPU.jl` and `Tracker.jl` reports a false cycle on 1.11
1 parent d59d80b commit f55307c

File tree

1 file changed

+42
-9
lines changed

1 file changed

+42
-9
lines changed

base/precompilation.jl

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -460,8 +460,6 @@ function _precompilepkgs(pkgs::Vector{String},
460460
# consider exts of direct deps to be direct deps so that errors are reported
461461
append!(direct_deps, keys(filter(d->last(d) in keys(env.project_deps), exts)))
462462

463-
@debug "precompile: deps collected"
464-
465463
# An extension effectively depends on another extension if it has a strict superset of its triggers
466464
for ext_a in keys(exts)
467465
for ext_b in keys(exts)
@@ -471,14 +469,49 @@ function _precompilepkgs(pkgs::Vector{String},
471469
end
472470
end
473471

472+
function expand_indirect_dependencies(direct_deps)
473+
function visit!(visited, node, all_deps)
474+
if node in visited
475+
return
476+
end
477+
push!(visited, node)
478+
for dep in get(Set{Base.PkgId}, direct_deps, node)
479+
if !(dep in all_deps)
480+
push!(all_deps, dep)
481+
visit!(visited, dep, all_deps)
482+
end
483+
end
484+
end
485+
486+
indirect_deps = Dict{Base.PkgId, Set{Base.PkgId}}()
487+
for package in keys(direct_deps)
488+
# Initialize a set to keep track of all dependencies for 'package'
489+
all_deps = Set{Base.PkgId}()
490+
visited = Set{Base.PkgId}()
491+
visit!(visited, package, all_deps)
492+
# Update direct_deps with the complete set of dependencies for 'package'
493+
indirect_deps[package] = all_deps
494+
end
495+
return indirect_deps
496+
end
497+
498+
indirect_deps = expand_indirect_dependencies(depsmap)
499+
@debug "precompile: deps collected"
500+
474501
# this loop must be run after the full depsmap has been populated
475-
for (pkg, pkg_exts) in pkg_exts_map
476-
# find any packages that depend on the extension(s)'s deps and replace those deps in their deps list with the extension(s),
477-
# basically injecting the extension into the precompile order in the graph, to avoid race to precompile extensions
478-
for (_pkg, deps) in depsmap # for each manifest dep
479-
if !in(_pkg, keys(exts)) && pkg in deps # if not an extension and depends on pkg
480-
append!(deps, pkg_exts) # add the package extensions to deps
481-
filter!(!isequal(pkg), deps) # remove the pkg from deps
502+
for ext in keys(exts)
503+
ext_loadable_in_pkg = Dict{Base.PkgId,Bool}()
504+
for pkg in keys(depsmap)
505+
is_trigger = in(pkg, depsmap[ext])
506+
is_extension = in(pkg, keys(exts))
507+
has_triggers = issubset(depsmap[ext], indirect_deps[pkg])
508+
ext_loadable_in_pkg[pkg] = !is_extension && has_triggers && !is_trigger
509+
end
510+
for (pkg, ext_loadable) in ext_loadable_in_pkg
511+
if ext_loadable && !any((dep)->ext_loadable_in_pkg[dep], depsmap[pkg])
512+
# add an edge if the extension is loadable by pkg, and was not loadable in any
513+
# of the pkg's dependencies
514+
push!(depsmap[pkg], ext)
482515
end
483516
end
484517
end

0 commit comments

Comments
 (0)