如何在Go中调用CMake生成的C++静态库?解决未定义引用错误
Cgo链接C++静态库出现未定义引用的解决方案
问题背景
使用CMake 3.27构建C++静态库后,通过Go 1.20.7的cgo调用时,持续触发undefined reference to 'Adder'链接错误。此前尝试过SWIG和C包装层,其中C包装层在纯C程序中可正常工作,但在cgo环境下仍报错。环境为Ubuntu 20.04。
核心原因
C编译器会对函数名进行名字修饰(Name Mangling),生成包含函数参数类型等信息的特殊符号;而cgo默认通过GCC按C语言的符号规则查找函数,无法识别被修饰的C符号,导致链接失败。
解决步骤
1. 修改头文件,添加extern "C"声明
修改cpp.h,将函数声明包裹在extern "C"块中,同时兼容C/C++编译环境:
#ifndef CONNECT_H #define CONNECT_H #ifdef __cplusplus extern "C" { #endif int Adder(int a, int b); #ifdef __cplusplus } #endif #endif
注意:原头文件中的宏
connect易与系统函数重名,建议改为大写的CONNECT_H避免冲突。
2. 修正C++源文件的头引用
确保add.cpp中包含的是修改后的头文件(若原引用的ConnectionHeader.h是笔误,改为cpp.h):
#include "cpp.h" #include <iostream> using namespace std; int Adder(int a, int b) { cout << a + b << " "; return a+b; }
3. 重新编译C++静态库
用CMake重新构建库,确保生成的静态库中包含C风格的函数符号。可通过以下命令验证:
nm /home/omar/CMake_Projects/PROJECT_HEADER/build/libMyLibrary.a | grep Adder
若输出为T Adder(无多余修饰字符),说明符号已按C规则生成。
4. 验证Go代码调用
保持原Go代码不变,确保#cgo参数中的头文件路径(-I)和库路径(-L)正确指向实际文件位置:
package main //#cgo CPPFLAGS: -I /home/omar/CMake_Projects/PROJECT_HEADER //#cgo LDFLAGS: -L /home/omar/CMake_Projects/PROJECT_HEADER/build -l MyLibrary //#include "cpp.h" import ( "C" ) import "fmt" func main() { a := C.int(9878) b := C.int(4) c := C.Adder(a, b) fmt.Println(c) }
额外说明
若仍使用C包装层,需确保包装层的函数也通过extern "C"声明,且包装层代码用C编译器编译(或在C环境下按C规则编译),再与C库链接。直接给C++函数添加extern "C"是更简洁的解决方案。
内容的提问来源于stack exchange,提问作者Omar Khalil
相关产品推荐
相关产品推荐

