Skip to content

Commit e672f35

Browse files
adaption to Windows (#151)
* adaption to windows: use clang to generate executable, skip GPUCompiler * a number of simplifications and bugfixes --------- Co-authored-by: C. Brenhin Keller <[email protected]>
1 parent 1e6116b commit e672f35

File tree

4 files changed

+59
-25
lines changed

4 files changed

+59
-25
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ jobs:
2020
version:
2121
- '1.8'
2222
- '1.9'
23-
- '1.10.0-rc1'
23+
- '1.10'
2424
os:
2525
- ubuntu-latest
2626
- macOS-latest

Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "StaticCompiler"
22
uuid = "81625895-6c0f-48fc-b932-11a18313743c"
33
authors = ["Tom Short and contributors"]
4-
version = "0.7.0"
4+
version = "0.7.1"
55

66

77
[deps]

src/StaticCompiler.jl

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ compile_executable(f::Function, types::Tuple, path::String, [name::String=string
3535
cflags=``, # Specify libraries you would like to link against, and other compiler options here
3636
also_expose=[],
3737
target::StaticTarget=StaticTarget(),
38+
llvm_to_clang = Sys.iswindows(),
3839
method_table=StaticCompiler.method_table,
3940
kwargs...
4041
)
@@ -98,17 +99,18 @@ shell> ./hello
9899
Hello, world!
99100
```
100101
"""
101-
function compile_executable(f::Function, types=(), path::String="./", name=fix_name(f);
102+
function compile_executable(f::Function, types=(), path::String=pwd(), name=fix_name(f);
102103
also_expose=Tuple{Function, Tuple{DataType}}[], target::StaticTarget=StaticTarget(),
103104
kwargs...)
104105
compile_executable(vcat([(f, types)], also_expose), path, name; target, kwargs...)
105106
end
106107

107-
function compile_executable(funcs::Union{Array,Tuple}, path::String="./", name=fix_name(first(first(funcs)));
108+
function compile_executable(funcs::Union{Array,Tuple}, path::String=pwd(), name=fix_name(first(first(funcs)));
108109
filename = name,
109110
demangle = true,
110111
cflags = ``,
111112
target::StaticTarget=StaticTarget(),
113+
llvm_to_clang = Sys.iswindows(),
112114
kwargs...
113115
)
114116

@@ -122,20 +124,20 @@ function compile_executable(funcs::Union{Array,Tuple}, path::String="./", name=f
122124
nativetype = isprimitivetype(rt) || isa(rt, Ptr)
123125
nativetype || @warn "Return type `$rt` of `$f$types` does not appear to be a native type. Consider returning only a single value of a native machine type (i.e., a single float, int/uint, bool, or pointer). \n\nIgnoring this warning may result in Undefined Behavior!"
124126

125-
generate_executable(funcs, path, name, filename; demangle, cflags, target, kwargs...)
127+
generate_executable(funcs, path, name, filename; demangle, cflags, target, llvm_to_clang, kwargs...)
126128
joinpath(abspath(path), filename)
127129
end
128130

129131
"""
130132
```julia
131-
compile_shlib(f::Function, types::Tuple, [path::String="./"], [name::String=string(nameof(f))];
133+
compile_shlib(f::Function, types::Tuple, [path::String=pwd()], [name::String=string(nameof(f))];
132134
filename::String=name,
133135
cflags=``,
134136
method_table=StaticCompiler.method_table,
135137
target::StaticTarget=StaticTarget(),
136138
kwargs...)
137139
138-
compile_shlib(funcs::Array, [path::String="./"];
140+
compile_shlib(funcs::Array, [path::String=pwd()];
139141
filename="libfoo",
140142
demangle=true,
141143
cflags=``,
@@ -172,15 +174,15 @@ julia> ccall(("test", "test.dylib"), Float64, (Int64,), 100_000)
172174
5.2564961094956075
173175
```
174176
"""
175-
function compile_shlib(f::Function, types=(), path::String="./", name=fix_name(f);
177+
function compile_shlib(f::Function, types=(), path::String=pwd(), name=fix_name(f);
176178
filename=name,
177179
target::StaticTarget=StaticTarget(),
178180
kwargs...
179181
)
180182
compile_shlib(((f, types),), path; filename, target, kwargs...)
181183
end
182184
# As above, but taking an array of functions and returning a single shlib
183-
function compile_shlib(funcs::Union{Array,Tuple}, path::String="./";
185+
function compile_shlib(funcs::Union{Array,Tuple}, path::String=pwd();
184186
filename = "libfoo",
185187
demangle = true,
186188
cflags = ``,
@@ -289,10 +291,11 @@ function generate_executable(funcs::Union{Array,Tuple}, path=tempname(), name=fi
289291
demangle = true,
290292
cflags = ``,
291293
target::StaticTarget=StaticTarget(),
294+
llvm_to_clang::Bool = Sys.iswindows(),
292295
kwargs...
293296
)
294297
exec_path = joinpath(path, filename)
295-
_, obj_path = generate_obj(funcs, path, filename; demangle, target, kwargs...)
298+
_, obj_or_ir_path = generate_obj(funcs, path, filename; demangle, target, emit_llvm_only=llvm_to_clang, kwargs...)
296299
# Pick a compiler
297300
if !isnothing(target.compiler)
298301
cc = `$(target.compiler)`
@@ -301,10 +304,10 @@ function generate_executable(funcs::Union{Array,Tuple}, path=tempname(), name=fi
301304
end
302305

303306
# Compile!
304-
if Sys.isapple()
307+
if Sys.isapple() && !llvm_to_clang
305308
# Apple no longer uses _start, so we can just specify a custom entry
306309
entry = demangle ? "_$name" : "_julia_$name"
307-
run(`$cc -e $entry $cflags $obj_path -o $exec_path`)
310+
run(`$cc -e $entry $cflags $obj_or_ir_path -o $exec_path`)
308311
else
309312
fn = demangle ? "$name" : "julia_$name"
310313
# Write a minimal wrapper to avoid having to specify a custom entry
@@ -319,9 +322,22 @@ function generate_executable(funcs::Union{Array,Tuple}, path=tempname(), name=fi
319322
return 0;
320323
}""")
321324
close(f)
322-
run(`$cc $wrapper_path $cflags $obj_path -o $exec_path`)
325+
if llvm_to_clang # (required on Windows)
326+
# Use clang (llc) to generate an executable from the LLVM IR
327+
cclang = if Sys.iswindows()
328+
`cmd \c clang` # Not clear if the `cmd \c` is necessary
329+
elseif Sys.isapple()
330+
`clang`
331+
else
332+
clang()
333+
end
334+
run(`$cclang -Wno-override-module $wrapper_path $obj_or_ir_path -o $exec_path`)
335+
else
336+
run(`$cc $wrapper_path $cflags $obj_or_ir_path -o $exec_path`)
337+
end
338+
323339
# Clean up
324-
run(`rm $wrapper_path`)
340+
rm(wrapper_path)
325341
end
326342
path, name
327343
end
@@ -482,7 +498,6 @@ generate_obj(f, tt, path::String = tempname(), filenamebase::String="obj";
482498
demangle = true,
483499
strip_llvm = false,
484500
strip_asm = true,
485-
opt_level = 3,
486501
kwargs...)
487502
```
488503
Low level interface for compiling object code (`.o`) for for function `f` given
@@ -519,10 +534,10 @@ end
519534
```julia
520535
generate_obj(funcs::Union{Array,Tuple}, path::String = tempname(), filenamebase::String="obj";
521536
target::StaticTarget=StaticTarget(),
522-
demangle =false,
537+
demangle = false,
538+
emit_llvm_only = false,
523539
strip_llvm = false,
524540
strip_asm = true,
525-
opt_level=3,
526541
kwargs...)
527542
```
528543
Low level interface for compiling object code (`.o`) for an array of Tuples
@@ -534,25 +549,34 @@ This is a struct of the type StaticTarget()
534549
The defaults compile to the native target.
535550
"""
536551
function generate_obj(funcs::Union{Array,Tuple}, path::String = tempname(), filenamebase::String="obj";
552+
target::StaticTarget=StaticTarget(),
537553
demangle = true,
554+
emit_llvm_only = false,
538555
strip_llvm = false,
539556
strip_asm = true,
540-
opt_level = 3,
541-
target::StaticTarget=StaticTarget(),
542557
kwargs...)
543558
f, tt = funcs[1]
544559
mkpath(path)
545-
obj_path = joinpath(path, "$filenamebase.o")
546560
mod = static_llvm_module(funcs; demangle, kwargs...)
547-
obj = GPUCompiler.JuliaContext() do ctx
561+
562+
if emit_llvm_only # (Required on Windows)
563+
ir_path = joinpath(path, "$filenamebase.ll")
564+
open(ir_path, "w") do io
565+
write(io, string(mod))
566+
end
567+
return path, ir_path
568+
else
569+
obj_path = joinpath(path, "$filenamebase.o")
570+
obj = GPUCompiler.JuliaContext() do ctx
548571
fakejob, _ = static_job(f, tt; target, kwargs...)
549572
obj, _ = GPUCompiler.emit_asm(fakejob, mod; strip=strip_asm, validate=false, format=LLVM.API.LLVMObjectFile)
550573
obj
574+
end
575+
open(obj_path, "w") do io
576+
write(io, obj)
577+
end
578+
return path, obj_path
551579
end
552-
open(obj_path, "w") do io
553-
write(io, obj)
554-
end
555-
path, obj_path
556580
end
557581

558582
end # module

test/testcore.jl

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,11 @@ end
5050
@test isa(r, Base.Process)
5151
@test r.exitcode == 0
5252

53+
filepath = compile_executable(foo, (), workdir, llvm_to_clang=true)
54+
r = run(`$filepath`);
55+
@test isa(r, Base.Process)
56+
@test r.exitcode == 0
57+
5358

5459
@inline function _puts(s::Ptr{UInt8}) # Can't use Base.println because it allocates
5560
Base.llvmcall(("""
@@ -85,6 +90,11 @@ end
8590
@test isa(r, Base.Process)
8691
@test r.exitcode == 0
8792

93+
filepath = compile_executable(print_args, (Int, Ptr{Ptr{UInt8}}), workdir, llvm_to_clang=true)
94+
r = run(`$filepath Hello, world!`);
95+
@test isa(r, Base.Process)
96+
@test r.exitcode == 0
97+
8898

8999
# Compile a function that definitely fails
90100
@inline foo_err() = UInt64(-1)

0 commit comments

Comments
 (0)