From fe3dcaf97ed041367ffe465b893972b21aa32820 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 12 May 2026 11:57:57 -0400 Subject: [PATCH 1/7] Don't rely on Pkg being present in the juliac env This way we rely on the stdlib lookup of Pkg (e.g. `julia -e 'using Pkg'` just works), and then activate the project in question. --- src/compiling.jl | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiling.jl b/src/compiling.jl index ee0cba1..065a5e9 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -124,8 +124,7 @@ function compile_products(recipe::ImageRecipe) env_overrides["JULIA_LOAD_PATH"] = load_path_sep * tmp_prefs_env end - inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) --project=$project_arg -e "using Pkg; Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) - recipe.verbose && println("Running: $inst_cmd") + inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) -e "using Pkg; Pkg.activate(\"$project_arg\"); Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) recipe.verbose && println("Running: $inst_cmd") precompile_time = time_ns() if !success(pipeline(inst_cmd; stdout, stderr)) error("Error encountered during instantiate/precompile of app project.") From 52b7c7f15858348e49279f44e8517de0031ada27 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 12 May 2026 12:08:00 -0400 Subject: [PATCH 2/7] Fix accidentally deleted newline --- src/compiling.jl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/compiling.jl b/src/compiling.jl index 065a5e9..f0553a0 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -124,7 +124,8 @@ function compile_products(recipe::ImageRecipe) env_overrides["JULIA_LOAD_PATH"] = load_path_sep * tmp_prefs_env end - inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) -e "using Pkg; Pkg.activate(\"$project_arg\"); Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) recipe.verbose && println("Running: $inst_cmd") + inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) -e "using Pkg; Pkg.activate(\"$project_arg\"); Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) + recipe.verbose && println("Running: $inst_cmd") precompile_time = time_ns() if !success(pipeline(inst_cmd; stdout, stderr)) error("Error encountered during instantiate/precompile of app project.") From 3510d24f3cd23d739b41c96ce2c463dc92c2e1f8 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 12 May 2026 12:18:39 -0400 Subject: [PATCH 3/7] Evade string issues by passing the project path as an argument to the script --- src/compiling.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiling.jl b/src/compiling.jl index f0553a0..7ba129e 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -124,7 +124,7 @@ function compile_products(recipe::ImageRecipe) env_overrides["JULIA_LOAD_PATH"] = load_path_sep * tmp_prefs_env end - inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) -e "using Pkg; Pkg.activate(\"$project_arg\"); Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) + inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) -e "using Pkg; Pkg.activate(only(ARGS)); Pkg.instantiate(); Pkg.precompile()" $project_arg`, env_overrides...) recipe.verbose && println("Running: $inst_cmd") precompile_time = time_ns() if !success(pipeline(inst_cmd; stdout, stderr)) From d1236e478745452249fe83beb1b23f729bb6d4a6 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 12 May 2026 13:31:16 -0400 Subject: [PATCH 4/7] Revert "Don't rely on Pkg being present in the juliac env" Reverts 3510d24, 52b7c7f, and fe3dcaf. The Pkg.activate(only(ARGS)) workaround will be replaced with a JULIA_LOAD_PATH-based fix. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/compiling.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiling.jl b/src/compiling.jl index 7ba129e..ee0cba1 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -124,7 +124,7 @@ function compile_products(recipe::ImageRecipe) env_overrides["JULIA_LOAD_PATH"] = load_path_sep * tmp_prefs_env end - inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) -e "using Pkg; Pkg.activate(only(ARGS)); Pkg.instantiate(); Pkg.precompile()" $project_arg`, env_overrides...) + inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) --project=$project_arg -e "using Pkg; Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) recipe.verbose && println("Running: $inst_cmd") precompile_time = time_ns() if !success(pipeline(inst_cmd; stdout, stderr)) From f1dbb65d46f3edb6a77dd656068c08e26148c14e Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 12 May 2026 13:21:48 -0400 Subject: [PATCH 5/7] Set JULIA_LOAD_PATH explicitly for the precompile subprocess MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When JuliaC is invoked as a Pkg app, the Pkg-app shim points JULIA_LOAD_PATH at JuliaC's own env so that JuliaC's deps resolve. That env var is inherited by the Julia subprocess we spawn to run `Pkg.instantiate(); Pkg.precompile()` on the user's project, which leaks two ways: 1. `using Pkg` resolves via JuliaC's env (which today happens to have Pkg as a direct dep — but we shouldn't have to rely on that), and 2. the user's project is effectively shadowed by JuliaC's manifest during precompile resolution. Mirror the pattern PackageCompiler.jl uses (see PackageCompiler.jl `ensurecompiled` / `run_precompilation_script`) and pin JULIA_LOAD_PATH = ":@stdlib" (with the trim prefs env appended when applicable). The user's project goes first so `using ` resolves via its Project/Manifest; `@stdlib` guarantees `using Pkg` resolves to the bundled Pkg regardless of whether the user's project lists Pkg as a direct dep. We still pass --project=\$project_arg so that Pkg.instantiate() / Pkg.precompile() target the user's project via Base.active_project(). Addresses topolarity's review on #138 to handle this with JULIA_LOAD_PATH rather than by switching to Pkg.activate(ARGS). Co-Authored-By: Claude Opus 4.7 (1M context) --- src/compiling.jl | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/compiling.jl b/src/compiling.jl index ee0cba1..e380536 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -105,9 +105,14 @@ function compile_products(recipe::ImageRecipe) project_arg = isdir(project_arg) ? tmp_project : joinpath(tmp_project, basename(project_arg)) env_overrides = Dict{String,Any}() + # Pin JULIA_LOAD_PATH to the user's project plus `@stdlib` so that + # `using Pkg` resolves via the stdlib (no Pkg dep required in the user's + # project, and JuliaC's own env doesn't leak through when JuliaC is + # invoked as a Pkg app — see #127). + load_path_sep = Sys.iswindows() ? ";" : ":" + load_path_entries = [project_arg, "@stdlib"] tmp_prefs_env = nothing if is_trim_enabled(recipe) - load_path_sep = Sys.iswindows() ? ";" : ":" # Create a temporary environment with a LocalPreferences.toml that will be added to JULIA_LOAD_PATH. tmp_prefs_env = mktempdir() open(joinpath(tmp_prefs_env, "Project.toml"), "w") do io @@ -119,10 +124,9 @@ function compile_products(recipe::ImageRecipe) println(io, "[HostCPUFeatures]") println(io, "freeze_cpu_target = true") end - # Append the temp env to JULIA_LOAD_PATH - - env_overrides["JULIA_LOAD_PATH"] = load_path_sep * tmp_prefs_env + push!(load_path_entries, tmp_prefs_env) end + env_overrides["JULIA_LOAD_PATH"] = join(load_path_entries, load_path_sep) inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) --project=$project_arg -e "using Pkg; Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) recipe.verbose && println("Running: $inst_cmd") From 2edcccf4acf4331dbc5989822bbdfb22d4702810 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Tue, 12 May 2026 13:46:26 -0400 Subject: [PATCH 6/7] Condense comment --- src/compiling.jl | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/compiling.jl b/src/compiling.jl index e380536..37463e7 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -105,10 +105,7 @@ function compile_products(recipe::ImageRecipe) project_arg = isdir(project_arg) ? tmp_project : joinpath(tmp_project, basename(project_arg)) env_overrides = Dict{String,Any}() - # Pin JULIA_LOAD_PATH to the user's project plus `@stdlib` so that - # `using Pkg` resolves via the stdlib (no Pkg dep required in the user's - # project, and JuliaC's own env doesn't leak through when JuliaC is - # invoked as a Pkg app — see #127). + # Add `@stdlib` to the LOAD_PATH so Pkg can be discovered load_path_sep = Sys.iswindows() ? ";" : ":" load_path_entries = [project_arg, "@stdlib"] tmp_prefs_env = nothing From fb5bb3260a86091018bb8f2f17304cfdd56a5285 Mon Sep 17 00:00:00 2001 From: Anshul Singhvi Date: Fri, 15 May 2026 21:37:04 -0400 Subject: [PATCH 7/7] Don't inherit JULIA_LOAD_PATH from the parent for the precompile subprocess MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When JuliaC is invoked as a Pkg app, the Pkg-app shim sets JULIA_LOAD_PATH to JuliaC's own env. That value gets inherited by the Julia subprocess we spawn for Pkg.instantiate/precompile, so the subprocess's LOAD_PATH becomes just JuliaC's env — no @stdlib, no @ — and `using Pkg` (along with anything else in startup.jl, like `using REPL`) fails unless JuliaC happens to list it as a direct dep. Per topolarity's review, set JULIA_LOAD_PATH => nothing in the env overrides so Julia falls back to its default load path. The leading `:` trick is preserved for the trim case, which appends the temp prefs env to the default. Verified locally by setting parent JULIA_LOAD_PATH= and running compile_products on test/AppProject; previously crashed in the subprocess startup, now succeeds. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/compiling.jl | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/compiling.jl b/src/compiling.jl index 37463e7..81070ac 100644 --- a/src/compiling.jl +++ b/src/compiling.jl @@ -104,12 +104,13 @@ function compile_products(recipe::ImageRecipe) end project_arg = isdir(project_arg) ? tmp_project : joinpath(tmp_project, basename(project_arg)) - env_overrides = Dict{String,Any}() - # Add `@stdlib` to the LOAD_PATH so Pkg can be discovered - load_path_sep = Sys.iswindows() ? ";" : ":" - load_path_entries = [project_arg, "@stdlib"] + # Drop any inherited JULIA_LOAD_PATH (e.g. set by the Pkg-app shim to + # JuliaC's own env) so the subprocess falls back to the default + # ["@", "@v#.#", "@stdlib"] and `using Pkg` resolves via @stdlib. + env_overrides = Dict{String,Any}("JULIA_LOAD_PATH" => nothing) tmp_prefs_env = nothing if is_trim_enabled(recipe) + load_path_sep = Sys.iswindows() ? ";" : ":" # Create a temporary environment with a LocalPreferences.toml that will be added to JULIA_LOAD_PATH. tmp_prefs_env = mktempdir() open(joinpath(tmp_prefs_env, "Project.toml"), "w") do io @@ -121,9 +122,10 @@ function compile_products(recipe::ImageRecipe) println(io, "[HostCPUFeatures]") println(io, "freeze_cpu_target = true") end - push!(load_path_entries, tmp_prefs_env) + # Leading separator → an empty entry that expands to the default load path, + # then append the temp prefs env. + env_overrides["JULIA_LOAD_PATH"] = load_path_sep * tmp_prefs_env end - env_overrides["JULIA_LOAD_PATH"] = join(load_path_entries, load_path_sep) inst_cmd = addenv(`$(Base.julia_cmd(cpu_target=precompile_cpu_target)) --project=$project_arg -e "using Pkg; Pkg.instantiate(); Pkg.precompile()"`, env_overrides...) recipe.verbose && println("Running: $inst_cmd")