Search code examples
cgointeropcgo

How to remove "extern" functions in C and be able to use them from golang?


I have a C wrapper of C++ library that I want to use with golang. Overall path of callback that I want is golang->C->C++. I tested part C->C++, but face difficulties with golang->C part.

As said in wiki, I tried this example. It works good on linux, but when I compile it on windows it fails on "extern" keyword because I compile C library and golang separately.

I thought that it is possible to split C library on part that doesn't know about golang at all. And put this callback with "extern" keyword into golang directory. But I think this will not fit me because function that takes callback and I need looks like this:

ClipperPaths64 *
clipper_clipperoffset_execute_gocallback(void *mem, ClipperClipperOffset *c, uintptr_t h) {
        auto result = new (mem) Paths64();
        from_c(c)->Execute(from_c(h), *result);
        return to_c(result);
}

You see that I use from_c(...) functions and they return C++ objects, they are not exposed publicly of this library and I cannot use them.

I would share more code if it would be helpful.


Solution

  • Well, it is solved and as reference you may peek my repo: here

    Solution: Just move function that is "extern" to directory of golang module. You will compile separately C/C++ library and alongside golang code you can place callbacks and whatever you will define in golang file.

    Example of callback.c:

    // define delta callback
    double delta_callback(
        uintptr_t h,
        ClipperPath64 *path, ClipperPathD *path_normals,
        size_t curr_idx, size_t prev_idx)
    {
        return goDeltaCallback64(h, path, path_normals, curr_idx, prev_idx);
    }
    

    callback.h:

    #ifndef CLIBRARY_H
    #define CLIBRARY_H
    
    #include <stddef.h>
    #include "../lib/clipper2c/clipper2c.h"
    
    typedef double (*callbackfunc) (
        uintptr_t h, ClipperPath64 *path, ClipperPathD *path_normals,
                        size_t curr_idx, size_t prev_idx);
    
    double delta_callback(
        uintptr_t h,
        ClipperPath64 *path, ClipperPathD *path_normals,
        size_t curr_idx, size_t prev_idx);
    
    extern double goDeltaCallback64(uintptr_t h, ClipperPath64 *path,
                                    ClipperPathD *path_normals, size_t curr_idx,
                                    size_t prev_idx);
    
    #endif
    

    .go:

    //export goDeltaCallback64
    func goDeltaCallback64(
        h C.uintptr_t,
        path *C.ClipperPath64,
        path_normals *C.ClipperPathD,
        curr_idx C.size_t,
        prev_idx C.size_t,
    ) C.double {
        fn := cgo.Handle(h).Value().(ClipperOffsetCallback)
    
        gopath := &Path64{
            p: path,
        }
    
        gopath_normals := &PathD{
            p: path_normals,
        }
    
        return C.double(fn(gopath, gopath_normals, int(curr_idx), int(prev_idx)))
    }