-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
/
Copy pathbuild_sysimg.jl
198 lines (174 loc) · 8.45 KB
/
build_sysimg.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
#!/usr/bin/env julia
# This file is a part of Julia. License is MIT: http://julialang.org/license
# Build a system image binary at sysimg_path.dlext. Allow insertion of a userimg via
# userimg_path. If sysimg_path.dlext is currently loaded into memory, don't continue
# unless force is set to true. Allow targeting of a CPU architecture via cpu_target
function default_sysimg_path(debug=false)
if is_unix()
splitext(Libdl.dlpath(debug ? "sys-debug" : "sys"))[1]
else
joinpath(JULIA_HOME, "..", "lib", "julia", debug ? "sys-debug" : "sys")
end
end
"""
build_sysimg(sysimg_path=default_sysimg_path, cpu_target="native", userimg_path=nothing; force=false)
Rebuild the system image. Store it in `sysimg_path`, which defaults to a file named `sys.ji`
that sits in the same folder as `libjulia.{so,dylib}`, except on Windows where it defaults
to `JULIA_HOME/../lib/julia/sys.ji`. Use the cpu instruction set given by `cpu_target`.
Valid CPU targets are the same as for the `-C` option to `julia`, or the `-march` option to
`gcc`. Defaults to `native`, which means to use all CPU instructions available on the
current processor. Include the user image file given by `userimg_path`, which should contain
directives such as `using MyPackage` to include that package in the new system image. New
system image will not replace an older image unless `force` is set to true.
"""
function build_sysimg(sysimg_path=nothing, cpu_target="native", userimg_path=nothing; force=false, debug=false)
if sysimg_path === nothing
sysimg_path = default_sysimg_path(debug)
end
# Quit out if a sysimg is already loaded and is in the same spot as sysimg_path, unless forcing
sysimg = Libdl.dlopen_e("sys")
if sysimg != C_NULL
if !force && Base.samefile(Libdl.dlpath(sysimg), "$(sysimg_path).$(Libdl.dlext)")
info("System image already loaded at $(Libdl.dlpath(sysimg)), set force to override")
return
end
end
# Canonicalize userimg_path before we enter the base_dir
if userimg_path !== nothing
userimg_path = abspath(userimg_path)
end
# Enter base/ and setup some useful paths
base_dir = dirname(Base.find_source_file("sysimg.jl"))
cd(base_dir) do
julia = joinpath(JULIA_HOME, debug ? "julia-debug" : "julia")
cc = find_system_compiler()
# Ensure we have write-permissions to wherever we're trying to write to
try
touch("$sysimg_path.ji")
catch
err_msg = "Unable to modify $sysimg_path.ji, ensure parent directory exists "
err_msg *= "and is writable. Absolute paths work best.)"
error( err_msg )
end
# Copy in userimg.jl if it exists
if userimg_path !== nothing
if !isfile(userimg_path)
error("$userimg_path is not found, ensure it is an absolute path!")
end
if isfile("userimg.jl")
error("$base_dir/userimg.jl already exists, delete manually to continue.")
end
cp(userimg_path, "userimg.jl")
end
try
# Start by building inference0.{ji,o}
inference0_path = joinpath(dirname(sysimg_path), "inference0")
info("Building inference0.o...")
println("$julia -C $cpu_target --output-ji $inference0_path.ji --output-o $inference0_path.o coreimg.jl")
run(`$julia -C $cpu_target --output-ji $inference0_path.ji --output-o $inference0_path.o coreimg.jl`)
# Bootstrap off off that to create inference.{ji,o}
inference_path = joinpath(dirname(sysimg_path), "inference")
info("Building inference.o...")
println("$julia -C $cpu_target --output-ji $inference_path.ji --output-o $inference_path.o coreimg.jl")
run(`$julia -C $cpu_target --output-ji $inference_path.ji --output-o $inference_path.o coreimg.jl`)
# Bootstrap off off that to create sys.{ji,o}
info("Building sys.o...")
println("$julia -C $cpu_target --output-ji $sysimg_path.ji --output-o $sysimg_path.o -J $inference_path.ji --startup-file=no sysimg.jl")
run(`$julia -C $cpu_target --output-ji $sysimg_path.ji --output-o $sysimg_path.o -J $inference_path.ji --startup-file=no sysimg.jl`)
if cc !== nothing
link_sysimg(sysimg_path, cc, debug)
else
info("System image successfully built at $sysimg_path.ji")
end
if !Base.samefile("$(default_sysimg_path(debug)).ji", "$sysimg_path.ji")
if Base.isfile("$sysimg_path.$(Libdl.dlext)")
info("To run Julia with this image loaded, run: julia -J $sysimg_path.$(Libdl.dlext)")
else
info("To run Julia with this image loaded, run: julia -J $sysimg_path.ji")
end
else
info("Julia will automatically load this system image at next startup")
end
finally
# Cleanup userimg.jl
if userimg_path !== nothing && isfile("userimg.jl")
rm("userimg.jl")
end
end
end
end
# Search for a compiler to link sys.o into sys.dl_ext. Honor LD environment variable.
function find_system_compiler()
if haskey( ENV, "CC" )
if !success(`$(ENV["CC"]) -v`)
warn("Using compiler override $(ENV["CC"]), but unable to run `$(ENV["CC"]) -v`")
end
return ENV["CC"]
end
# On Windows, check to see if WinRPM is installed, and if so, see if gcc is installed
if is_windows()
try
eval(Main, :(using WinRPM))
winrpmgcc = joinpath(WinRPM.installdir,"usr","$(Sys.ARCH)-w64-mingw32",
"sys-root","mingw","bin","gcc.exe")
if success(`$winrpmgcc --version`)
return winrpmgcc
else
throw()
end
catch
warn("Install GCC via `Pkg.add(\"WinRPM\"); WinRPM.install(\"gcc\")` to generate sys.dll for faster startup times")
end
end
# See if `cc` exists
try
if success(`cc -v`)
return "cc"
end
end
warn( "No supported compiler found; startup times will be longer" )
end
# Link sys.o into sys.$(dlext)
function link_sysimg(sysimg_path=nothing, cc=find_system_compiler(), debug=false)
if sysimg_path === nothing
sysimg_path = default_sysimg_path(debug)
end
julia_libdir = dirname(Libdl.dlpath(debug ? "libjulia-debug" : "libjulia"))
FLAGS = ["-L$julia_libdir"]
push!(FLAGS, "-shared")
push!(FLAGS, debug ? "-ljulia-debug" : "-ljulia")
if is_windows()
push!(FLAGS, "-lssp")
end
info("Linking sys.$(Libdl.dlext)")
run(`$cc $FLAGS -o $sysimg_path.$(Libdl.dlext) $sysimg_path.o`)
info("System image successfully built at $sysimg_path.$(Libdl.dlext)")
end
# When running this file as a script, try to do so with default values. If arguments are passed
# in, use them as the arguments to build_sysimg above
#
# Also check whether we are running `genstdlib.jl`, in which case we don't want to build a
# system image and instead only need `build_sysimg`'s docstring to be available.
if !isdefined(Main, :GenStdLib) && !isinteractive()
if length(ARGS) > 5 || ("--help" in ARGS || "-h" in ARGS)
println("Usage: build_sysimg.jl <sysimg_path> <cpu_target> <usrimg_path.jl> [--force] [--debug] [--help]")
println(" <sysimg_path> is an absolute, extensionless path to store the system image at")
println(" <cpu_target> is an LLVM cpu target to build the system image against")
println(" <usrimg_path.jl> is the path to a user image to be baked into the system image")
println(" --debug Using julia-debug instead of julia to build the system image")
println(" --force Set if you wish to overwrite the default system image")
println(" --help Print out this help text and exit")
println()
println(" Example:")
println(" build_sysimg.jl /usr/local/lib/julia/sys core2 ~/my_usrimg.jl --force")
println()
println(" Running this script with no arguments is equivalent to:")
println(" build_sysimg.jl $(default_sysimg_path()) native")
return 0
end
debug_flag = "--debug" in ARGS
filter!(x -> x != "--debug", ARGS)
force_flag = "--force" in ARGS
filter!(x -> x != "--force", ARGS)
build_sysimg(ARGS...; force=force_flag, debug=debug_flag)
end