Closed mokuki082 closed 5 years ago
My goal is to create a Go function createContainer
, where I should be able to give it some config struct from C/Haskell, and it would call the underlying libcontainer API to create the container, and return another c struct with all necessary information about the container back to C.
As a simplification of the problem, I created a practice project with a function Foo()
that acts as the createContainer function, and two structs Fooz and Barz which acts as the input and outputs of the Foo function respectively.
func foo(f *C.struct_Fooz) (*C.struct_Barz, error) {
// Do some operations...
return ConvBarz(bar(ConvFooz(f))), nil
}
The pseudo-module C
has to be imported for this to work. "C" is not a real module, it represents the C namespace and it gets replaced from C.xxx
to _C_xxx
during compilation phase, which can be interpreted as unexported Go types/variables.
Although untested, this function is supposed to take in a C struct and return a C struct using the C pseudo-module, which is precisely what I wanted to do for createContainer
.
The marshalling processes ConvBarz
and ConvFooz
can be a little more complicated when dealing with structs of structs, or structs of arrays, but for simplicity Fooz
and Barz
both contains an int
field n
, which can be converted easily using int()
as follows:
func ConvFooz(f *C.struct_Fooz) *data.Fooz {
return &data.Fooz { int(f.n) }
}
func ConvBarz(b *data.Barz) *C.struct_Barz {
return &C.struct_Barz{ C.int(b.N) } // N is exported because it's in a different package.
}
Altogether this is compiled into a shared object.
There are a lot of restrictions in passing pointers between C and Go. I'm not confident that this code works but at least it compiled. I'll be working on calling the shared library from C/Haskell tomorrow
It is working!
I renamed the variables so they are more readable now, here is the code
Here are some main points that I've discovered:
func foo(a1 *C.struct_InputStruct, a2 *C.struct_OutputStruct)
rather than func foo(a *C.struct_InputStruct) *C.struct_OutputStruct
).It makes sense that a go function called by C cannot return a go pointer. The usual idiom in C when expecting the procedure to allocate something onto the heap is to pass it the result pointer. C functions can only return by value. That is primitive values. There was some work done to allow C to pass structs by value though.
A way to pass structs to and from Go is needed for the creation of containers.
The main structs we need to serialise are
spec.Spec
andContainer
.This stackoverflow post suggests that directly accessing C structs from Go is possible.
I should investigate how pointers work and what is provided in cgo.