Julia has a very powerful @cfunction
macro that can make any pure Julia function callable to C. However, it only produces a single function pointer, contrary to modern C libraries where a pair of function pointer and a pass-through context pointer is passed to support arbitrary closures. As a result, @cfunction
’s support for closures resorts to LLVM trampolines which is not available on all platforms.
CClosure.jl exports cclosure
cclosure(callable, context_position, ReturnType, (ArgumentTypes...)) -> func_ptr, context
which
- is regular Julia function call, so local variable and expressions are supported.
- uses the context pointer to support closures on all platforms that Julia runs.
- has no extra cost compared to
@cfunction
AFAICT.
This is an example that uses qsort
on Windows
using CClosure
function qsort_c(a, func, ctx)
@ccall qsort_s(a::Ptr{Cvoid}, length(a)::Csize_t, sizeof(eltype(a))::Csize_t, func::Ptr{Cvoid}, ctx::Ptr{Cvoid})::Cvoid
end
compare(a, b)::Cint = a > b ? +1 : a < b ? -1 : 0
function qsort_log_cclosure(a)
T = eltype(a)
log = Tuple{T, T}[]
func, ctx = cclosure(1, Cint, (Ref{T}, Ref{T})) do a, b
push!(log, (a, b))
compare(a, b)
end
qsort_c(a, func, ctx)
log, a
end
qsort_log_cclosure([3,2,1])
For more descriptions check GitHub repo: melonedo/CClosure.jl