Search code examples
c++goshared-objectsobject-files

Using Go in C++


linux Debian Buster

go version go1.11.6 linux/amd64

gcc version 8.3.0 (Debian 8.3.0-6)

libmylib.go

package main

import "C"

import (
    "fmt"
)

func say(text string) {
    fmt.Println(text)
}

func main(){}

mylib.h

#ifndef MY_LIB_H
#define MY_LIB_H

#include <string>

void say(std::string text);

#endif

main.cpp

#include <string>
#include "mylib.h"

using namespace std;

int main() {
    string text = "Hello, world!";

    say(text);

    return 0;
}

CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go

g++ -L/path/to/lib/ -lmylib main.cpp -o my-test-program

/usr/bin/ld: /tmp/ccu4fXFB.o: in function 'main': main.cpp:(.text+0x53): undefined reference to `say(std::__cxx11::basic_string<char, std::char_traits, std::allocator >)'
collect2: error: ld returned 1 exit status

with change: package main -> package mylib

CGO_ENABLED=1 go build -o libmylib.so -buildmode=c-shared libmylib.go

-buildmode=c-shared requires exactly one main package


Solution

  • You have to use GoString rather than std::string in the C++ version. The error message you are getting is because of the type mismatch, manifesting as a link-time error.

    See the cgo reference.

    Here's a working example. There's a few differences from yours. The //export directive is needed to include the function in the generated header file, the argument is *C.char rather than string or GoString. The C++ code uses the header generated by cgo, and there has to be a const-removing cast from the static string (because go doesn't have C-like const).

    libmylib.go

    package main
    
    import "C"
    
    import (
        "fmt"
    )
    
    //export say
    func say(text *C.char) {
        fmt.Println(C.GoString(text))
    }
    
    func main() {}
    

    main.cpp

    #include "libmylib.h"
    
    int main(void) {
        say(const_cast<char*>("hello world"));
    
        return 0;
    }
    

    commands

    This compiles to go file, generating libmylib.so and libmylib.h in the current directory.

    go build -o libmylib.so -buildmode=c-shared libmylib.go
    

    The compiles the C++ program, linking it to the shared library above:

    g++ -L. main.cpp -lmylib -o hello_program
    

    To run the program, LD_LIBRARY_PATH needs to be set to the current directory. That would be different if program was installed and the shared library put in a sensible place.

    LD_LIBRARY_PATH=. ./hello_program