[4/6 and 5/6 solved it] I am trying to wrap ngspice_jll.jl And have generated wrapper functions to sharedspice.h file.
A typical function has pointers to callback functions as arguments. Initialization looks like:
function ngSpice_Init(sendchar, statfcn) #and 5 more similar callbacks
ccall((:ngSpice_Init, libngspice), Cint, (Ptr{Cvoid}, Ptr{Cvoid}), sendchar, statfcn)
end
where sendchar = @cfunction($SendChar, Cint, (Ptr{Char}, Cint, Ptr{Cvoid})).ptr
(And SendChar is supposed to print the string pointed by Ptr{Char})
After executing ngSpice_Init(...), and loading circuit, I want to access the sendchar and its arguement. (This and other callbacks are expected to contain info about the simulation being run) When I unsafe_load it, as expected, points to nothing. unsafe_pointer_to_objref crashes the repl. What should I do to access the string (and other values) returned by the callback function.
Alright, so @cfunction creates a C pointer that is a callback to a julia function (in this case SendChar). So whenever ngspice invokes the sendchar function pointer you passed, it will end up coming through on the Julia side by invoking the SendChar function. Doing an unsafe_pointer_to_objref on sendchar doesn’t make sense, because it’s not a julia object. It’s a c function pointer. What you’ll want to do is implement the SendChar method and inside there handle whatever arguments ngspice gives to the callback.
This post is probably obsoleted but it’s still a good reading material on how to pass Julia callback functions to C.
I didn’t test the following code, but I guess you could get the idea.
function sendchar(str::Ptr{Cchar}, id::Cint, userData)::Cint
push!(userData, unsafe_string(str))
# I'm not sure what should be returned by this callback function, the header file doesn't tell much
# maybe the id, maybe just 0 as you mentioned above, you may need to dive into the code of `ngSpice_Init`.
return 0 or id?
end
user_data = String[] # you may need a more complex Julia structure for user_data, here I just make it as a string vector.
sendchar_fptr = @cfunction(sendchar, Cint, (Ptr{Cchar}, Cint, Ref{Vector{String}}))
function ngSpice_Init(sendchar, userData) #and 5 more similar callbacks
ccall((:ngSpice_Init, libngspice), Cint, (Ptr{Cvoid}, Any), sendchar, userData)
end
ngSpice_Init(sendchar_fptr, user_data)
Although I had defined function sendchar(...), I had totally mistaken that it would work only after I explicitly do “something” with the sendchar_ptr before invoking it. Now the workflow is clear. Thanks again!