From 0101903aa0401946fe1dbba9630accbde0bd6279 Mon Sep 17 00:00:00 2001 From: projectured Date: Mon, 14 Sep 2026 14:38:34 +0200 Subject: [PATCH] ensurecompiled: load the packages instead of precompiling them `ensurecompiled` only has to leave a cache that the sysimage build can read. That build runs with `--pkgimages=no`, so it needs the source-only cache, and loading the packages writes it. `Pkg.precompile()` reaches the same state, but under `--pkgimages=no` Pkg's own native code is not available, so the first call in a process compiles Pkg's precompile path from IR. `ensurecompiled` starts a fresh process every build, so it pays that every time. On `examples/MyApp` with a warm depot of 381 packages, all with `--pkgimages=no`: `using Pkg; Pkg.precompile()` takes 28.7 s and 26.8 s on repeat, `import MyApp` takes 0.6 s and 0.6 s. In one process the first `Pkg.precompile()` costs 21.1 s and the second 0.0 s. Assisted-by: Claude Code (Opus 5) --- src/PackageCompiler.jl | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/PackageCompiler.jl b/src/PackageCompiler.jl index a5f48264..bba2cc75 100644 --- a/src/PackageCompiler.jl +++ b/src/PackageCompiler.jl @@ -497,8 +497,10 @@ end function ensurecompiled(project, packages, sysimage) length(packages) == 0 && return - # TODO: Only precompile `packages` (should be available in Pkg 1.8) - cmd = `$(get_julia_cmd()) --sysimage=$sysimage -e 'using Pkg; Pkg.precompile()'` + # `import` writes the source-only cache that the --pkgimages=no sysimage + # build needs. Pkg.precompile() would JIT-compile Pkg itself to do the same. + imports = join(("import " * String(package) for package in packages), "\n") + cmd = `$(get_julia_cmd()) --sysimage=$sysimage -e $imports` splitter = Sys.iswindows() ? ';' : ':' @debug "ensurecompiled: running $cmd" JULIA_LOAD_PATH = "$project$(splitter)@stdlib" cmd = addenv(cmd, "JULIA_LOAD_PATH" => "$project$(splitter)@stdlib")