Go调用静态C/C++库遇函数未定义链接错误求助
Go调用静态C++库时无法识别C包装函数的问题
我处于Go语言学习阶段,已成功编译运行包含C目标文件的Go程序。当前目标是调用一个现有静态C++库,计划通过简单C包装函数实现,但Go无法识别该包装函数。
简化后的代码
main.go
package main // #cgo CFLAGS: -I. -g -Wall // #cgo LDFLAGS: -L. -lSMHeatmapLib // #include <stdlib.h> // #include "ExternalJSON.h" import "C" import ( "fmt" "unsafe" ) const MAX_RETURN_BUFFER int = 8192 func main() { var result_str string; in_json := "The cat sat on the mat" in_buff := C.CString(in_json) defer C.free(unsafe.Pointer(in_buff)) in_sz := C.int( len(in_json) ) out_buff := C.malloc( C.sizeof_char * MAX_RETURN_BUFFER ) defer C.free(unsafe.Pointer(out_buff) ) sz := C.RunWithJSON(in_buff,in_sz, (*C.char)(out_buff),MAX_RETURN_BUFFER); b:= C.GoBytes(out_buff,sz) result_str = string(b) fmt.Printf("Return: >%s<\n", result_str) }
ExternalJSON.h
int RunWithJSON( char* in, int in_len, char* out, int max_out);
ExternalJSON.c
#include "ExternalJSON.h" int RunWithJSON( char* in, int in_len, char* out, int max_out) { for (int i=0; i<in_len; i++) { out[in_len-1-i] = in[i]; } int olen = in_len; // 添加末尾标记 out[olen++] = '#'; out[olen++] = '\0'; return olen; }
编译链接信息
C包装代码用gcc编译,库其余C代码用g编译,最终打包静态库的命令:
ar rcs $(TARGET) $(OBJS)
已将静态库和ExternalJSON.h复制到main.go同目录下,执行go build时出现以下错误:
# _/my/path/main /usr/bin/ld: $WORK/b001/_x002.o: in function `_cgo_750343fded39_Cfunc_RunWithJSON': /tmp/go-build/cgo-gcc-prolog:58: undefined reference to `RunWithJSON' collect2: error: ld returned 1 exit status
问题原因与解决方法
核心原因:C/C++函数名修饰差异
C编译器会对函数名进行名称修饰(Name Mangling),以此支持函数重载等特性;而C语言的函数名保持原样。你的静态库包含C代码,若C包装函数未做特殊处理,会被C++编译器修饰,导致Go的cgo按照C风格的函数名查找时找不到匹配的符号。
分步解决
修改头文件,用
extern "C"包裹C函数声明
确保C包装函数的声明被C++编译器识别为C风格函数,避免名称修饰。更新ExternalJSON.h:#ifdef __cplusplus extern "C" { #endif int RunWithJSON( char* in, int in_len, char* out, int max_out); #ifdef __cplusplus } #endif重新编译并打包静态库
用gcc编译C包装文件(保持C的函数名规则),再和C++目标文件一起打包:# 编译C包装文件 gcc -c ExternalJSON.c -o ExternalJSON.o # 编译C++源文件(替换为你的实际C++文件) g++ -c your_cpp_code.cpp -o your_cpp_code.o # 打包静态库 ar rcs libSMHeatmapLib.a ExternalJSON.o your_cpp_code.o验证静态库中的函数名
用nm命令检查静态库,确认RunWithJSON是未被修饰的C风格名称:nm libSMHeatmapLib.a | grep RunWithJSON正确输出应为:
0000000000000000 T RunWithJSON;若输出带乱码的名称,说明仍存在名称修饰问题,需重新检查头文件。调整Go编译命令(可选)
若链接顺序导致符号查找失败,可直接将静态库作为参数传入编译命令:go build -o main main.go libSMHeatmapLib.a
内容的提问来源于stack exchange,提问作者winwaed
相关产品推荐
相关产品推荐

