Hello,
I’m doing some FFI gymnastics but I am a bit lost in the woods.
Here is a mock up of my situation:
struct TAG_DEF # this structure was automatically generated by Clang.jl
name::Ptr{Cuchar} # string
dims::Ptr{Int64} # array of ints
type::Ptr{Cvoid} # opaque type (long story)
end
function makeStruct(tags)
ccall((:makeStruct, lib), <some return type>, (ptr{TAG_DEF},), tags)
end
so In practice, I need to pass an array of TAG_DEF
s to the makeStruct
function, but first I need to generate those TAG_DEF
s from julia objects.
I am familiar with the cconvert/unsafe_convert
dance, but so far I’ve only needed to interface with passing refs and pointers directly to the ccall.
If I had to pass only a single TAG_DEF
to the ccall, I would try something like
name = "name"
dims = [1, 2, 3]
type = 4 # types from the c side.
v = (name, dims, type)
# with
Base.cconvert(::Type{TAG_DEF}, v::Tuple) = begin
(Base.cconvert(Cstring, v[1]), v[2], Ref(v[3]))
end
Base.unsafe_convert(::Type{TAG_DEF}, v::Tuple) = begin
TAG_DEF(Base.unsafe_convert(Cstring, v[1]), pointer(v[2]), Base.unsafe_convert(Ptr{Cvoid}, v[3]))
end
# and a makeStruct call like
function makeStruct(single_tag)
ccall((:makeStruct, lib), < some return type>, (TAG_DEF,), single_tag)
end
# and call it with
makeStruct(v)
to make the translation happen automatically inside the ccall.
But the extra pointer required by the array argument really throws me off.
In particular, I’m not sure how I can make sure to tell the gc to not delete objects that are behind 3 layers of pointers. Or how to override the cconvert
and unsafe_convert
calls to also account for the additional array conversion.
I’ve sprinkled a lot of GC.@preserve
s around but really without a real rationale or understanding so it hasn’t been very useful…
Any pointers (pun intended)?