Skip to content
This repository was archived by the owner on Mar 4, 2019. It is now read-only.

Commit d405ce4

Browse files
lucatrvViralBShah
authored andcommitted
Add Julia v0.7 support (#58)
* Update author information * Change "--auto" into "--autodeps" * Code tweaks * Add Julia v0.7 support
1 parent c1f7b20 commit d405ce4

File tree

5 files changed

+127
-60
lines changed

5 files changed

+127
-60
lines changed

.mailmap

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
2-
1+
2+
33

44
55

README.md

+17-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
# Julia AOT compiler
1+
# Static Julia Compiler
22

3-
Helper script to build libraries and executables from Julia code.
3+
Building shared libraries and executables from Julia code.
4+
5+
Run `juliac.jl -h` for help:
46

57
```
68
usage: juliac.jl [-v] [-q] [-c] [-J <file>]
@@ -10,6 +12,8 @@ usage: juliac.jl [-v] [-q] [-c] [-J <file>]
1012
[--depwarn {yes|no|error}] [-a] [-o] [-s] [-e] [-j]
1113
[--version] [-h] juliaprog [cprog] [builddir]
1214
15+
Static Julia Compiler
16+
1317
positional arguments:
1418
juliaprog Julia program to compile
1519
cprog C program to compile (required only when
@@ -40,7 +44,7 @@ optional arguments:
4044
set floating point optimizations
4145
--depwarn {yes|no|error}
4246
set syntax and method deprecation warnings
43-
-a, --auto automatically build required dependencies
47+
-a, --autodeps automatically build required dependencies
4448
-o, --object build object file
4549
-s, --shared build shared library
4650
-e, --executable build executable file
@@ -49,10 +53,10 @@ optional arguments:
4953
-h, --help show this help message and exit
5054
5155
examples:
52-
juliac.jl -vae hello.jl # verbose, auto, build executable
53-
juliac.jl -vae hello.jl myprog.c # embed into user defined C program
54-
juliac.jl -qo hello.jl # quiet, build object file only
55-
juliac.jl -vosej hello.jl # build all and sync Julia libs
56+
juliac.jl -vae hello.jl # verbose, build executable and deps
57+
juliac.jl -vae hello.jl prog.c # embed into user defined C program
58+
juliac.jl -qo hello.jl # quiet, build object file only
59+
juliac.jl -vosej hello.jl # build all and sync Julia libs
5660
```
5761

5862
### Notes
@@ -101,11 +105,16 @@ build a binary that runs the julia code.
101105

102106
Instead of a driver script, the generated system image can be embedded
103107
into a larger program following the embedding examples and relevant
104-
sections in the Julia manual. Note that the name of the generated system image (`"libhello"` for `hello.jl`) is accessible from C in the preprocessor macro `JULIAC_PROGRAM_LIBNAME`.
108+
sections in the Julia manual. Note that the name of the generated system
109+
image (`"libhello"` for `hello.jl`) is accessible from C in the
110+
preprocessor macro `JULIAC_PROGRAM_LIBNAME`.
105111

106112
With Julia 0.7, a single large binary can be created, which does not
107113
require the driver program to load the shared library. An example of
108114
that is in `program2.c`, where the image file is the binary itself.
109115

116+
For more information on static Julia compilation see:\
117+
https://juliacomputing.com/blog/2016/02/09/static-julia.html
118+
110119
For more information on embedding Julia see:\
111120
https://github.com/JuliaLang/julia/blob/master/doc/src/manual/embedding.md

juliac.jl

+104-46
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
## 1. gcc / x86_64-w64-mingw32-gcc is available and is in path
33
## 2. Package ArgParse is installed
44

5+
# TODO: remove once Julia v0.7 is released
6+
julia_v07 = VERSION > v"0.7-"
7+
58
using ArgParse
9+
julia_v07 && using Libdl
610

711
function main(args)
812

9-
s = ArgParseSettings("Julia AOT compiler" *
10-
"\n\nhelper script to build libraries and executables from Julia code",
11-
version = "$(basename(@__FILE__)) version 0.6",
13+
s = ArgParseSettings("Static Julia Compiler",
14+
version = "$(basename(@__FILE__)) version 0.7-DEV",
1215
add_version = true)
1316

1417
@add_arg_table s begin
@@ -19,7 +22,7 @@ function main(args)
1922
"cprog"
2023
arg_type = String
2124
default = nothing
22-
help = "C program to compile (required only when building an executable; if not provided a minimal standard program is used)"
25+
help = "C program to compile (required only when building an executable; if not provided a minimal driver program is used)"
2326
"builddir"
2427
arg_type = String
2528
default = "builddir"
@@ -86,7 +89,7 @@ function main(args)
8689
metavar = "{yes|no|error}"
8790
range_tester = (x -> x == "yes" || x == "no" || x == "error")
8891
help = "set syntax and method deprecation warnings"
89-
"--auto", "-a"
92+
"--autodeps", "-a"
9093
action = :store_true
9194
help = "automatically build required dependencies"
9295
"--object", "-o"
@@ -105,15 +108,16 @@ function main(args)
105108

106109
s.epilog = """
107110
examples:\n
108-
\ua0\ua0juliac.jl -vae hello.jl # verbose, auto, build executable\n
109-
\ua0\ua0juliac.jl -vae hello.jl myprog.c # embed into user defined C program\n
110-
\ua0\ua0juliac.jl -qo hello.jl # quiet, build object file only\n
111-
\ua0\ua0juliac.jl -vosej hello.jl # build all and sync Julia libs\n
111+
\ua0\ua0juliac.jl -vae hello.jl # verbose, build executable and deps\n
112+
\ua0\ua0juliac.jl -vae hello.jl prog.c # embed into user defined C program\n
113+
\ua0\ua0juliac.jl -qo hello.jl # quiet, build object file only\n
114+
\ua0\ua0juliac.jl -vosej hello.jl # build all and sync Julia libs\n
112115
"""
113116

114117
parsed_args = parse_args(args, s)
115118

116-
if !any([parsed_args["clean"], parsed_args["object"], parsed_args["shared"], parsed_args["executable"], parsed_args["julialibs"]])
119+
# TODO: in future it may be possible to broadcast dictionary indexing, see: https://discourse.julialang.org/t/accessing-multiple-values-of-a-dictionary/8648
120+
if !any(getindex.(parsed_args, ["clean", "object", "shared", "executable", "julialibs"]))
117121
parsed_args["quiet"] || println("Nothing to do, exiting\nTry \"$(basename(@__FILE__)) -h\" for more information")
118122
exit(0)
119123
end
@@ -134,7 +138,7 @@ function main(args)
134138
parsed_args["check-bounds"],
135139
parsed_args["math-mode"],
136140
parsed_args["depwarn"],
137-
parsed_args["auto"],
141+
parsed_args["autodeps"],
138142
parsed_args["object"],
139143
parsed_args["shared"],
140144
parsed_args["executable"],
@@ -145,11 +149,11 @@ end
145149
function julia_compile(julia_program, c_program=nothing, build_dir="builddir", verbose=false, quiet=false,
146150
clean=false, sysimage = nothing, compile=nothing, cpu_target=nothing, optimize=nothing,
147151
debug=nothing, inline=nothing, check_bounds=nothing, math_mode=nothing, depwarn=nothing,
148-
auto=false, object=false, shared=false, executable=true, julialibs=true)
152+
autodeps=false, object=false, shared=false, executable=true, julialibs=true)
149153

150-
verbose && quiet && (verbose = false)
154+
verbose && quiet && (quiet = false)
151155

152-
if auto
156+
if autodeps
153157
executable && (shared = true)
154158
shared && (object = true)
155159
end
@@ -193,12 +197,21 @@ function julia_compile(julia_program, c_program=nothing, build_dir="builddir", v
193197
julia_program_basename = splitext(basename(julia_program))[1]
194198
o_file = julia_program_basename * ".o"
195199
s_file = "lib" * julia_program_basename * ".$(Libdl.dlext)"
196-
e_file = julia_program_basename * (is_windows() ? ".exe" : "")
200+
if julia_v07
201+
e_file = julia_program_basename * (Sys.iswindows() ? ".exe" : "")
202+
else
203+
e_file = julia_program_basename * (is_windows() ? ".exe" : "")
204+
end
197205
tmp_dir = "tmp_v$VERSION"
198206

199207
# TODO: these should probably be emitted from julia-config also:
200-
shlibdir = is_windows() ? JULIA_HOME : abspath(JULIA_HOME, Base.LIBDIR)
201-
private_shlibdir = abspath(JULIA_HOME, Base.PRIVATE_LIBDIR)
208+
if julia_v07
209+
shlibdir = Sys.iswindows() ? Sys.BINDIR : abspath(Sys.BINDIR, Base.LIBDIR)
210+
private_shlibdir = abspath(Sys.BINDIR, Base.PRIVATE_LIBDIR)
211+
else
212+
shlibdir = is_windows() ? JULIA_HOME : abspath(JULIA_HOME, Base.LIBDIR)
213+
private_shlibdir = abspath(JULIA_HOME, Base.PRIVATE_LIBDIR)
214+
end
202215

203216
if object
204217
julia_cmd = `$(Base.julia_cmd())`
@@ -215,66 +228,111 @@ function julia_compile(julia_program, c_program=nothing, build_dir="builddir", v
215228
check_bounds == nothing || push!(julia_cmd.exec, "--check-bounds=$check_bounds")
216229
math_mode == nothing || push!(julia_cmd.exec, "--math-mode=$math_mode")
217230
depwarn == nothing || (julia_cmd.exec[5] = "--depwarn=$depwarn")
218-
is_windows() && (julia_program = replace(julia_program, "\\", "\\\\"))
219-
expr = "
220-
VERSION >= v\"0.7+\" && Base.init_load_path($(repr(JULIA_HOME))) # initialize location of site-packages
231+
if julia_v07
232+
Sys.iswindows() && (julia_program = replace(julia_program, "\\", "\\\\"))
233+
expr = "
234+
Base.init_depot_path() # initialize package depots
235+
Base.init_load_path() # initialize location of site-packages
221236
empty!(Base.LOAD_CACHE_PATH) # reset / remove any builtin paths
222237
push!(Base.LOAD_CACHE_PATH, abspath(\"$tmp_dir\")) # enable usage of precompiled files
223-
include($(repr(julia_program))) # include \"julia_program\" file
238+
include(\"$julia_program\") # include \"julia_program\" file
224239
empty!(Base.LOAD_CACHE_PATH) # reset / remove build-system-relative paths"
240+
else
241+
is_windows() && (julia_program = replace(julia_program, "\\", "\\\\"))
242+
expr = "
243+
empty!(Base.LOAD_CACHE_PATH) # reset / remove any builtin paths
244+
push!(Base.LOAD_CACHE_PATH, abspath(\"$tmp_dir\")) # enable usage of precompiled files
245+
include(\"$julia_program\") # include \"julia_program\" file
246+
empty!(Base.LOAD_CACHE_PATH) # reset / remove build-system-relative paths"
247+
end
248+
isdir(tmp_dir) || mkpath(tmp_dir)
225249
command = `$julia_cmd -e $expr`
226-
verbose && println("Build \".ji\" files:\n $command")
250+
verbose && println("Build module image files \".ji\" in subdirectory \"$tmp_dir\":\n $command")
227251
run(command)
228252
command = `$julia_cmd --output-o $(joinpath(tmp_dir, o_file)) -e $expr`
229-
verbose && println("Build object file \"$o_file\":\n $command")
253+
verbose && println("Build object file \"$o_file\" in subdirectory \"$tmp_dir\":\n $command")
230254
run(command)
231255
end
232256

233257
if shared || executable
234-
command = `$(Base.julia_cmd()) --startup-file=no $(joinpath(dirname(JULIA_HOME), "share", "julia", "julia-config.jl"))`
235-
cflags = Base.shell_split(readstring(`$command --cflags`))
236-
ldflags = Base.shell_split(readstring(`$command --ldflags`))
237-
ldlibs = Base.shell_split(readstring(`$command --ldlibs`))
238-
cc = is_windows() ? "x86_64-w64-mingw32-gcc" : "gcc"
258+
if julia_v07
259+
cc = Sys.iswindows() ? "x86_64-w64-mingw32-gcc" : "gcc"
260+
command = `$(Base.julia_cmd()) --startup-file=no $(joinpath(dirname(Sys.BINDIR), "share", "julia", "julia-config.jl"))`
261+
flags = `$(Base.shell_split(read(\`$command --allflags\`, String)))`
262+
else
263+
cc = is_windows() ? "x86_64-w64-mingw32-gcc" : "gcc"
264+
command = `$(Base.julia_cmd()) --startup-file=no $(joinpath(dirname(JULIA_HOME), "share", "julia", "julia-config.jl"))`
265+
cflags = `$(Base.shell_split(readstring(\`$command --cflags\`)))`
266+
ldflags = `$(Base.shell_split(readstring(\`$command --ldflags\`)))`
267+
ldlibs = `$(Base.shell_split(readstring(\`$command --ldlibs\`)))`
268+
flags = `$cflags $ldflags $ldlibs`
269+
end
239270
end
240271
241272
if shared
242-
command = `$cc -m64 -shared -o $s_file $(joinpath(tmp_dir, o_file)) $cflags $ldflags $ldlibs`
243-
if is_apple()
244-
command = `$command -Wl,-install_name,@rpath/lib$julia_program_basename.dylib`
245-
elseif is_windows()
246-
command = `$command -Wl,--export-all-symbols`
273+
command = `$cc -m64 -shared -o $s_file $(joinpath(tmp_dir, o_file)) $flags`
274+
if julia_v07
275+
if Sys.isapple()
276+
command = `$command -Wl,-install_name,@rpath/\"$s_file\"`
277+
elseif Sys.iswindows()
278+
command = `$command -Wl,--export-all-symbols`
279+
end
280+
else
281+
if is_apple()
282+
command = `$command -Wl,-install_name,@rpath/\"$s_file\"`
283+
elseif is_windows()
284+
command = `$command -Wl,--export-all-symbols`
285+
end
247286
end
248-
verbose && println("Build shared library \"$s_file\":\n $command")
287+
verbose && println("Build shared library \"$s_file\" in build directory:\n $command")
249288
run(command)
250289
end
251290
252291
if executable
253-
push!(cflags, "-DJULIAC_PROGRAM_LIBNAME=\"lib$julia_program_basename\"")
254-
command = `$cc -m64 -o $e_file $c_program $s_file $cflags $ldflags $ldlibs`
255-
if is_apple()
256-
command = `$command -Wl,-rpath,@executable_path`
257-
elseif is_unix()
258-
command = `$command -Wl,-rpath,\$ORIGIN`
292+
command = `$cc -m64 -DJULIAC_PROGRAM_LIBNAME=\"lib$julia_program_basename\" -o $e_file $c_program $s_file $flags`
293+
if julia_v07
294+
if Sys.isapple()
295+
command = `$command -Wl,-rpath,@executable_path`
296+
elseif Sys.isunix()
297+
command = `$command -Wl,-rpath,\$ORIGIN`
298+
end
299+
else
300+
if is_apple()
301+
command = `$command -Wl,-rpath,@executable_path`
302+
elseif is_unix()
303+
command = `$command -Wl,-rpath,\$ORIGIN`
304+
end
259305
end
260-
verbose && println("Build executable file \"$e_file\":\n $command")
306+
verbose && println("Build executable file \"$e_file\" in build directory:\n $command")
261307
run(command)
262308
end
263309
264310
if julialibs
265-
verbose && println("Sync Julia libraries:")
311+
verbose && println("Sync Julia libraries to build directory:")
266312
libfiles = String[]
267313
dlext = "." * Libdl.dlext
268314
for dir in (shlibdir, private_shlibdir)
269-
if is_windows() || is_apple()
270-
append!(libfiles, joinpath.(dir, filter(x -> endswith(x, dlext), readdir(dir))))
315+
if julia_v07
316+
if Sys.iswindows() || Sys.isapple()
317+
append!(libfiles, joinpath.(dir, filter(x -> endswith(x, dlext), readdir(dir))))
318+
else
319+
append!(libfiles, joinpath.(dir, filter(x -> contains(x, r"^lib.+\.so(?:\.\d+)*$"), readdir(dir))))
320+
end
271321
else
272-
append!(libfiles, joinpath.(dir, filter(x -> ismatch(r"^lib.+\.so(?:\.\d+)*$", x), readdir(dir))))
322+
if is_windows() || is_apple()
323+
append!(libfiles, joinpath.(dir, filter(x -> endswith(x, dlext), readdir(dir))))
324+
else
325+
append!(libfiles, joinpath.(dir, filter(x -> ismatch(r"^lib.+\.so(?:\.\d+)*$", x), readdir(dir))))
326+
end
273327
end
274328
end
275329
sync = false
276330
for src in libfiles
277-
ismatch(r"debug", src) && continue
331+
if julia_v07
332+
contains(src, r"debug") && continue
333+
else
334+
ismatch(r"debug", src) && continue
335+
end
278336
dst = basename(src)
279337
if filesize(src) != filesize(dst) || ctime(src) > ctime(dst) || mtime(src) > mtime(dst)
280338
verbose && println(" $dst")

program.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "uv.h"
99
#include "julia.h"
1010

11-
#ifdef JULIA_DEFINE_FAST_TLS // only available in Julia 0.7+
11+
#ifdef JULIA_DEFINE_FAST_TLS // only available in Julia v0.7 and above
1212
JULIA_DEFINE_FAST_TLS()
1313
#endif
1414

@@ -22,7 +22,7 @@ int main(int argc, char *argv[])
2222
// Initialize Julia
2323
uv_setup_args(argc, argv); // no-op on Windows
2424
libsupport_init();
25-
// JULIAC_PROGRAM_LIBNAME defined on command-line for compilation.
25+
// JULIAC_PROGRAM_LIBNAME defined on command-line for compilation
2626
jl_options.image_file = JULIAC_PROGRAM_LIBNAME;
2727
julia_init(JL_IMAGE_JULIA_HOME);
2828

program2.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#include "uv.h"
99
#include "julia.h"
1010

11-
#ifdef JULIA_DEFINE_FAST_TLS // only available in Julia 0.7+
11+
#ifdef JULIA_DEFINE_FAST_TLS // only available in Julia v0.7 and above
1212
JULIA_DEFINE_FAST_TLS()
1313
#endif
1414

@@ -41,7 +41,7 @@ int wmain(int argc, wchar_t *wargv[], wchar_t *envp[])
4141
// initialization
4242
libsupport_init();
4343
// jl_options.compile_enabled = JL_OPTIONS_COMPILE_OFF;
44-
// JULIAC_PROGRAM_LIBNAME defined on command-line for compilation.
44+
// JULIAC_PROGRAM_LIBNAME defined on command-line for compilation
4545
jl_options.image_file = JULIAC_PROGRAM_LIBNAME;
4646
julia_init(JL_IMAGE_JULIA_HOME);
4747

0 commit comments

Comments
 (0)