forked from JuliaLang/julia
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build_sysimg.jl
209 lines (186 loc) · 8.93 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
199
200
201
202
203
204
205
206
207
208
209
#!/usr/bin/env julia
# This file is a part of Julia. License is MIT: https://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 Sys.isunix()
splitext(Libdl.dlpath(debug ? "sys-debug" : "sys"))[1]
else
joinpath(dirname(Sys.BINDIR), "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 `Sys.BINDIR/../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=true to override.")
return nothing
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(Sys.BINDIR, debug ? "julia-debug" : "julia")
cc, warn_msg = 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("$(joinpath(base_dir, "userimg.jl")) already exists, delete manually to continue.")
end
cp(userimg_path, "userimg.jl")
end
try
# Start by building basecompiler.{ji,o}
basecompiler_path = joinpath(dirname(sysimg_path), "basecompiler")
info("Building basecompiler.o")
info("$julia -C $cpu_target --output-ji $basecompiler_path.ji --output-o $basecompiler_path.o compiler/compiler.jl")
run(`$julia -C $cpu_target --output-ji $basecompiler_path.ji --output-o $basecompiler_path.o compiler/compiler.jl`)
# Bootstrap off of that to create sys.{ji,o}
info("Building sys.o")
info("$julia -C $cpu_target --output-ji $sysimg_path.ji --output-o $sysimg_path.o -J $basecompiler_path.ji --startup-file=no sysimg.jl")
run(`$julia -C $cpu_target --output-ji $sysimg_path.ji --output-o $sysimg_path.o -J $basecompiler_path.ji --startup-file=no sysimg.jl`)
if cc !== nothing
link_sysimg(sysimg_path, cc, debug)
!isempty(warn_msg) && foreach(warn, warn_msg)
else
!isempty(warn_msg) && foreach(warn, warn_msg)
info("System image successfully built at $sysimg_path.ji.")
end
if !Base.samefile("$(default_sysimg_path(debug)).ji", "$sysimg_path.ji")
if 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()
cc = nothing
warn_msg = String[] # save warning messages into an array
# On Windows, check to see if WinRPM is installed, and if so, see if gcc is installed
if Sys.iswindows()
try
eval(Main, :(using WinRPM))
winrpmgcc = joinpath(WinRPM.installdir, "usr", "$(Sys.ARCH)-w64-mingw32",
"sys-root", "mingw", "bin", "gcc.exe")
if success(`$winrpmgcc --version`)
cc = winrpmgcc
else
throw()
end
catch
push!(warn_msg, "Install GCC via `Pkg.add(\"WinRPM\"); WinRPM.install(\"gcc\")` to generate sys.dll for faster startup times.")
end
end
if haskey(ENV, "CC")
if !success(`$(ENV["CC"]) -v`)
push!(warn_msg, "Using compiler override $(ENV["CC"]), but unable to run `$(ENV["CC"]) -v`.")
end
cc = ENV["CC"]
end
# See if `cc` exists
try
if success(`cc -v`)
cc = "cc"
end
end
if cc === nothing
push!(warn_msg, "No supported compiler found; startup times will be longer.")
end
return cc, warn_msg
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 Sys.iswindows()
push!(FLAGS, "-lssp")
end
sysimg_file = "$sysimg_path.$(Libdl.dlext)"
info("Linking sys.$(Libdl.dlext)")
info("$cc $(join(FLAGS, ' ')) -o $sysimg_file $sysimg_path.o")
# Windows has difficulties overwriting a file in use so we first link to a temp file
if Sys.iswindows() && isfile(sysimg_file)
if success(pipeline(`$cc $FLAGS -o $sysimg_path.tmp $sysimg_path.o`; stdout=STDOUT, stderr=STDERR))
mv(sysimg_file, "$sysimg_file.old"; remove_destination=true)
mv("$sysimg_path.tmp", sysimg_file; remove_destination=true)
end
else
run(`$cc $FLAGS -o $sysimg_file $sysimg_path.o`)
end
info("System image successfully built at $sysimg_path.$(Libdl.dlext)")
return
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