Skip to content

Instantly share code, notes, and snippets.

@geraldstanje
Last active April 6, 2024 17:23
Show Gist options
  • Save geraldstanje/4624ac47eb3dec5b8bbe12d4714ed330 to your computer and use it in GitHub Desktop.
Save geraldstanje/4624ac47eb3dec5b8bbe12d4714ed330 to your computer and use it in GitHub Desktop.
Call go from C++ using a shared library

https://medium.com/@walkert/fun-building-shared-libraries-in-go-639500a6a669

https://www.darkcoding.net/software/building-shared-libraries-in-go-part-2/

https://karthikkaranth.me/blog/calling-c-code-from-go/

https://www.cockroachlabs.com/blog/the-cost-and-complexity-of-cgo/

https://golang.org/cmd/cgo/#hdr-Passing_pointers

https://blog.filippo.io/building-python-modules-with-go-1-5/

Build modes The 'go build' and 'go install' commands take a -buildmode argument which indicates which kind of object file is to be built. Currently supported values are:

-buildmode=archive Build the listed non-main packages into .a files. Packages named main are ignored.

-buildmode=c-archive Build the listed main package, plus all packages it imports, into a C archive file. The only callable symbols will be those functions exported using a cgo //export comment. Requires exactly one main package to be listed.

-buildmode=c-shared Build the listed main package, plus all packages it imports, into a C shared library. The only callable symbols will be those functions exported using a cgo //export comment. Requires exactly one main package to be listed.

-buildmode=default Listed main packages are built into executables and listed non-main packages are built into .a files (the default behavior).

-buildmode=shared Combine all the listed non-main packages into a single shared library that will be used when building with the -linkshared option. Packages named main are ignored.

-buildmode=exe Build the listed main packages and everything they import into executables. Packages not named main are ignored.

-buildmode=pie Build the listed main packages and everything they import into position independent executables (PIE). Packages not named main are ignored.

-buildmode=plugin Build the listed main packages, plus all packages that they import, into a Go plugin. Packages not named main are ignored. On AIX, when linking a C program that uses a Go archiv

package main
import "C"
import (
"sort"
)
//export Add
func Add(a, b int) int {
return a + b
}
//export Sub
func Sub(a, b int) int {
return a - b
}
//export Print
func Print(str string) {
fmt.Printf("Go prints: %s\n", str)
}
func strFxn(input string) string {
return "Hello " + input + " World"
}
//export StrFxn
func StrFxn(cinput *C.char) *C.char {
// C data needs to be manually managed in memory.
// But we will do it from C++.
input := C.GoString(cinput)
return C.CString(strFxn(input))
}
//export Sort
func Sort(vals []int) {
sort.Ints(vals)
}
func main() {
// We need the main function to make possible
// CGO compiler to compile the package as C shared library
}
#include <iostream>
#include <string>
#include "bidder_module.h"
int main() {
int res = Add(1, 2);
std::cout << res << std::endl;
GoString str;
str.p = "Hello World";
str.n = strlen(str.p);
Print(str);
std::string s = "Bidder";
char *cstr = new char[s.length()+1];
std::strcpy (cstr, s.c_str());
cstr = StrFxn(cstr);
std::cout << cstr << std::endl;
delete[] cstr;
return 0;
}
# if you are on osx:
# this creates bidder_module.h and bidder_module.dylib file
go build -o bidder_module.dylib -buildmode=c-shared bidder_module.go
g++ main.cpp bidder_module.dylib -o main && ./main
# if you are on linux:
# this creates bidder_module.h and bidder_module.so file
# go build -o bidder_module.so -buildmode=c-shared bidder_module.go
# g++ main.cpp bidder_module.so -o main && ./main
@prokash-sinha
Copy link

Who gens the .h file ?

prokash@prokash-PC /cygdrive/c/Users/prokash/mysrc/C++go
$ ls
bidder_module.go main.cpp run.sh wincmds

prokash@prokash-PC /cygdrive/c/Users/prokash/mysrc/C++go
$ source ./run.sh

runtime/cgo

gcc_libinit_windows.c: In function ‘x_cgo_sys_thread_create’:
gcc_libinit_windows.c:58:19: error: implicit declaration of function ‘_beginthre
ad’; did you mean ‘OpenThread’? [-Werror=implicit-function-declaration]
58 | thandle = _beginthread(func, 0, arg);
| ^~~~~~~~~~~~
| OpenThread
cc1: all warnings being treated as errors
main.cpp:3:10: fatal error: bidder_module.h: No such file or directory
3 | #include "bidder_module.h"
| ^~~~~~~~~~~~~~~~~
compilation terminated.

@prokash-sinha
Copy link

I was using cygWin on Windows 10. But neither static or dll build creates the .h file --- Any help ?

if you are on windows:

static linking

this creates bidder_module.h and bidder_module.a file

go build -o bidder_module.a -buildmode=c-archive bidder_module.go
g++ main.cpp bidder_module.a -o main && main.exe

dynamic linking

this creates bidder_module.h and bidder_module.dll file

go build -o bidder_module.dll -buildmode=c-shared bidder_module.go
g++ main.cpp bidder_module.dll -o main && main.exe

@prokash-sinha
Copy link

Nevermind tdm does it

@kiskit
Copy link

kiskit commented Dec 9, 2022

I'm kinda in awe of that discovery right now

@kiskit
Copy link

kiskit commented Dec 9, 2022

Nevermind tdm does it

I was using cygWin on Windows 10. But neither static or dll build creates the .h file --- Any help ?

if you are on windows:

static linking

this creates bidder_module.h and bidder_module.a file

go build -o bidder_module.a -buildmode=c-archive bidder_module.go g++ main.cpp bidder_module.a -o main && main.exe

dynamic linking

this creates bidder_module.h and bidder_module.dll file

go build -o bidder_module.dll -buildmode=c-shared bidder_module.go g++ main.cpp bidder_module.dll -o main && main.exe

Nevermind tdm does it

Have you by any chance written // export instead of //export? I struggled for 10 minutes with the .h generation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment