@@ -15,18 +15,18 @@ export native_code_llvm, native_code_typed, native_llvm_module
1515
1616 !!! Warning: this will fail on programs that heap allocate any memory, or have dynamic dispatch !!!
1717
18- Statically compile the method of a function `f` specialized to arguments of the type given by `types`.
18+ Statically compile the method of a function `f` specialized to arguments of the type given by `types`.
1919
20- This will create a directory at the specified path with a shared object file (i.e. a `.so` or `.dylib`),
21- and will save a `LazyStaticCompiledFunction` object in the same directory with the extension `.cjl`. This
22- `LazyStaticCompiledFunction` can be deserialized with `load_function(path)`. Once it is instantiated in
23- a julia session, it will be of type `StaticCompiledFunction` and may be called with arguments of type
20+ This will create a directory at the specified path with a shared object file (i.e. a `.so` or `.dylib`),
21+ and will save a `LazyStaticCompiledFunction` object in the same directory with the extension `.cjl`. This
22+ `LazyStaticCompiledFunction` can be deserialized with `load_function(path)`. Once it is instantiated in
23+ a julia session, it will be of type `StaticCompiledFunction` and may be called with arguments of type
2424`types` as if it were a function with a single method (the method determined by `types`).
2525
26- `compile` will return an already instantiated `StaticCompiledFunction` object and `obj_path` which is the
26+ `compile` will return an already instantiated `StaticCompiledFunction` object and `obj_path` which is the
2727location of the directory containing the compilation artifacts.
2828
29- Example :
29+ ### Examples :
3030
3131Define and compile a `fib` function:
3232```julia
@@ -67,7 +67,7 @@ function compile(f, _tt, path::String = tempname(); name = GPUCompiler.safe_nam
6767 # Keep an eye on https://github.com/JuliaLang/julia/pull/43747 for this
6868
6969 f_wrap! (out:: Ref , args:: Ref{<:Tuple} ) = (out[] = f (args[]. .. ); nothing )
70-
70+
7171 generate_shlib (f_wrap!, Tuple{RefValue{rt}, RefValue{tt}}, path, name; kwargs... )
7272
7373 lf = LazyStaticCompiledFunction {rt, tt} (Symbol (f), path, name)
@@ -137,28 +137,65 @@ function native_job(@nospecialize(func), @nospecialize(types); kernel::Bool=fals
137137 GPUCompiler. CompilerJob (target, source, params), kwargs
138138end
139139
140+
141+ """
142+ ```julia
143+ generate_shlib(f, tt, path::String, name::String; kwargs...)
144+ ```
145+ Low level interface for compiling a shared object / dynamically loaded library
146+ (`.so` / `.dylib`) for function `f` given a tuple type `tt` characterizing
147+ the types of the arguments for which the function will be compiled.
148+
149+ See also `StaticCompiler.generate_shlib_fptr`.
150+
151+ ### Examples
152+ ```julia
153+ julia> function test(n)
154+ r = 0.0
155+ for i=1:n
156+ r += log(sqrt(i))
157+ end
158+ return r/n
159+ end
160+ test (generic function with 1 method)
161+
162+ julia> path, name = StaticCompiler.generate_shlib(test, Tuple{Int64}, "./test")
163+ ("./test", "test")
164+
165+ shell> tree \$ path
166+ ./test
167+ |-- obj.bc
168+ `-- obj.dylib
169+
170+ 0 directories, 2 files
171+
172+ julia> test(100_000)
173+ 5.256496109495593
174+
175+ julia> ccall(StaticCompiler.generate_shlib_fptr(path, name), Float64, (Int64,), 100_000)
176+ 5.256496109495593
177+ ```
178+ """
140179function generate_shlib (f, tt, path:: String = tempname (), name = GPUCompiler. safe_name (repr (f)); kwargs... )
141180 mkpath (path)
142- obj_path = joinpath (path, " obj" )
181+ obj_path = joinpath (path, " obj.bc " )
143182 lib_path = joinpath (path, " obj.$(Libdl. dlext) " )
144183 open (obj_path, " w" ) do io
145184 job, kwargs = native_job (f, tt; name, kwargs... )
146185 obj, _ = GPUCompiler. codegen (:obj , job; strip= true , only_entry= false , validate= false )
147-
186+
148187 write (io, obj)
149188 flush (io)
150- try
151- clang () do exe
152- run (pipeline (` $exe -shared -o $lib_path $obj_path ` , stderr = devnull )) # get rid of devnull when debugging
153- end
154- catch e;
155- # if Clang_jll fails, check if gcc is available
156- run (` cc -shared -o $lib_path $obj_path ` )
157- end
189+
190+ # Pick a Clang
191+ cc = Sys. isapple () ? ` cc` : clang ()
192+ # Compile!
193+ run (` $cc -shared -o $lib_path $obj_path ` )
158194 end
159195 path, name
160196end
161197
198+
162199function generate_shlib_fptr (f, tt, path:: String = tempname (), name = GPUCompiler. safe_name (repr (f)); temp:: Bool = true , kwargs... )
163200 generate_shlib (f, tt, path, name; kwargs... )
164201 lib_path = joinpath (abspath (path), " obj.$(Libdl. dlext) " )
@@ -171,6 +208,42 @@ function generate_shlib_fptr(f, tt, path::String=tempname(), name = GPUCompiler.
171208 fptr
172209end
173210
211+ """
212+ ```julia
213+ generate_shlib_fptr(path::String, name)
214+ ```
215+ Low level interface for obtaining a function pointer by `dlopen`ing a shared
216+ library given the `path` and `name` of a `.so`/`.dylib` already compiled by
217+ `generate_shlib`.
218+
219+ See also `StaticCompiler.enerate_shlib`.
220+
221+ ### Examples
222+ ```julia
223+ julia> function test(n)
224+ r = 0.0
225+ for i=1:n
226+ r += log(sqrt(i))
227+ end
228+ return r/n
229+ end
230+ test (generic function with 1 method)
231+
232+ julia> path, name = StaticCompiler.generate_shlib(test, Tuple{Int64}, "./test");
233+
234+ julia> test_ptr = StaticCompiler.generate_shlib_fptr(path, name)
235+ Ptr{Nothing} @0x000000015209f600
236+
237+ julia> ccall(test_ptr, Float64, (Int64,), 100_000)
238+ 5.256496109495593
239+
240+ julia> @ccall \$ test_ptr(100_000::Int64)::Float64 # Equivalently
241+ 5.256496109495593
242+
243+ julia> test(100_000)
244+ 5.256496109495593
245+ ```
246+ """
174247function generate_shlib_fptr (path:: String , name)
175248 lib_path = joinpath (abspath (path), " obj.$(Libdl. dlext) " )
176249 ptr = Libdl. dlopen (lib_path, Libdl. RTLD_LOCAL)
0 commit comments