@@ -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
9899Hello, 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... )
105106end
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\n Ignoring 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)
127129end
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)
1721745.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... )
181183end
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
327343end
@@ -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```
488503Low level interface for compiling object code (`.o`) for for function `f` given
@@ -519,10 +534,10 @@ end
519534```julia
520535generate_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```
528543Low level interface for compiling object code (`.o`) for an array of Tuples
@@ -534,25 +549,34 @@ This is a struct of the type StaticTarget()
534549The defaults compile to the native target.
535550"""
536551function 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
556580end
557581
558582end # module
0 commit comments