Skip to content

Commit c1c08f8

Browse files
Merge pull request #160 from daizutabi/feature-windows
Support compilation of shared library (DLL) for Windows
2 parents c0b0ef8 + 7d53475 commit c1c08f8

File tree

5 files changed

+53
-9
lines changed

5 files changed

+53
-9
lines changed

.github/workflows/ci-integration.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,17 @@ jobs:
2424
os:
2525
- ubuntu-latest
2626
- macOS-latest
27+
- windows-latest
2728
arch:
2829
- x64
2930
group:
3031
- Integration
3132
steps:
3233
- uses: actions/checkout@v2
34+
- uses: KyleMayes/install-llvm-action@v2
35+
with:
36+
version: "17"
37+
if: matrix.os == 'windows-latest'
3338
- uses: julia-actions/setup-julia@latest
3439
with:
3540
version: ${{ matrix.version }}

.github/workflows/ci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ jobs:
2424
os:
2525
- ubuntu-latest
2626
- macOS-latest
27+
- windows-latest
2728
arch:
2829
- x64
2930
group:
@@ -34,6 +35,10 @@ jobs:
3435
os: ubuntu-latest
3536
steps:
3637
- uses: actions/checkout@v2
38+
- uses: KyleMayes/install-llvm-action@v2
39+
with:
40+
version: "17"
41+
if: matrix.os == 'windows-latest'
3742
- uses: julia-actions/setup-julia@latest
3843
with:
3944
version: ${{ matrix.version }}

src/StaticCompiler.jl

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ include("interpreter.jl")
2323
include("target.jl")
2424
include("pointer_warning.jl")
2525
include("quirks.jl")
26+
include("dllexport.jl")
2627

2728
fix_name(f::Function) = fix_name(string(nameof(f)))
2829
fix_name(s) = String(GPUCompiler.safe_name(s))
@@ -125,6 +126,7 @@ function compile_executable(funcs::Union{Array,Tuple}, path::String=pwd(), name=
125126
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!"
126127

127128
generate_executable(funcs, path, name, filename; demangle, cflags, target, llvm_to_clang, kwargs...)
129+
Sys.iswindows() && (filename *= ".exe")
128130
joinpath(abspath(path), filename)
129131
end
130132

@@ -187,6 +189,7 @@ function compile_shlib(funcs::Union{Array,Tuple}, path::String=pwd();
187189
demangle = true,
188190
cflags = ``,
189191
target::StaticTarget=StaticTarget(),
192+
llvm_to_clang = Sys.iswindows(),
190193
kwargs...
191194
)
192195
for func in funcs
@@ -200,7 +203,7 @@ function compile_shlib(funcs::Union{Array,Tuple}, path::String=pwd();
200203
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!"
201204
end
202205

203-
generate_shlib(funcs, path, filename; demangle, cflags, target, kwargs...)
206+
generate_shlib(funcs, path, filename; demangle, cflags, target, llvm_to_clang, kwargs...)
204207

205208
joinpath(abspath(path), filename * "." * Libdl.dlext)
206209
end
@@ -325,17 +328,18 @@ function generate_executable(funcs::Union{Array,Tuple}, path=tempname(), name=fi
325328
if llvm_to_clang # (required on Windows)
326329
# Use clang (llc) to generate an executable from the LLVM IR
327330
cclang = if Sys.iswindows()
328-
`cmd \c clang` # Not clear if the `cmd \c` is necessary
331+
exec_path *= ".exe"
332+
`clang`
329333
elseif Sys.isapple()
330334
`clang`
331335
else
332336
clang()
333337
end
334-
run(`$cclang -Wno-override-module $wrapper_path $obj_or_ir_path -o $exec_path`)
338+
run(`$cclang -Wno-override-module $wrapper_path $obj_or_ir_path -o $exec_path`)
335339
else
336340
run(`$cc $wrapper_path $cflags $obj_or_ir_path -o $exec_path`)
337341
end
338-
342+
339343
# Clean up
340344
rm(wrapper_path)
341345
end
@@ -391,6 +395,7 @@ function generate_shlib(funcs::Union{Array,Tuple}, path::String=tempname(), file
391395
demangle = true,
392396
cflags = ``,
393397
target::StaticTarget=StaticTarget(),
398+
llvm_to_clang::Bool = Sys.iswindows(),
394399
kwargs...
395400
)
396401
if !isnothing(target.platform)
@@ -399,15 +404,28 @@ function generate_shlib(funcs::Union{Array,Tuple}, path::String=tempname(), file
399404
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
400405
end
401406

402-
_, obj_path = generate_obj(funcs, path, filename; target, demangle, kwargs...)
407+
_, obj_or_ir_path = generate_obj(funcs, path, filename; demangle, target, emit_llvm_only=llvm_to_clang, kwargs...)
403408
# Pick a Clang
404409
if !isnothing(target.compiler)
405410
cc = `$(target.compiler)`
406411
else
407412
cc = Sys.isapple() ? `cc` : clang()
408413
end
409414
# Compile!
410-
run(`$cc -shared $cflags $obj_path -o $lib_path `)
415+
if llvm_to_clang # (required on Windows)
416+
# Use clang (llc) to generate an executable from the LLVM IR
417+
cclang = if Sys.iswindows()
418+
add_dllexport(funcs, obj_or_ir_path; demangle)
419+
`clang`
420+
elseif Sys.isapple()
421+
`clang`
422+
else
423+
clang()
424+
end
425+
run(`$cclang -shared -Wno-override-module $obj_or_ir_path -o $lib_path`)
426+
else
427+
run(`$cc -shared $cflags $obj_or_ir_path -o $lib_path `)
428+
end
411429

412430
path, name
413431
end

src/dllexport.jl

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function add_dllexport(funcs, ir_path; demangle=true)
2+
ir = read(ir_path, String)
3+
4+
for (f, _) in funcs
5+
name_f = (demangle ? "" : "julia_") * fix_name(f)
6+
pattern = Regex("^define(.*?@$name_f\\()", "m")
7+
ir = replace(ir, pattern => s"define dllexport\1")
8+
end
9+
10+
write(ir_path, ir)
11+
end

test/testintegration.jl

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ if VERSION >= v"1.9"
99
buf = AllocBuffer(MallocVector, sizeof(Float64) * N)
1010
s = 0.0
1111
for i 1:N
12-
# some excuse to reuse the same memory a bunch of times
12+
# some excuse to reuse the same memory a bunch of times
1313
@no_escape buf begin
1414
v = @alloc(Float64, N)
1515
v .= i
@@ -24,7 +24,7 @@ if VERSION >= v"1.9"
2424

2525
path = compile_shlib(bumper_test, (Int,), "./")
2626
ptr = Libdl.dlopen(path, Libdl.RTLD_LOCAL)
27-
27+
2828
fptr = Libdl.dlsym(ptr, "bumper_test")
2929

3030
@test bumper_test(8) == @ccall($fptr(8::Int)::Float64)
@@ -303,7 +303,12 @@ end
303303
catch e
304304
@info "maybe_throw: task failed sucessfully!"
305305
end
306-
@test status === -1
306+
if Sys.iswindows()
307+
@info "maybe_throw: task doesn't fail on Windows."
308+
@test status.exitcode == 0
309+
else
310+
@test status === -1
311+
end
307312
end
308313

309314
## --- Test interop

0 commit comments

Comments
 (0)