Skip to content

Commit cba19bf

Browse files
topolaritygbaraldi
andauthored
contrib: add --relative-rpath option to juliac.jl (#57199)
This flag is useful when you'd like to deploy the generated library / executable across machines. This will tell the linker to look for the required libraries (`libjulia*.so`, `libopenblas`, etc.) in an adjacent `julia/` directory. We'll eventually use PackageCompiler to help bundle all the required libraries together, but for now this at least gets the lookup setup correctly in the created `.so` / binary. --------- Co-authored-by: Gabriel Baraldi <[email protected]>
1 parent 0b9525b commit cba19bf

File tree

2 files changed

+65
-28
lines changed

2 files changed

+65
-28
lines changed

contrib/julia-config.jl

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ function includeDir()
4545
return abspath(Sys.BINDIR, Base.INCLUDEDIR, "julia")
4646
end
4747

48-
function ldflags(doframework)
49-
doframework && return "-F$(shell_escape(frameworkDir()))"
48+
function ldflags(; framework::Bool=false)
49+
framework && return "-F$(shell_escape(frameworkDir()))"
5050
fl = "-L$(shell_escape(libDir()))"
5151
if Sys.iswindows()
5252
fl = fl * " -Wl,--stack,8388608"
@@ -56,27 +56,40 @@ function ldflags(doframework)
5656
return fl
5757
end
5858

59-
function ldlibs(doframework)
59+
function ldrpath()
60+
libname = if Base.isdebugbuild()
61+
"julia-debug"
62+
else
63+
"julia"
64+
end
65+
return "-Wl,-rpath,$(shell_escape(private_libDir())) -Wl,-rpath,$(shell_escape(libDir())) -l$libname"
66+
end
67+
68+
function ldlibs(; framework::Bool=false, rpath::Bool=true)
6069
# Return "Julia" for the framework even if this is a debug build.
6170
# If the user wants the debug framework, DYLD_IMAGE_SUFFIX=_debug
6271
# should be used (refer to man 1 dyld).
63-
doframework && return "-framework $(Base.DARWIN_FRAMEWORK_NAME)"
72+
framework && return "-framework $(Base.DARWIN_FRAMEWORK_NAME)"
6473
libname = if Base.isdebugbuild()
6574
"julia-debug"
6675
else
6776
"julia"
6877
end
6978
if Sys.isunix()
70-
return "-L$(shell_escape(private_libDir())) -Wl,-rpath,$(shell_escape(libDir())) -Wl,-rpath,$(shell_escape(private_libDir())) -l$libname"
79+
if rpath
80+
return "-L$(shell_escape(private_libDir())) $(ldrpath())"
81+
else
82+
return "-L$(shell_escape(private_libDir()))"
83+
end
7184
else
7285
return "-l$libname -lopenlibm"
7386
end
7487
end
7588

76-
function cflags(doframework)
89+
function cflags(; framework::Bool=false)
7790
flags = IOBuffer()
7891
print(flags, "-std=gnu11")
79-
if doframework
92+
if framework
8093
include = shell_escape(frameworkDir())
8194
print(flags, " -F", include)
8295
else
@@ -89,8 +102,8 @@ function cflags(doframework)
89102
return String(take!(flags))
90103
end
91104

92-
function allflags(doframework)
93-
return "$(cflags(doframework)) $(ldflags(doframework)) $(ldlibs(doframework))"
105+
function allflags(; framework::Bool=false, rpath::Bool=true)
106+
return "$(cflags(; framework)) $(ldflags(; framework)) $(ldlibs(; framework, rpath))"
94107
end
95108

96109
function check_args(args)
@@ -102,31 +115,29 @@ function check_args(args)
102115
end
103116

104117
function check_framework_flag(args)
105-
doframework = "--framework" in args
106-
if doframework && !Base.DARWIN_FRAMEWORK
118+
framework = "--framework" in args
119+
if framework && !Base.DARWIN_FRAMEWORK
107120
println(stderr, "NOTICE: Ignoring --framework because Julia is not packaged as a framework.")
108121
return false
109-
elseif !doframework && Base.DARWIN_FRAMEWORK
122+
elseif !framework && Base.DARWIN_FRAMEWORK
110123
println(stderr, "NOTICE: Consider using --framework because Julia is packaged as a framework.")
111124
return false
112125
end
113-
return doframework
126+
return framework
114127
end
115128

116-
function main()
117-
check_args(ARGS)
118-
doframework = check_framework_flag(ARGS)
119-
for args in ARGS
129+
function (@main)(args)
130+
check_args(args)
131+
framework = check_framework_flag(args)
132+
for args in args
120133
if args == "--ldflags"
121-
println(ldflags(doframework))
134+
println(ldflags(; framework))
122135
elseif args == "--cflags"
123-
println(cflags(doframework))
136+
println(cflags(; framework))
124137
elseif args == "--ldlibs"
125-
println(ldlibs(doframework))
138+
println(ldlibs(; framework))
126139
elseif args == "--allflags"
127-
println(allflags(doframework))
140+
println(allflags(; framework))
128141
end
129142
end
130143
end
131-
132-
main()

contrib/juliac.jl

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
# Julia compiler wrapper script
22
# NOTE: The interface and location of this script are considered unstable/experimental
33

4+
module JuliaConfig
5+
include(joinpath(@__DIR__, "julia-config.jl"))
6+
end
7+
48
julia_cmd = `$(Base.julia_cmd()) --startup-file=no --history-file=no`
59
output_type = nothing # exe, sharedlib, sysimage
610
outname = nothing
711
file = nothing
812
add_ccallables = false
13+
relative_rpath = false
914
verbose = false
1015

1116
help = findfirst(x->x == "--help", ARGS)
@@ -15,6 +20,7 @@ if help !== nothing
1520
Usage: julia juliac.jl [--output-exe | --output-lib | --output-sysimage] <name> [options] <file.jl>
1621
--experimental --trim=<no,safe,unsafe,unsafe-warn> Only output code statically determined to be reachable
1722
--compile-ccallable Include all methods marked `@ccallable` in output
23+
--relative-rpath Configure the library / executable to lookup all required libraries in an adjacent "julia/" folder
1824
--verbose Request verbose output
1925
""")
2026
exit(0)
@@ -36,6 +42,8 @@ let i = 1
3642
global add_ccallables = true
3743
elseif arg == "--verbose"
3844
global verbose = true
45+
elseif arg == "--relative-rpath"
46+
global relative_rpath = true
3947
elseif startswith(arg, "--trim") || arg == "--experimental"
4048
# forwarded args
4149
push!(julia_args, arg)
@@ -53,11 +61,27 @@ end
5361
isnothing(outname) && error("No output file specified")
5462
isnothing(file) && error("No input file specified")
5563

64+
function get_rpath(; relative::Bool = false)
65+
if relative
66+
if Sys.isapple()
67+
return "-Wl,-rpath,'@loader_path/julia/' -Wl,-rpath,'@loader_path/'"
68+
elseif Sys.islinux()
69+
return "-Wl,-rpath,'\$ORIGIN/julia/' -Wl,-rpath,'\$ORIGIN/'"
70+
else
71+
error("unimplemented")
72+
end
73+
else
74+
return JuliaConfig.ldrpath()
75+
end
76+
end
77+
5678
absfile = abspath(file)
57-
cflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --cflags `)
79+
cflags = JuliaConfig.cflags(; framework=false)
5880
cflags = Base.shell_split(cflags)
59-
allflags = readchomp(`$(julia_cmd) $(joinpath(Sys.BINDIR, Base.DATAROOTDIR,"julia", "julia-config.jl")) --allflags`)
81+
allflags = JuliaConfig.allflags(; framework=false, rpath=false)
6082
allflags = Base.shell_split(allflags)
83+
rpath = get_rpath(; relative = relative_rpath)
84+
rpath = Base.shell_split(rpath)
6185
tmpdir = mktempdir(cleanup=false)
6286
initsrc_path = joinpath(tmpdir, "init.c")
6387
init_path = joinpath(tmpdir, "init.a")
@@ -113,12 +137,14 @@ function link_products()
113137
julia_libs = Base.shell_split(Base.isdebugbuild() ? "-ljulia-debug -ljulia-internal-debug" : "-ljulia -ljulia-internal")
114138
try
115139
if output_type == "--output-lib"
116-
run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`)
140+
cmd2 = `cc $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`
117141
elseif output_type == "--output-sysimage"
118-
run(`cc $(allflags) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`)
142+
cmd2 = `cc $(allflags) $(rpath) -o $outname -shared -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $(julia_libs)`
119143
else
120-
run(`cc $(allflags) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`)
144+
cmd2 = `cc $(allflags) $(rpath) -o $outname -Wl,$(Base.Linking.WHOLE_ARCHIVE) $img_path -Wl,$(Base.Linking.NO_WHOLE_ARCHIVE) $init_path $(julia_libs)`
121145
end
146+
verbose && println("Running: $cmd2")
147+
run(cmd2)
122148
catch e
123149
println("\nCompilation failed: ", e)
124150
exit(1)

0 commit comments

Comments
 (0)