Linux下Go调用C++ .so编译报错:gcc替代g++编译问题
Hey there, let's break down what's going wrong here and fix it step by step:
First, your errors stem from two key issues:
- The
unknown type name 'class'error happens because cgo defaults to usinggcc(a C compiler) to process your C++ header file—gcc doesn't understand C++ syntax likeclass. - The
could not determine kind of name for C.Initerror is because C++ functions get name-mangled by default, so Go can't locate the exact symbol it's looking for.
Let's tackle each problem one by one:
1. Force cgo to use g++ for C++ code
By default, cgo uses gcc for C code, but we need to tell it to use g++ for your C++ files. You can do this by setting the CGO_CXX environment variable when building:
CGO_CXX=g++ go build
If you want this setting to persist, add it to your shell environment (e.g., export CGO_CXX=g++ in bash).
Also, update your cgo block to include a C++ standard flag if needed—for example:
// #cgo CXXFLAGS: -I./ -std=c++11
2. Export C-compatible interfaces from your C++ code
Go's cgo can only call C-style functions directly. C++ class members and regular functions get their names modified (name mangling) which makes them invisible to Go. We need to wrap your C++ code in extern "C" to export clean, C-compatible symbols.
Update a.h:
#ifdef __cplusplus extern "C" { #endif // Use an opaque pointer to hide the C++ class from Go (Go can't handle C++ classes directly) typedef void* AHandle; // Export a C-style init function instead of the class constructor AHandle Init(void* handle); // Add a cleanup function to avoid memory leaks void DestroyA(AHandle a); #ifdef __cplusplus } #endif // Your original C++ class definition stays here (or in a separate header) class A { public: A(void* handle) { // Your constructor logic goes here } // ... other class members };
Update a.cpp to implement the exported functions:
#include "a.h" extern "C" { AHandle Init(void* handle) { // Create and return an instance of A as an opaque pointer return new A(handle); } void DestroyA(AHandle a) { // Safely cast back to A* and delete to clean up delete static_cast<A*>(a); } }
3. Adjust your Go code to match the new interface
You have two options here: statically link against liba.so, or dynamically load it with dlopen. Let's cover both:
Option A: Static Link (Simpler)
If you want to link directly against liba.so, update your client.go cgo block and function:
package main // #cgo linux LDFLAGS: -L./libs -la // #cgo CXXFLAGS: -I./ -std=c++11 // #include "a.h" import "C" import "unsafe" func function() { // Call the exported C-style Init function // Convert your handle to a void* (adjust type as needed) blob := C.Init(unsafe.Pointer(/* your handle value */)) // Clean up when done defer C.DestroyA(blob) }
Build with CGO_CXX=g++ go build—this will link against liba.so in the ./libs directory.
Option B: Dynamic Load (Using dlopen)
If you need to load the library at runtime, adjust your code to fetch the function pointer via dlsym:
// +build linux package main // #cgo linux LDFLAGS: -ldl // #include <dlfcn.h> // #include <stdlib.h> // typedef void* (*InitFunc)(void*); // typedef void (*DestroyFunc)(void*); import "C" import "errors" import "unsafe" type Handle struct { c unsafe.Pointer } func dlOpen(filename string) (Handle, error) { ptr := C.CString(filename) defer C.free(unsafe.Pointer(ptr)) ret := C.dlopen(ptr, C.RTLD_LAZY) if ret != nil { return Handle{ret}, nil } return Handle{ret}, errors.New(C.GoString(C.dlerror())) } func function() { handle, err := dlOpen("./libs/liba.so") if err != nil { // Handle error return } defer C.dlclose(handle.c) // Fetch Init function pointer initSym := C.dlsym(handle.c, C.CString("Init")) if initSym == nil { // Handle symbol not found error return } initFunc := (*C.InitFunc)(unsafe.Pointer(initSym)) // Call the function blob := initFunc(unsafe.Pointer(/* your handle value */)) // Fetch and use DestroyA if needed destroySym := C.dlsym(handle.c, C.CString("DestroyA")) if destroySym != nil { destroyFunc := (*C.DestroyFunc)(unsafe.Pointer(destroySym)) defer destroyFunc(blob) } }
This still requires the Init and DestroyA functions to be exported with extern "C".
4. Compile your C++ shared library first
Make sure you build liba.so with g++ to ensure it's compatible:
g++ -shared -fPIC a.cpp -o libs/liba.so
Then build your Go program with:
CGO_ENABLED=1 CGO_CXX=g++ go build
内容的提问来源于stack exchange,提问作者Jimmy Lin

