Skip to content

Commit

Permalink
Merge pull request #160 from daizutabi/feature-windows
Browse files Browse the repository at this point in the history
Support compilation of shared library (DLL)  for Windows
  • Loading branch information
brenhinkeller authored May 29, 2024
2 parents c0b0ef8 + 7d53475 commit c1c08f8
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 9 deletions.
5 changes: 5 additions & 0 deletions .github/workflows/ci-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,17 @@ jobs:
os:
- ubuntu-latest
- macOS-latest
- windows-latest
arch:
- x64
group:
- Integration
steps:
- uses: actions/checkout@v2
- uses: KyleMayes/install-llvm-action@v2
with:
version: "17"
if: matrix.os == 'windows-latest'
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.version }}
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ jobs:
os:
- ubuntu-latest
- macOS-latest
- windows-latest
arch:
- x64
group:
Expand All @@ -34,6 +35,10 @@ jobs:
os: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: KyleMayes/install-llvm-action@v2
with:
version: "17"
if: matrix.os == 'windows-latest'
- uses: julia-actions/setup-julia@latest
with:
version: ${{ matrix.version }}
Expand Down
30 changes: 24 additions & 6 deletions src/StaticCompiler.jl
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ include("interpreter.jl")
include("target.jl")
include("pointer_warning.jl")
include("quirks.jl")
include("dllexport.jl")

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

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

Expand Down Expand Up @@ -187,6 +189,7 @@ function compile_shlib(funcs::Union{Array,Tuple}, path::String=pwd();
demangle = true,
cflags = ``,
target::StaticTarget=StaticTarget(),
llvm_to_clang = Sys.iswindows(),
kwargs...
)
for func in funcs
Expand All @@ -200,7 +203,7 @@ function compile_shlib(funcs::Union{Array,Tuple}, path::String=pwd();
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!"
end

generate_shlib(funcs, path, filename; demangle, cflags, target, kwargs...)
generate_shlib(funcs, path, filename; demangle, cflags, target, llvm_to_clang, kwargs...)

joinpath(abspath(path), filename * "." * Libdl.dlext)
end
Expand Down Expand Up @@ -325,17 +328,18 @@ function generate_executable(funcs::Union{Array,Tuple}, path=tempname(), name=fi
if llvm_to_clang # (required on Windows)
# Use clang (llc) to generate an executable from the LLVM IR
cclang = if Sys.iswindows()
`cmd \c clang` # Not clear if the `cmd \c` is necessary
exec_path *= ".exe"
`clang`
elseif Sys.isapple()
`clang`
else
clang()
end
run(`$cclang -Wno-override-module $wrapper_path $obj_or_ir_path -o $exec_path`)
run(`$cclang -Wno-override-module $wrapper_path $obj_or_ir_path -o $exec_path`)
else
run(`$cc $wrapper_path $cflags $obj_or_ir_path -o $exec_path`)
end

# Clean up
rm(wrapper_path)
end
Expand Down Expand Up @@ -391,6 +395,7 @@ function generate_shlib(funcs::Union{Array,Tuple}, path::String=tempname(), file
demangle = true,
cflags = ``,
target::StaticTarget=StaticTarget(),
llvm_to_clang::Bool = Sys.iswindows(),
kwargs...
)
if !isnothing(target.platform)
Expand All @@ -399,15 +404,28 @@ function generate_shlib(funcs::Union{Array,Tuple}, path::String=tempname(), file
lib_path = joinpath(path, "$filename.$(Libdl.dlext)")
end

_, obj_path = generate_obj(funcs, path, filename; target, demangle, kwargs...)
_, obj_or_ir_path = generate_obj(funcs, path, filename; demangle, target, emit_llvm_only=llvm_to_clang, kwargs...)
# Pick a Clang
if !isnothing(target.compiler)
cc = `$(target.compiler)`
else
cc = Sys.isapple() ? `cc` : clang()
end
# Compile!
run(`$cc -shared $cflags $obj_path -o $lib_path `)
if llvm_to_clang # (required on Windows)
# Use clang (llc) to generate an executable from the LLVM IR
cclang = if Sys.iswindows()
add_dllexport(funcs, obj_or_ir_path; demangle)
`clang`
elseif Sys.isapple()
`clang`
else
clang()
end
run(`$cclang -shared -Wno-override-module $obj_or_ir_path -o $lib_path`)
else
run(`$cc -shared $cflags $obj_or_ir_path -o $lib_path `)
end

path, name
end
Expand Down
11 changes: 11 additions & 0 deletions src/dllexport.jl
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
function add_dllexport(funcs, ir_path; demangle=true)
ir = read(ir_path, String)

for (f, _) in funcs
name_f = (demangle ? "" : "julia_") * fix_name(f)
pattern = Regex("^define(.*?@$name_f\\()", "m")
ir = replace(ir, pattern => s"define dllexport\1")
end

write(ir_path, ir)
end
11 changes: 8 additions & 3 deletions test/testintegration.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if VERSION >= v"1.9"
buf = AllocBuffer(MallocVector, sizeof(Float64) * N)
s = 0.0
for i 1:N
# some excuse to reuse the same memory a bunch of times
# some excuse to reuse the same memory a bunch of times
@no_escape buf begin
v = @alloc(Float64, N)
v .= i
Expand All @@ -24,7 +24,7 @@ if VERSION >= v"1.9"

path = compile_shlib(bumper_test, (Int,), "./")
ptr = Libdl.dlopen(path, Libdl.RTLD_LOCAL)

fptr = Libdl.dlsym(ptr, "bumper_test")

@test bumper_test(8) == @ccall($fptr(8::Int)::Float64)
Expand Down Expand Up @@ -303,7 +303,12 @@ end
catch e
@info "maybe_throw: task failed sucessfully!"
end
@test status === -1
if Sys.iswindows()
@info "maybe_throw: task doesn't fail on Windows."
@test status.exitcode == 0
else
@test status === -1
end
end

## --- Test interop
Expand Down

0 comments on commit c1c08f8

Please sign in to comment.