Skip to content

Commit

Permalink
juliac: add pre-compilation step to build pipeline (#57207)
Browse files Browse the repository at this point in the history
This is required to avoid obscure loading / package errors during the
trimming build process.
  • Loading branch information
topolarity authored Jan 31, 2025
1 parent cf4ab83 commit 2a9c133
Showing 1 changed file with 58 additions and 37 deletions.
95 changes: 58 additions & 37 deletions contrib/juliac.jl
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Julia compiler wrapper script
# NOTE: The interface and location of this script are considered unstable/experimental

cmd = Base.julia_cmd()
cmd = `$cmd --startup-file=no --history-file=no`
julia_cmd = `$(Base.julia_cmd()) --startup-file=no --history-file=no`
output_type = nothing # exe, sharedlib, sysimage
outname = nothing
file = nothing
Expand Down Expand Up @@ -55,55 +54,77 @@ isnothing(outname) && error("No output file specified")
isnothing(file) && error("No input file specified")

absfile = abspath(file)
cflags = readchomp(`$(cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --cflags `)
cflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --cflags `)
cflags = Base.shell_split(cflags)
allflags = readchomp(`$(cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --allflags`)
allflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --allflags`)
allflags = Base.shell_split(allflags)
tmpdir = mktempdir(cleanup=false)
initsrc_path = joinpath(tmpdir, "init.c")
init_path = joinpath(tmpdir, "init.a")
img_path = joinpath(tmpdir, "img.a")
bc_path = joinpath(tmpdir, "img-bc.a")

open(initsrc_path, "w") do io
print(io, """
#include <julia.h>
__attribute__((constructor)) void static_init(void) {
if (jl_is_initialized())
return;
julia_init(JL_IMAGE_IN_MEMORY);
jl_exception_clear();
}
""")
end

cmd = addenv(`$cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1)
verbose && println("Running: $cmd")
if !success(pipeline(cmd; stdout, stderr))
println(stderr, "\nFailed to compile $file")
exit(1)
function precompile_env()
# Pre-compile the environment
# (otherwise obscure error messages will occur)
cmd = addenv(`$julia_cmd --project=$(Base.active_project()) -e "using Pkg; Pkg.precompile()"`)
verbose && println("Running: $cmd")
if !success(pipeline(cmd; stdout, stderr))
println(stderr, "\nError encountered during pre-compilation of environment.")
exit(1)
end
end

run(`cc $(cflags) -g -c -o $init_path $initsrc_path`)
function compile_products()
# Compile the Julia code
cmd = addenv(`$julia_cmd --project=$(Base.active_project()) --output-o $img_path --output-incremental=no --strip-ir --strip-metadata $julia_args $(joinpath(@__DIR__,"juliac-buildscript.jl")) $absfile $output_type $add_ccallables`, "OPENBLAS_NUM_THREADS" => 1, "JULIA_NUM_THREADS" => 1)
verbose && println("Running: $cmd")
if !success(pipeline(cmd; stdout, stderr))
println(stderr, "\nFailed to compile $file")
exit(1)
end

if output_type == "--output-lib" || output_type == "--output-sysimage"
of, ext = splitext(outname)
soext = "." * Base.BinaryPlatforms.platform_dlext()
if ext == ""
outname = of * soext
# Compile the initialization code
open(initsrc_path, "w") do io
print(io, """
#include <julia.h>
__attribute__((constructor)) void static_init(void) {
if (jl_is_initialized())
return;
julia_init(JL_IMAGE_IN_MEMORY);
jl_exception_clear();
}
""")
end
run(`cc $(cflags) -g -c -o $init_path $initsrc_path`)
end

julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal")
try
if output_type == "--output-lib"
run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`)
elseif output_type == "--output-sysimage"
run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`)
else
run(`cc $(allflags) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`)
function link_products()
global outname
if output_type == "--output-lib" || output_type == "--output-sysimage"
of, ext = splitext(outname)
soext = "." * Base.BinaryPlatforms.platform_dlext()
if ext == ""
outname = of * soext
end
end

julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal")
try
if output_type == "--output-lib"
run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`)
elseif output_type == "--output-sysimage"
run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`)
else
run(`cc $(allflags) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`)
end
catch e
println("\nCompilation failed: ", e)
exit(1)
end
catch
println("\nCompilation failed.")
exit(1)
end

precompile_env()
compile_products()
link_products()

0 comments on commit 2a9c133

Please sign in to comment.