gostructenumscgo

How to use enums and structs defined in another package with cgo?


When I want to create an instance of a struct, defined in another package then I get an IncompatibleAssign error.

The project has following structure:

def.go
root/root.go

In def.go a struct is defined as follows:

package fastlogging

/*
#cgo LDFLAGS: -L. -L../lib -lcfastlogging
#include "../h/cfastlogging.h"
*/
import "C"

type ServerConfig struct {
    Config *C.CServerConfig
}

In root.go I want to create an instance of this struct:

package root

/*
#cgo LDFLAGS: -L. -L../lib -lcfastlogging
#include "../../h/cfastlogging.h"
*/
import "C"
import (
    logging "gofastlogging/fastlogging"
    "gofastlogging/fastlogging/logger"
    "unsafe"
)

func GetServerConfig() logging.ServerConfig {
    config := C.root_get_server_config()
    ptr := unsafe.Pointer(config)
    config2 := (*C.CServerConfig)(ptr)
    return logging.ServerConfig{Config: config2}
}

This leads to the following error message:

cannot use config2 (variable of type *_Ctype_struct_CServerConfig) as *fastlogging._Ctype_struct_CServerConfig value in struct literal

How can I fix this?


Solution

  • You are importing the same .h file to define two distinct Go types. Although they have the same memory layout, they have different (package) names and therefore types.

    Best keep all your cgo stuff in one file gofastlogging/fastlogging/def.go:

    package fastlogging
    
    // #include "../h/cfastlogging.h"
    import "C"
    
    type ServerConfig struct {
        Config *C.CServerConfig
    }
    
    func GetServerConfig() ServerConfig {
        config := C.root_get_server_config()
        return ServerConfig{Config: config}
    }
    

    and then use it from root.go like:

    package root
    
    import (
        "fmt"
    
        "your.domain/gofastlogging/fastlogging"
    )
    
    func main() {
        config := fastlogging.GetServerConfig()
        fmt.Println(config)
    }
    

    Note that you should declare

    CServerConfig* root_get_server_config() {
        //  ...
    }
    

    to avoid casting in Go code.