Skip to content

Commit 5f51683

Browse files
vtjnashKristofferC
authored andcommitted
fix precompile process flag propagation (#56214)
CacheFlags could get set, but were never propagated to the target process, so the result would be unusable. Additionally, the debug and optimization levels were not synchronized with the sysimg, causing a regression in pkgimage usability after moving out stdlibs. Fixes #56207 Fixes #56054 Fixes #56206
1 parent dfc3521 commit 5f51683

File tree

9 files changed

+112
-64
lines changed

9 files changed

+112
-64
lines changed

base/Base.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ include("deepcopy.jl")
533533
include("download.jl")
534534
include("summarysize.jl")
535535
include("errorshow.jl")
536+
include("util.jl")
536537

537538
include("initdefs.jl")
538539
Filesystem.__postinit__()
@@ -549,7 +550,6 @@ include("loading.jl")
549550

550551
# misc useful functions & macros
551552
include("timing.jl")
552-
include("util.jl")
553553
include("client.jl")
554554
include("asyncmap.jl")
555555

base/loading.jl

Lines changed: 43 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1683,6 +1683,8 @@ function CacheFlags(cf::CacheFlags=CacheFlags(ccall(:jl_cache_flags, UInt8, ()))
16831683
opt_level === nothing ? cf.opt_level : opt_level
16841684
)
16851685
end
1686+
# reflecting jloptions.c defaults
1687+
const DefaultCacheFlags = CacheFlags(use_pkgimages=true, debug_level=isdebugbuild() ? 2 : 1, check_bounds=0, inline=true, opt_level=2)
16861688

16871689
function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
16881690
f = UInt8(0)
@@ -1694,12 +1696,29 @@ function _cacheflag_to_uint8(cf::CacheFlags)::UInt8
16941696
return f
16951697
end
16961698

1699+
function translate_cache_flags(cacheflags::CacheFlags, defaultflags::CacheFlags)
1700+
opts = String[]
1701+
cacheflags.use_pkgimages != defaultflags.use_pkgimages && push!(opts, cacheflags.use_pkgimages ? "--pkgimages=yes" : "--pkgimages=no")
1702+
cacheflags.debug_level != defaultflags.debug_level && push!(opts, "-g$(cacheflags.debug_level)")
1703+
cacheflags.check_bounds != defaultflags.check_bounds && push!(opts, ("--check-bounds=auto", "--check-bounds=yes", "--check-bounds=no")[cacheflags.check_bounds + 1])
1704+
cacheflags.inline != defaultflags.inline && push!(opts, cacheflags.inline ? "--inline=yes" : "--inline=no")
1705+
cacheflags.opt_level != defaultflags.opt_level && push!(opts, "-O$(cacheflags.opt_level)")
1706+
return opts
1707+
end
1708+
16971709
function show(io::IO, cf::CacheFlags)
1698-
print(io, "use_pkgimages = ", cf.use_pkgimages)
1699-
print(io, ", debug_level = ", cf.debug_level)
1700-
print(io, ", check_bounds = ", cf.check_bounds)
1701-
print(io, ", inline = ", cf.inline)
1702-
print(io, ", opt_level = ", cf.opt_level)
1710+
print(io, "CacheFlags(")
1711+
print(io, "; use_pkgimages=")
1712+
print(io, cf.use_pkgimages)
1713+
print(io, ", debug_level=")
1714+
print(io, cf.debug_level)
1715+
print(io, ", check_bounds=")
1716+
print(io, cf.check_bounds)
1717+
print(io, ", inline=")
1718+
print(io, cf.inline)
1719+
print(io, ", opt_level=")
1720+
print(io, cf.opt_level)
1721+
print(io, ")")
17031722
end
17041723

17051724
struct ImageTarget
@@ -2950,7 +2969,8 @@ end
29502969

29512970
const PRECOMPILE_TRACE_COMPILE = Ref{String}()
29522971
function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::Union{Nothing, String},
2953-
concrete_deps::typeof(_concrete_dependencies), flags::Cmd=``, internal_stderr::IO = stderr, internal_stdout::IO = stdout, isext::Bool=false)
2972+
concrete_deps::typeof(_concrete_dependencies), flags::Cmd=``, cacheflags::CacheFlags=CacheFlags(),
2973+
internal_stderr::IO = stderr, internal_stdout::IO = stdout, isext::Bool=false)
29542974
@nospecialize internal_stderr internal_stdout
29552975
rm(output, force=true) # Remove file if it exists
29562976
output_o === nothing || rm(output_o, force=true)
@@ -2993,24 +3013,29 @@ function create_expr_cache(pkg::PkgId, input::String, output::String, output_o::
29933013
deps = deps_eltype * "[" * join(deps_strs, ",") * "]"
29943014
precomp_stack = "Base.PkgId[$(join(map(pkg_str, vcat(Base.precompilation_stack, pkg)), ", "))]"
29953015

3016+
if output_o === nothing
3017+
# remove options that make no difference given the other cache options
3018+
cacheflags = CacheFlags(cacheflags, opt_level=0)
3019+
end
3020+
opts = translate_cache_flags(cacheflags, CacheFlags()) # julia_cmd is generated for the running system, and must be fixed if running for precompile instead
29963021
if output_o !== nothing
29973022
@debug "Generating object cache file for $(repr("text/plain", pkg))"
29983023
cpu_target = get(ENV, "JULIA_CPU_TARGET", nothing)
2999-
opts = `--output-o $(output_o) --output-ji $(output) --output-incremental=yes`
3024+
push!(opts, "--output-o", output_o)
30003025
else
30013026
@debug "Generating cache file for $(repr("text/plain", pkg))"
30023027
cpu_target = nothing
3003-
opts = `-O0 --output-ji $(output) --output-incremental=yes`
30043028
end
3029+
push!(opts, "--output-ji", output)
3030+
isassigned(PRECOMPILE_TRACE_COMPILE) && push!(opts, "--trace-compile=$(PRECOMPILE_TRACE_COMPILE[])")
30053031

3006-
trace = isassigned(PRECOMPILE_TRACE_COMPILE) ? `--trace-compile=$(PRECOMPILE_TRACE_COMPILE[]) --trace-compile-timing` : ``
30073032
io = open(pipeline(addenv(`$(julia_cmd(;cpu_target)::Cmd)
3008-
$(flags)
3009-
$(opts)
3010-
--startup-file=no --history-file=no --warn-overwrite=yes
3011-
--color=$(have_color === nothing ? "auto" : have_color ? "yes" : "no")
3012-
$trace
3013-
-`,
3033+
$(flags)
3034+
$(opts)
3035+
--output-incremental=yes
3036+
--startup-file=no --history-file=no --warn-overwrite=yes
3037+
$(have_color === nothing ? "--color=auto" : have_color ? "--color=yes" : "--color=no")
3038+
-`,
30143039
"OPENBLAS_NUM_THREADS" => 1,
30153040
"JULIA_NUM_THREADS" => 1),
30163041
stderr = internal_stderr, stdout = internal_stdout),
@@ -3128,7 +3153,7 @@ function compilecache(pkg::PkgId, path::String, internal_stderr::IO = stderr, in
31283153
close(tmpio_o)
31293154
close(tmpio_so)
31303155
end
3131-
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, flags, internal_stderr, internal_stdout, isext)
3156+
p = create_expr_cache(pkg, path, tmppath, tmppath_o, concrete_deps, flags, cacheflags, internal_stderr, internal_stdout, isext)
31323157

31333158
if success(p)
31343159
if cache_objects
@@ -4133,5 +4158,5 @@ end
41334158

41344159
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), Nothing)) || @assert false
41354160
precompile(include_package_for_output, (PkgId, String, Vector{String}, Vector{String}, Vector{String}, typeof(_concrete_dependencies), String)) || @assert false
4136-
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, IO, IO)) || @assert false
4137-
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, IO, IO)) || @assert false
4161+
precompile(create_expr_cache, (PkgId, String, String, String, typeof(_concrete_dependencies), Cmd, CacheFlags, IO, IO)) || @assert false
4162+
precompile(create_expr_cache, (PkgId, String, String, Nothing, typeof(_concrete_dependencies), Cmd, CacheFlags, IO, IO)) || @assert false

base/precompilation.jl

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ function printpkgstyle(io, header, msg; color=:green)
362362
end
363363

364364
const Config = Pair{Cmd, Base.CacheFlags}
365-
const PkgConfig = Tuple{Base.PkgId,Config}
365+
const PkgConfig = Tuple{PkgId,Config}
366366

367367
function precompilepkgs(pkgs::Vector{String}=String[];
368368
internal_call::Bool=false,
@@ -375,8 +375,22 @@ function precompilepkgs(pkgs::Vector{String}=String[];
375375
# asking for timing disables fancy mode, as timing is shown in non-fancy mode
376376
fancyprint::Bool = can_fancyprint(io) && !timing,
377377
manifest::Bool=false,)
378+
# monomorphize this to avoid latency problems
379+
_precompilepkgs(pkgs, internal_call, strict, warn_loaded, timing, _from_loading,
380+
configs isa Vector{Config} ? configs : [configs],
381+
IOContext{IO}(io), fancyprint, manifest)
382+
end
378383

379-
configs = configs isa Config ? [configs] : configs
384+
function _precompilepkgs(pkgs::Vector{String},
385+
internal_call::Bool,
386+
strict::Bool,
387+
warn_loaded::Bool,
388+
timing::Bool,
389+
_from_loading::Bool,
390+
configs::Vector{Config},
391+
io::IOContext{IO},
392+
fancyprint::Bool,
393+
manifest::Bool)
380394
requested_pkgs = copy(pkgs) # for understanding user intent
381395

382396
time_start = time_ns()
@@ -393,17 +407,32 @@ function precompilepkgs(pkgs::Vector{String}=String[];
393407

394408
if _from_loading && !Sys.isinteractive() && Base.get_bool_env("JULIA_TESTS", false)
395409
# suppress passive loading printing in julia test suite. `JULIA_TESTS` is set in Base.runtests
396-
io = devnull
410+
io = IOContext{IO}(devnull)
397411
end
398412

413+
nconfigs = length(configs)
399414
hascolor = get(io, :color, false)::Bool
400415
color_string(cstr::String, col::Union{Int64, Symbol}) = _color_string(cstr, col, hascolor)
401416

402417
stale_cache = Dict{StaleCacheKey, Bool}()
403-
exts = Dict{Base.PkgId, String}() # ext -> parent
418+
exts = Dict{PkgId, String}() # ext -> parent
404419
# make a flat map of each dep and its direct deps
405-
depsmap = Dict{Base.PkgId, Vector{Base.PkgId}}()
406-
pkg_exts_map = Dict{Base.PkgId, Vector{Base.PkgId}}()
420+
depsmap = Dict{PkgId, Vector{PkgId}}()
421+
pkg_exts_map = Dict{PkgId, Vector{PkgId}}()
422+
423+
function describe_pkg(pkg::PkgId, is_direct_dep::Bool, flags::Cmd, cacheflags::Base.CacheFlags)
424+
name = haskey(exts, pkg) ? string(exts[pkg], "", pkg.name) : pkg.name
425+
name = is_direct_dep ? name : color_string(name, :light_black)
426+
if nconfigs > 1 && !isempty(flags)
427+
config_str = join(flags, " ")
428+
name *= color_string(" `$config_str`", :light_black)
429+
end
430+
if nconfigs > 1
431+
config_str = join(Base.translate_cache_flags(cacheflags, Base.DefaultCacheFlags), " ")
432+
name *= color_string(" $config_str", :light_black)
433+
end
434+
return name
435+
end
407436

408437
for (dep, deps) in env.deps
409438
pkg = Base.PkgId(dep, env.names[dep])
@@ -569,7 +598,6 @@ function precompilepkgs(pkgs::Vector{String}=String[];
569598
end
570599
end
571600

572-
nconfigs = length(configs)
573601
target = nothing
574602
if nconfigs == 1
575603
if !isempty(only(configs)[1])
@@ -584,7 +612,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
584612
failed_deps = Dict{PkgConfig, String}()
585613
precomperr_deps = PkgConfig[] # packages that may succeed after a restart (i.e. loaded packages with no cache file)
586614

587-
print_lock = io isa Base.LibuvStream ? io.lock::ReentrantLock : ReentrantLock()
615+
print_lock = io.io isa Base.LibuvStream ? io.io.lock::ReentrantLock : ReentrantLock()
588616
first_started = Base.Event()
589617
printloop_should_exit::Bool = !fancyprint # exit print loop immediately if not fancy printing
590618
interrupted_or_done = Base.Event()
@@ -677,7 +705,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
677705
n_print_rows = 0
678706
while !printloop_should_exit
679707
lock(print_lock) do
680-
term_size = Base.displaysize_(io)
708+
term_size = displaysize(io)
681709
num_deps_show = max(term_size[1] - 3, 2) # show at least 2 deps
682710
pkg_queue_show = if !interrupted_or_done.set && length(pkg_queue) > num_deps_show
683711
last(pkg_queue, num_deps_show)
@@ -692,20 +720,16 @@ function precompilepkgs(pkgs::Vector{String}=String[];
692720
bar.max = n_total - n_already_precomp
693721
# when sizing to the terminal width subtract a little to give some tolerance to resizing the
694722
# window between print cycles
695-
termwidth = Base.displaysize_(io)[2] - 4
723+
termwidth = displaysize(io)[2] - 4
696724
if !final_loop
697725
str = sprint(io -> show_progress(io, bar; termwidth, carriagereturn=false); context=io)
698726
print(iostr, Base._truncate_at_width_or_chars(true, str, termwidth), "\n")
699727
end
700728
for pkg_config in pkg_queue_show
701729
dep, config = pkg_config
702730
loaded = warn_loaded && haskey(Base.loaded_modules, dep)
703-
_name = haskey(exts, dep) ? string(exts[dep], "", dep.name) : dep.name
704-
name = dep in direct_deps ? _name : string(color_string(_name, :light_black))
705-
if nconfigs > 1 && !isempty(config[1])
706-
config_str = "$(join(config[1], " "))"
707-
name *= color_string(" $(config_str)", :light_black)
708-
end
731+
flags, cacheflags = config
732+
name = describe_pkg(dep, dep in direct_deps, flags, cacheflags)
709733
line = if pkg_config in precomperr_deps
710734
string(color_string(" ? ", Base.warn_color()), name)
711735
elseif haskey(failed_deps, pkg_config)
@@ -793,12 +817,7 @@ function precompilepkgs(pkgs::Vector{String}=String[];
793817
std_pipe = Base.link_pipe!(Pipe(); reader_supports_async=true, writer_supports_async=true)
794818
t_monitor = @async monitor_std(pkg_config, std_pipe; single_requested_pkg)
795819

796-
_name = haskey(exts, pkg) ? string(exts[pkg], "", pkg.name) : pkg.name
797-
name = is_direct_dep ? _name : string(color_string(_name, :light_black))
798-
if nconfigs > 1 && !isempty(flags)
799-
config_str = "$(join(flags, " "))"
800-
name *= color_string(" $(config_str)", :light_black)
801-
end
820+
name = describe_pkg(pkg, is_direct_dep, flags, cacheflags)
802821
lock(print_lock) do
803822
if !fancyprint && isempty(pkg_queue)
804823
printpkgstyle(io, :Precompiling, something(target, "packages..."))

base/show.jl

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,11 @@ end
324324

325325
convert(::Type{IOContext}, io::IOContext) = io
326326
convert(::Type{IOContext}, io::IO) = IOContext(io, ioproperties(io))::IOContext
327+
convert(::Type{IOContext{IO_t}}, io::IOContext{IO_t}) where {IO_t} = io
328+
convert(::Type{IOContext{IO_t}}, io::IO) where {IO_t} = IOContext{IO_t}(io, ioproperties(io))::IOContext{IO_t}
327329

328330
IOContext(io::IO) = convert(IOContext, io)
331+
IOContext{IO_t}(io::IO) where {IO_t} = convert(IOContext{IO_t}, io)
329332

330333
function IOContext(io::IO, KV::Pair)
331334
d = ioproperties(io)
@@ -427,7 +430,7 @@ get(io::IO, key, default) = default
427430
keys(io::IOContext) = keys(io.dict)
428431
keys(io::IO) = keys(ImmutableDict{Symbol,Any}())
429432

430-
displaysize(io::IOContext) = haskey(io, :displaysize) ? io[:displaysize]::Tuple{Int,Int} : Base.displaysize_(io.io)
433+
displaysize(io::IOContext) = haskey(io, :displaysize) ? io[:displaysize]::Tuple{Int,Int} : displaysize(io.io)
431434

432435
show_circular(io::IO, @nospecialize(x)) = false
433436
function show_circular(io::IOContext, @nospecialize(x))

base/util.jl

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ function julia_cmd(julia=joinpath(Sys.BINDIR, julia_exename()); cpu_target::Unio
249249
end
250250

251251
function julia_exename()
252-
if !Base.isdebugbuild()
252+
if !isdebugbuild()
253253
return @static Sys.iswindows() ? "julia.exe" : "julia"
254254
else
255255
return @static Sys.iswindows() ? "julia-debug.exe" : "julia-debug"
@@ -530,7 +530,6 @@ function _crc32c(io::IO, nb::Integer, crc::UInt32=0x00000000)
530530
end
531531
_crc32c(io::IO, crc::UInt32=0x00000000) = _crc32c(io, typemax(Int64), crc)
532532
_crc32c(io::IOStream, crc::UInt32=0x00000000) = _crc32c(io, filesize(io)-position(io), crc)
533-
_crc32c(uuid::UUID, crc::UInt32=0x00000000) = _crc32c(uuid.value, crc)
534533
_crc32c(x::UInt128, crc::UInt32=0x00000000) =
535534
ccall(:jl_crc32c, UInt32, (UInt32, Ref{UInt128}, Csize_t), crc, x, 16)
536535
_crc32c(x::UInt64, crc::UInt32=0x00000000) =

base/uuid.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ let
3636
Base.hash(uuid::UUID, h::UInt) = hash(uuid_hash_seed, hash(convert(NTuple{2, UInt64}, uuid), h))
3737
end
3838

39+
_crc32c(uuid::UUID, crc::UInt32=0x00000000) = _crc32c(uuid.value, crc)
40+
3941
let
4042
@inline function uuid_kernel(s, i, u)
4143
_c = UInt32(@inbounds codeunit(s, i))

pkgimage.mk

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ print-depot-path:
2525
@$(call PRINT_JULIA, $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e '@show Base.DEPOT_PATH')
2626

2727
$(BUILDDIR)/stdlib/%.image: $(JULIAHOME)/stdlib/Project.toml $(JULIAHOME)/stdlib/Manifest.toml $(INDEPENDENT_STDLIBS_SRCS) $(JULIA_DEPOT_PATH)/compiled
28-
@$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e 'Base.Precompilation.precompilepkgs(;configs=[``=>Base.CacheFlags(), `--check-bounds=yes`=>Base.CacheFlags(;check_bounds=1)])')
28+
@$(call PRINT_JULIA, JULIA_CPU_TARGET="$(JULIA_CPU_TARGET)" $(call spawn,$(JULIA_EXECUTABLE)) --startup-file=no -e \
29+
'Base.Precompilation.precompilepkgs(configs=[``=>Base.CacheFlags(debug_level=2, opt_level=3), ``=>Base.CacheFlags(check_bounds=1, debug_level=2, opt_level=3)])')
2930
touch $@
3031

3132
$(BUILDDIR)/stdlib/release.image: $(build_private_libdir)/sys.$(SHLIB_EXT)

src/staticdata_utils.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -605,15 +605,15 @@ static void write_mod_list(ios_t *s, jl_array_t *a)
605605
write_int32(s, 0);
606606
}
607607

608-
// OPT_LEVEL should always be the upper bits
609608
#define OPT_LEVEL 6
609+
#define DEBUG_LEVEL 1
610610

611611
JL_DLLEXPORT uint8_t jl_cache_flags(void)
612612
{
613613
// OOICCDDP
614614
uint8_t flags = 0;
615615
flags |= (jl_options.use_pkgimages & 1); // 0-bit
616-
flags |= (jl_options.debug_level & 3) << 1; // 1-2 bit
616+
flags |= (jl_options.debug_level & 3) << DEBUG_LEVEL; // 1-2 bit
617617
flags |= (jl_options.check_bounds & 3) << 3; // 3-4 bit
618618
flags |= (jl_options.can_inline & 1) << 5; // 5-bit
619619
flags |= (jl_options.opt_level & 3) << OPT_LEVEL; // 6-7 bit
@@ -636,14 +636,13 @@ JL_DLLEXPORT uint8_t jl_match_cache_flags(uint8_t requested_flags, uint8_t actua
636636
actual_flags &= ~1;
637637
}
638638

639-
// 2. Check all flags, except opt level must be exact
640-
uint8_t mask = (1 << OPT_LEVEL)-1;
639+
// 2. Check all flags, except opt level and debug level must be exact
640+
uint8_t mask = (~(3u << OPT_LEVEL) & ~(3u << DEBUG_LEVEL)) & 0x7f;
641641
if ((actual_flags & mask) != (requested_flags & mask))
642642
return 0;
643-
// 3. allow for higher optimization flags in cache
644-
actual_flags >>= OPT_LEVEL;
645-
requested_flags >>= OPT_LEVEL;
646-
return actual_flags >= requested_flags;
643+
// 3. allow for higher optimization and debug level flags in cache to minimize required compile option combinations
644+
return ((actual_flags >> OPT_LEVEL) & 3) >= ((requested_flags >> OPT_LEVEL) & 3) &&
645+
((actual_flags >> DEBUG_LEVEL) & 3) >= ((requested_flags >> DEBUG_LEVEL) & 3);
647646
}
648647

649648
JL_DLLEXPORT uint8_t jl_match_cache_flags_current(uint8_t flags)

test/loading.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,10 +1206,7 @@ end
12061206
@test cf.check_bounds == 3
12071207
@test cf.inline
12081208
@test cf.opt_level == 3
1209-
1210-
io = PipeBuffer()
1211-
show(io, cf)
1212-
@test read(io, String) == "use_pkgimages = true, debug_level = 3, check_bounds = 3, inline = true, opt_level = 3"
1209+
@test repr(cf) == "CacheFlags(; use_pkgimages=true, debug_level=3, check_bounds=3, inline=true, opt_level=3)"
12131210
end
12141211

12151212
empty!(Base.DEPOT_PATH)
@@ -1401,13 +1398,16 @@ end
14011398
"JULIA_DEPOT_PATH" => depot_path,
14021399
"JULIA_DEBUG" => "loading")
14031400

1404-
out = Pipe()
1405-
proc = run(pipeline(cmd, stdout=out, stderr=out))
1406-
close(out.in)
1407-
1408-
log = @async String(read(out))
1409-
@test success(proc)
1410-
fetch(log)
1401+
out = Base.PipeEndpoint()
1402+
log = @async read(out, String)
1403+
try
1404+
proc = run(pipeline(cmd, stdout=out, stderr=out))
1405+
@test success(proc)
1406+
catch
1407+
@show fetch(log)
1408+
rethrow()
1409+
end
1410+
return fetch(log)
14111411
end
14121412

14131413
log = load_package("Parent", `--compiled-modules=no --pkgimages=no`)

0 commit comments

Comments
 (0)