Using a Base.CFunction in ccall

I want to do something like this, inside a begin block:

begin
    f(x) = x * x
    ptr = @cfunction(f, Cdouble, (Cdouble,))
    g(x) = ccall(ptr, Cdouble, (Cdouble,), x)
    g(1.2)
end

However this gives the following error:

ERROR: LoadError: UndefVarError: f not defined

I’ve been suggested by @kristoffer.carlsson to use $f in @cfunction, thus resulting in the creation of Base.CFunction. However, I don’t understand ho to use in a ccall. I couldn’t find any such example in Julia’s Base. Base.CFunction’s docstring reads:

Like all cfunction handles, it should be passed to ccall as a Ptr{Cvoid}, and will be converted automatically at the call site to the appropriate type.

How to convert a Base.CFunction to Ptr{Cvoid}? convert and Base.cconvert don’t work, but Base.unsafe_convert may do the trick. Is this the way to go (i.e., ccall(Base.unsafe_convert(Ptr{Cvoid}, ptr), ...))?

1 Like

Does anyone have a clue about how to do this?

Is there some problem due to be inside the begin end block?
Anyway, just to confirm, are you aware of the qsort example https://docs.julialang.org/en/stable/manual/calling-c-and-fortran-code/#Creating-C-Compatible-Julia-Function-Pointers-1, right?

Yes, I need to do this inside a begin-end block, specifically it’s in a @testset.

Yes, I know that example and I’ve used callbacks in Cuba.jl. However, here there is no callback, I just want to ccall a very simple function defined with @cfunction

Oh, that’s true, I had not read your original question very carefully.

Bump. Does anyone know how to do this?

(edited, see next comment for the correct solution)
julia> function f end
       begin
           global f
           f(x) = x * x
           ptr = @cfunction(f, Cdouble, (Cdouble,))
           g(x) = ccall(ptr, Cdouble, (Cdouble,), x)
           g(1.2)
       end
1.44

No that’s not a closure (If you don’t need a closure then that’s fine but in that case you should use function f end instead of defining a dummy method).

julia> let f = (x)->x * x
           ptr = @cfunction $f Cdouble (Cdouble,)
           GC.@preserve ptr ccall(Base.unsafe_convert(Ptr{Cvoid}, ptr), Cdouble, (Cdouble,), 2.0)
       end
4.0
2 Likes

Ok, so Base.unsafe_convert was indeed the way to go, I was missing the GC.@preserve. Thank you!

This topic was automatically closed 12 days after the last reply. New replies are no longer allowed.