c++goswig

Swig is not detecting correctly the struct to call C++


I am trying to use a Golang structure in c++ code. To do so, I defined the same structure in both C++ header and in Golang, but when I try to run the project I get the following error:

./runme.go:22:32: cannot use (*Edge)(dataPtr) (value of type *Edge) as example.Edge value in argument to example.Process: *Edge does not implement example.Edge (missing method GetW)

My project has the following structure.

./go.mod:

module simple

go 1.20

./runme.go:

package main

import (
        "unsafe"
        "simple/example"
)

type Edge struct {
        X, Y int64
        W    float64
}

func main() {
        data := []Edge {
                {1,2,1.0},
                {1,3,4.0},
                {2,3,3.0},
                {2,4,0.5},
        }

        dataPtr := unsafe.Pointer(&data[0])
        example.Process((*Edge)(dataPtr),int64(len(data)), int64(4))
}

Then I have my package that contains the c++ code:

./example/package.go:

package example

import "C"

./example/example.i:

%module example

// Typemaps for Edge struct
%typemap(in) Edge {
    $1 = *($1_ltype*)($input);
}
%typemap(in) Edge* {
    $1 = *($1_ltype*)($input);
}

%typemap(out) Edge {
    $result = new $1_btype($1);
}

%{
#include "example.h"
%}

%include "example.h"

./example/example.h:

#ifndef EXAMPLE_H
#define EXAMPLE_H

typedef struct Edge
{
        long int X, Y;
        double W;
} Edge;

void Process(Edge *G, long int M, long int N);

#endif

./example/example.cpp:

#include "example.h"
#include <iostream>

void Process(Edge *G, long int M, long int N) {
        // Do some work with the Edge list
        std::cout << "|V| = " << N << "  --  |E| = " << M << std::endl;

        for(int i = 0; i < M; i++) {
                std::cout << "(" << G[i].X << ", " << G[i].Y << ") = " << G[i].W << std::endl;
        }
}

I tried to implement the GetW and all other methods that it asks for, but at some point it asks for methods that I do not understand what they mean. I believe the problem might be with the typemap in the swig interface that is not connecting properly both structs, but I have no clue how to fix it.


Solution

  • Declare the types in both languages as you have done.

    Ignore the C++ type from SWIG:

    %ignore Edge;
    

    SWIG generates a Go wrapper with the Go signatures, this wrapper must have the Go Edge type declared, import it using:

    %insert(go_wrapper) %{
    // import here
    %}
    

    SWIG must also know to use the right type in the wrapper, use the special gotype typemap for this:

    %typemap(gotype) Edge "root.Edge"
    

    Remember to check the example/example.go file - it will have something that goes as:

    func Process(arg1 Edge, arg2 int64, arg3 int64) {
    

    This is the root of your problem. The gotype typemap should fix this.

    Sorry, but I have but a very basic understanding of Go.