Skip to content

Comments

reenable precompilation progress output even in non-interactive mode#61064

Open
KristofferC wants to merge 1 commit intomasterfrom
kc/precompiling_output
Open

reenable precompilation progress output even in non-interactive mode#61064
KristofferC wants to merge 1 commit intomasterfrom
kc/precompiling_output

Conversation

@KristofferC
Copy link
Member

Fixes #59924

@KristofferC KristofferC added the backport 1.13 Change should be backported to release-1.13 label Feb 18, 2026
@topolarity topolarity requested a review from vtjnash February 18, 2026 13:40
@vtjnash
Copy link
Member

vtjnash commented Feb 18, 2026

This introduces a regression into our tests output, which needs to be corrected before merging. We can change the noisiness heuristics here, but it needs to be done in a way that avoids printing output from the background to avoid fighting for the terminal, like from a script or other usages like that, including Pkg.precompile after #60943:

precompile                                                   (1) |        started at 2026-02-18T13:50:16.326
Precompiling packages...
    640.0 ms  ✓ F2oo4b3a94a1a081a8cb (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
   3830.7 ms  ✓ Foo4b3a94a1a081a8cb (serial)
  1 dependency successfully precompiled in 4 seconds
Precompiling packages...
    627.5 ms  ✓ Nest4b3a94a1a081a8cb (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
   1326.4 ms  ✓ UsesB4b3a94a1a081a8cb (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    457.5 ms  ? UseBaz (serial)
Precompiling packages...
    632.2 ms  ✓ FooBar1 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
ERROR: LoadError: break me
Stacktrace:
  [1] error(s::String)
    @ Base ./error.jl:56
  [2] top-level scope
    @ /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar2.jl:2
  [3] include(mod::Module, _path::String)
    @ Base ./Base.jl:309
  [4] include_package_for_output(pkg::Base.PkgId, input::String, syntax_version::VersionNumber, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing)
    @ Base ./loading.jl:3288
  [5] top-level scope
    @ stdin:5
  [6] eval(m::Module, e::Any)
    @ Core ./boot.jl:489
  [7] include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
    @ Base ./loading.jl:3130
  [8] include_string
    @ ./loading.jl:3140 [inlined]
  [9] exec_options(opts::Base.JLOptions)
    @ Base ./client.jl:342
 [10] _start()
    @ Base ./client.jl:585
in expression starting at /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar2.jl:1
in expression starting at stdin:5
              ✗ FooBar2 (serial)
  0 dependencies successfully precompiled in 2 seconds
  1 dependency had output during precompilation:
┌ FooBar2
│  [Output was shown above]
└  
Precompiling packages...
ERROR: LoadError: Evaluation into the closed module `Base` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `Base` with `eval` during precompilation - don't do this.
Stacktrace:
  [1] eval(m::Module, e::Any)
    @ Core ./boot.jl:489
  [2] top-level scope
    @ /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar3.jl:2
  [3] include(mod::Module, _path::String)
    @ Base ./Base.jl:309
  [4] include_package_for_output(pkg::Base.PkgId, input::String, syntax_version::VersionNumber, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing)
    @ Base ./loading.jl:3288
  [5] top-level scope
    @ stdin:5
  [6] eval(m::Module, e::Any)
    @ Core ./boot.jl:489
  [7] include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
    @ Base ./loading.jl:3130
  [8] include_string
    @ ./loading.jl:3140 [inlined]
  [9] exec_options(opts::Base.JLOptions)
    @ Base ./client.jl:342
 [10] _start()
    @ Base ./client.jl:585
in expression starting at /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar3.jl:1
in expression starting at stdin:5
              ✗ FooBar3 (serial)
  0 dependencies successfully precompiled in 2 seconds
  1 dependency had output during precompilation:
┌ FooBar3
│  [Output was shown above]
└  
Precompiling packages...
ERROR: LoadError: Evaluation into the closed module `Base` breaks incremental compilation because the side effects will not be permanent. This is likely due to some other module mutating `Base` with `eval` during precompilation - don't do this.
Stacktrace:
  [1] include(mod::Module, _path::String)
    @ Base ./Base.jl:309
  [2] top-level scope
    @ /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar3.jl:2
  [3] include(mod::Module, _path::String)
    @ Base ./Base.jl:309
  [4] include_package_for_output(pkg::Base.PkgId, input::String, syntax_version::VersionNumber, depot_path::Vector{String}, dl_load_path::Vector{String}, load_path::Vector{String}, concrete_deps::Vector{Pair{Base.PkgId, UInt128}}, source::Nothing)
    @ Base ./loading.jl:3288
  [5] top-level scope
    @ stdin:5
  [6] eval(m::Module, e::Any)
    @ Core ./boot.jl:489
  [7] include_string(mapexpr::typeof(identity), mod::Module, code::String, filename::String)
    @ Base ./loading.jl:3130
  [8] include_string
    @ ./loading.jl:3140 [inlined]
  [9] exec_options(opts::Base.JLOptions)
    @ Base ./client.jl:342
 [10] _start()
    @ Base ./client.jl:585
in expression starting at /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar3_inc.jl:1
in expression starting at /cache/build/tester-amdci4-8/julialang/julia-master/tmp/jltestdepot_vNl4YS/FooBar3.jl:1
in expression starting at stdin:5
              ✗ FooBar3 (serial)
  0 dependencies successfully precompiled in 2 seconds
  1 dependency had output during precompilation:
┌ FooBar3
│  [Output was shown above]
└  
Precompiling packages...
   1331.5 ms  ✓ FooBarT2 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    703.3 ms  ✓ Time4b3a94a1a081a8cb (serial)
  1 dependency successfully precompiled in 2 seconds
Precompiling packages...
    620.6 ms  ✓ Teste4095a83 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
   1362.8 ms  ✓ Issue19960B (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    656.8 ms  ✓ Aedb164bd3a126418 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    651.9 ms  ✓ Bedb164bd3a126418 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    661.9 ms  ✓ Issue19030 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    647.6 ms  ✓ Foo29936 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    676.0 ms  ✓ InitCachePath (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    629.2 ms  ✓ UniqueBinding1 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    643.0 ms  ✓ UniqueBinding2 (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    651.3 ms  ✓ LLVMCall (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    649.9 ms  ✓ LLVMCall (serial)
  1 dependency successfully precompiled in 1 seconds
Precompiling packages...
    630.5 ms  ✓ TestPkgNoManifest (serial)
  1 dependency successfully precompiled in 1 seconds
precompile                                                   (1) |   275.17 |   0.87 |  0.3 |     568.26 |   346.70

@topolarity
Copy link
Member

it needs to be done in a way that avoids printing output from the background to avoid fighting for the terminal, like from a script or other usages like that, including Pkg.precompile after #60943:

That sounds sensible, but how do we distinguish distinguish "background" non-interactive executions vs. "foreground" (e.g. CLI tools / Pkg app wrappers)?

Do we need to go by the -q flag or similar?

@vtjnash
Copy link
Member

vtjnash commented Feb 18, 2026

Maybe we should track the controlling terminal in the ScopedValue, just like unix?

@topolarity
Copy link
Member

Maybe we should track the controlling terminal in the ScopedValue, just like unix?

How does an (in-process) ScopedValue help with sharing the terminal across processes? Where does "control" transfer?

@topolarity
Copy link
Member

After a talk with @vtjnash , I think we clarified the request / idea:

@vtjnash agreed that these are OK to print if the user is "at the keyboard" and directly issued the command that's precompiling, but he wants to avoid clogging sub-process / script output with them. In particular, these messages can cause errors if your script calls Julia or a Julia-based app, but doesn't expect the "Precompiling..." message. The requirement then is to avoid adding this printing for non-interactive "background" / "child" processes (intentionally left a bit hand-wavey).

The main idea we discussed was to add a Base._is_foreground_process to complement Base.isinteractive as a heuristic for when we should be printing these "Precompiling" messages. We explored trying to check whether the current process is in a foreground vs. background process group via tcgetpgrp() or other utilities (https://pubs.opengroup.org/onlinepubs/009695299/basedefs/xbd_chap11.html), but these API's have no equivalent on Windows as far as we can tell. So this heuristic does not seem straightforward to implement across platforms. That heuristic is likely also flawed: Sometimes a "child" Julia process is likely to end up in a foreground process group, despite having an automated caller that is not expecting a "precompile" message.

Long story short, we think that the simplest thing to do here may be to disable this logging in -q quiet mode, which is similar to what uv does (uv run is similar to executing a Julia script / Pkg app):

--quiet, -q
Use quiet output.

Repeating this option, e.g., -qq, will enable a silent mode in which uv will write no output to stdout.

and Base.julia_cmd() should (arguably) be updated to enable this quiet mode by default.

@KristofferC
Copy link
Member Author

, these messages can cause errors if your script calls Julia or a Julia-based app, but doesn't expect the "Precompiling..."

I think this gets printed to stderr.

@topolarity
Copy link
Member

I think this gets printed to stderr.

That avoids some issues, but I still think it's fair that we support a mode that leaves all IO to the user-level Julia application, incl. stderr (equivalent to uv's -qq)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backport 1.13 Change should be backported to release-1.13

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Precompilation progress is not shown in non-interactive mode

3 participants