Skip to content

Commit 6849019

Browse files
committed
Code tweaks
1 parent da6c8a6 commit 6849019

File tree

3 files changed

+103
-118
lines changed

3 files changed

+103
-118
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
*.ji
12
*.o
23
*.so
34
*.so.*

README.md

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,47 @@
1-
## Building a shared library and executable from your julia code
1+
# Julia AOT compiler
22

3-
1. Make sure all the packages and modules used by `hello.jl` are precompiled.
4-
The `juliac.jl` script uses the `ArgParse` package, make sure it is installed as well.
3+
Helper script to build libraries and executables from Julia code.
54

6-
2. Clone this repo and use the `juliac.jl` script. The way to call it is as follows:
5+
```
6+
usage: juliac.jl [-v] [-q] [-c] [-o] [-s] [-e] [-j] [--version] [-h]
7+
juliaprog [cprog] [builddir]
8+
9+
positional arguments:
10+
juliaprog Julia program to compile
11+
cprog C program to compile (if not provided, a minimal
12+
standard program is used)
13+
builddir build directory, either absolute or relative to
14+
the Julia program directory (default: "builddir")
715
8-
Usage: `juliac.jl [-v] [-q] [-o] [-s] [-e] [-j] [-h] juliaprog [cprog] [builddir]`
16+
optional arguments:
17+
-v, --verbose increase verbosity
18+
-q, --quiet suppress non-error messages
19+
-c, --clean delete builddir
20+
-o, --object build object file
21+
-s, --shared build shared library
22+
-e, --executable build executable file
23+
-j, --julialibs sync Julia libraries to builddir
24+
--version show version information and exit
25+
-h, --help show this help message and exit
26+
27+
examples:
28+
juliac.jl -ve hello.jl # verbose, build executable
29+
juliac.jl -ve hello.jl myprog.c # embed into user defined C program
30+
juliac.jl -qo hello.jl # quiet, build object file
31+
juliac.jl -vosej hello.jl # build all and sync Julia libs
32+
```
933

10-
Examples:
11-
```
12-
julia juliac.jl -ve hello.jl # verbose, create an executable
13-
julia juliac.jl -ve hello.jl myprogram.c # embed into a user defined c program
14-
julia juliac.jl --quiet --object hello.jl # builds just the `hello.o` object file
15-
julia juliac.jl -vosej hello.jl buildtest # build object, shared lib, exec, and sync julia libs
16-
julia juliac.jl -h # print help message
17-
```
34+
### Notes
1835

19-
Note: `hello.jl` does not need to be in the `static-julia` directory.
36+
1. The `juliac.jl` script uses the `ArgParse` package, make sure it is installed.
2037

21-
3. A shared library containing the system image `libhello.so`, and a
38+
3. On Windows install `Cygwin` and the `mingw64-x86_64-gcc-core` package, see:\
39+
https://github.com/JuliaLang/julia/blob/master/README.windows.md
40+
41+
2. A shared library containing the system image `libhello.so`, and a
2242
driver binary `hello` are created in the `builddir` directory.
43+
Running `hello` produces the following output:
44+
2345
```
2446
$ ./hello
2547
hello, world
@@ -62,4 +84,3 @@ sections in the Julia manual.
6284
With Julia 0.7, a single large binary can be created, which does not
6385
require the driver program to load the shared library. An example of
6486
that is in `program2.c`, where the image file is the binary itself.
65-

juliac.jl

Lines changed: 65 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -6,50 +6,59 @@ using ArgParse
66

77
function main(args)
88

9-
s = ArgParseSettings("Static AOT Julia compilation.")
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",
12+
add_version = true)
1013

1114
@add_arg_table s begin
1215
"juliaprog"
13-
help = "julia program to compile"
1416
arg_type = String
1517
required = true
18+
help = "Julia program to compile"
1619
"cprog"
17-
help = "c program to compile (if not provided, a minimal standard program is used)"
1820
arg_type = String
1921
default = nothing
22+
help = "C program to compile (if not provided, a minimal standard program is used)"
2023
"builddir"
21-
help = "build directory, either absolute or relative to the julia program directory"
2224
arg_type = String
2325
default = "builddir"
26+
help = "build directory, either absolute or relative to the Julia program directory"
2427
"--verbose", "-v"
25-
help = "increase verbosity"
2628
action = :store_true
29+
help = "increase verbosity"
2730
"--quiet", "-q"
31+
action = :store_true
2832
help = "suppress non-error messages"
33+
"--clean", "-c"
2934
action = :store_true
35+
help = "delete builddir"
3036
"--object", "-o"
31-
help = "build object file"
3237
action = :store_true
38+
help = "build object file"
3339
"--shared", "-s"
34-
help = "build shared library"
3540
action = :store_true
41+
help = "build shared library"
3642
"--executable", "-e"
37-
help = "build executable file"
3843
action = :store_true
44+
help = "build executable file"
3945
"--julialibs", "-j"
40-
help = "sync julia libraries to builddir"
41-
action = :store_true
42-
"--clean", "-c"
43-
help = "delete builddir"
4446
action = :store_true
47+
help = "sync Julia libraries to builddir"
4548
end
4649

50+
s.epilog = """
51+
examples:\n
52+
\ua0\ua0juliac.jl -ve hello.jl # verbose, build executable\n
53+
\ua0\ua0juliac.jl -ve hello.jl myprog.c # embed into user defined C program\n
54+
\ua0\ua0juliac.jl -qo hello.jl # quiet, build object file\n
55+
\ua0\ua0juliac.jl -vosej hello.jl # build all and sync Julia libs\n
56+
"""
57+
4758
parsed_args = parse_args(args, s)
4859

49-
if !any([parsed_args["object"], parsed_args["shared"], parsed_args["executable"], parsed_args["julialibs"], parsed_args["clean"]])
50-
if !parsed_args["quiet"]
51-
println("Nothing to do, exiting\nTry \"$(basename(@__FILE__)) -h\" for more information")
52-
end
60+
if !any([parsed_args["clean"], parsed_args["object"], parsed_args["shared"], parsed_args["executable"], parsed_args["julialibs"]])
61+
parsed_args["quiet"] || println("Nothing to do, exiting\nTry \"$(basename(@__FILE__)) -h\" for more information")
5362
exit(0)
5463
end
5564

@@ -59,77 +68,51 @@ function main(args)
5968
parsed_args["builddir"],
6069
parsed_args["verbose"],
6170
parsed_args["quiet"],
71+
parsed_args["clean"],
6272
parsed_args["object"],
6373
parsed_args["shared"],
6474
parsed_args["executable"],
65-
parsed_args["julialibs"],
66-
parsed_args["clean"]
75+
parsed_args["julialibs"]
6776
)
6877
end
6978

7079
function julia_compile(julia_program, c_program=nothing, build_dir="builddir", verbose=false, quiet=false,
71-
object=false, shared=false, executable=true, julialibs=true, clean=false)
80+
clean=false, object=false, shared=false, executable=true, julialibs=true)
7281

73-
if verbose && quiet
74-
verbose = false
75-
end
82+
verbose && quiet && (verbose = false)
7683

7784
julia_program = abspath(julia_program)
78-
if !isfile(julia_program)
79-
error("Cannot find file:\n\"$julia_program\"")
80-
end
81-
if !quiet
82-
println("Julia program file:\n\"$julia_program\"")
83-
end
85+
isfile(julia_program) || error("Cannot find file:\n \"$julia_program\"")
86+
quiet || println("Julia program file:\n \"$julia_program\"")
8487

85-
if c_program == nothing
86-
c_program = joinpath(@__DIR__, "program.c")
87-
else
88-
c_program = abspath(c_program)
89-
end
90-
if !isfile(c_program)
91-
error("Cannot find file:\n\"$c_program\"")
92-
end
93-
if !quiet
94-
println("C program file:\n\"$c_program\"")
95-
end
88+
c_program = c_program == nothing ? joinpath(@__DIR__, "program.c") : abspath(c_program)
89+
isfile(c_program) || error("Cannot find file:\n \"$c_program\"")
90+
quiet || println("C program file:\n \"$c_program\"")
9691

9792
cd(dirname(julia_program))
9893

9994
build_dir = abspath(build_dir)
100-
if !quiet
101-
println("Build directory:\n\"$build_dir\"")
102-
end
95+
quiet || println("Build directory:\n \"$build_dir\"")
10396

10497
if clean
105-
if !isdir(build_dir)
106-
if verbose
107-
println("Build directory does not exist")
108-
end
109-
else
110-
if verbose
111-
println("Delete build directory")
112-
end
98+
if isdir(build_dir)
99+
verbose && println("Delete build directory")
113100
rm(build_dir, recursive=true)
101+
else
102+
verbose && println("Build directory does not exist, nothing to delete")
114103
end
115-
return
116104
end
117105

118106
if !isdir(build_dir)
119-
if verbose
120-
println("Make build directory")
121-
end
107+
verbose && println("Make build directory")
122108
mkpath(build_dir)
123109
end
110+
124111
if pwd() != build_dir
125-
if verbose
126-
println("Change to build directory")
127-
end
112+
verbose && println("Change to build directory")
128113
cd(build_dir)
129114
else
130-
if verbose
131-
println("Already in build directory")
132-
end
115+
verbose && println("Already in build directory")
133116
end
134117

135118
file_name = splitext(basename(julia_program))[1]
@@ -138,32 +121,26 @@ function julia_compile(julia_program, c_program=nothing, build_dir="builddir", v
138121
e_file = file_name * (is_windows() ? ".exe" : "")
139122

140123
# TODO: these should probably be emitted from julia-config also:
141-
julia_pkglibdir = joinpath(dirname(Pkg.dir()), "lib", basename(Pkg.dir()))
142124
shlibdir = is_windows() ? JULIA_HOME : abspath(JULIA_HOME, Base.LIBDIR)
143125
private_shlibdir = abspath(JULIA_HOME, Base.PRIVATE_LIBDIR)
144126

145-
if is_windows()
146-
julia_program = replace(julia_program, "\\", "\\\\")
147-
julia_pkglibdir = replace(julia_pkglibdir, "\\", "\\\\")
148-
end
149-
150127
delete_object = false
151128
if object || shared || executable
152-
command = `$(Base.julia_cmd()) --startup-file=no -e "
153-
VERSION >= v\"0.7+\" && Base.init_load_path($(repr(JULIA_HOME))) # initialize location of site-packages
154-
empty!(Base.LOAD_CACHE_PATH) # reset / remove any builtin paths
155-
push!(Base.LOAD_CACHE_PATH, abspath(\"ji$VERSION\")) #$(repr(julia_pkglibdir))) # enable usage of precompile files
156-
include($(repr(julia_program)))
157-
empty!(Base.LOAD_CACHE_PATH) # reset / remove build-system-relative paths
158-
"`
159-
if verbose
160-
println("Build object file \"$o_file\":\n$command")
161-
end
162-
run(command) # first populate the .ji cache (when JULIA_HOME is defined)
163-
run(`$command --output-o $o_file`) # then output the combined file
164-
if !object
165-
delete_object = true
166-
end
129+
julia_cmd = `$(Base.julia_cmd()) --startup-file=no`
130+
is_windows() && (julia_program = replace(julia_program, "\\", "\\\\"))
131+
expr = "
132+
VERSION >= v\"0.7+\" && Base.init_load_path($(repr(JULIA_HOME))) # initialize location of site-packages
133+
empty!(Base.LOAD_CACHE_PATH) # reset / remove any builtin paths
134+
push!(Base.LOAD_CACHE_PATH, abspath(\"cache_ji_v$VERSION\")) # enable usage of precompiled files
135+
include($(repr(julia_program))) # include \"julia_program\" file
136+
empty!(Base.LOAD_CACHE_PATH) # reset / remove build-system-relative paths"
137+
command = `$julia_cmd -e $expr`
138+
verbose && println("Populate \".ji\" local cache:\n $command")
139+
run(command)
140+
command = `$julia_cmd --output-o $o_file -e $expr`
141+
verbose && println("Build object file \"$o_file\":\n $command")
142+
run(command)
143+
object || (delete_object = true)
167144
end
168145

169146
if shared || executable
@@ -181,9 +158,7 @@ function julia_compile(julia_program, c_program=nothing, build_dir="builddir", v
181158
elseif is_windows()
182159
command = `$command -Wl,--export-all-symbols`
183160
end
184-
if verbose
185-
println("Build shared library \"$s_file\":\n$command")
186-
end
161+
verbose && println("Build shared library \"$s_file\":\n $command")
187162
run(command)
188163
end
189164

@@ -194,23 +169,17 @@ function julia_compile(julia_program, c_program=nothing, build_dir="builddir", v
194169
elseif is_unix()
195170
command = `$command -Wl,-rpath,\$ORIGIN`
196171
end
197-
if verbose
198-
println("Build executable file \"$e_file\":\n$command")
199-
end
172+
verbose && println("Build executable file \"$e_file\":\n $command")
200173
run(command)
201174
end
202175

203176
if delete_object && isfile(o_file)
204-
if verbose
205-
println("Delete object file \"$o_file\"")
206-
end
177+
verbose && println("Delete object file \"$o_file\"")
207178
rm(o_file)
208179
end
209180

210181
if julialibs
211-
if verbose
212-
println("Sync Julia libraries:")
213-
end
182+
verbose && println("Sync Julia libraries:")
214183
libfiles = String[]
215184
dlext = "." * Libdl.dlext
216185
for dir in (shlibdir, private_shlibdir)
@@ -222,21 +191,15 @@ function julia_compile(julia_program, c_program=nothing, build_dir="builddir", v
222191
end
223192
sync = false
224193
for src in libfiles
225-
if ismatch(r"debug", src)
226-
continue
227-
end
194+
ismatch(r"debug", src) && continue
228195
dst = basename(src)
229196
if filesize(src) != filesize(dst) || ctime(src) > ctime(dst) || mtime(src) > mtime(dst)
230-
if verbose
231-
println(" $dst")
232-
end
197+
verbose && println(" $dst")
233198
cp(src, dst, remove_destination=true, follow_symlinks=false)
234199
sync = true
235200
end
236201
end
237-
if verbose && !sync
238-
println(" none")
239-
end
202+
sync || verbose && println(" none")
240203
end
241204
end
242205

0 commit comments

Comments
 (0)