使用cgo编译Go代码失败:子目录C文件引发链接错误求助
Go cgo编译错误:子目录下C文件链接失败的原因与解决方法
环境信息
- Go版本:
go version go1.20.2 linux/amd64
项目结构
example/ ├── main.go └── lib/ ├── lib.c └── lib.h
代码文件
main.go
package main // #include "lib/lib.h" // #include <stdio.h> // #include <stdlib.h> import "C" import ( "fmt" "unsafe" ) func main() { cstrin := C.CString("welcome") s1 := C.struct_s1{b: cstrin, a: 100} C.f32_123(&s1) cs := C.GoString(s1.b) fmt.Println(cs) fmt.Println(s1) C.free(unsafe.Pointer(cstrin)) }
lib/lib.c
#include <stdlib.h> #include <stdio.h> void printc(char *str, int *t) { str = "Test"; printf("%d\n", *t); *t = 30; printf("%s\n", str); } void f32_123(struct s1 *s) { printf("%s\n", s->b); s->a = 10; s->b = "Hello123"; printf("%d\n", s->a); printf("%s\n", s->b); }
lib/lib.h
struct s1 { int a; char *b; }; void printc(char *str, int *t); void f32_123(struct s1 *s);
编译错误信息
/usr/local/go/pkg/tool/linux_amd64/link: running gcc failed: exit status 1 /usr/bin/ld: /tmp/go-link-3024881602/000001.o: in function _cgo_cf24297edd23_Cfunc_f32_123': /tmp/go-build/cgo-gcc-prolog:49: undefined reference to f32_123' collect2: error: ld returned 1 exit status
现象总结
- 将所有文件放在同一目录(example)时,编译成功;
- 将
lib.c和lib.h放在子目录时,编译失败; - 在main.go中移除对
f32_123的调用后,编译也能成功。
问题原因
cgo默认只会自动编译当前包目录下的C源文件,不会递归查找子目录里的.c文件。当lib.c放在子目录时,cgo未将其纳入编译流程,导致链接阶段找不到f32_123函数的实现,从而报错。
移除对f32_123的调用后,cgo不会生成该函数的调用代码,链接器无需查找对应符号,因此编译能通过。
解决方法
方法1:用#cgo LDFLAGS指定编译子目录C文件
在main.go的cgo注释块中添加编译指令,让cgo编译子目录下的lib.c:
package main // #cgo LDFLAGS: ${SRCDIR}/lib/lib.c // #include "lib/lib.h" // #include <stdio.h> // #include <stdlib.h> import "C" // 剩余代码不变
${SRCDIR}是cgo内置变量,代表当前Go文件所在目录,可正确定位子目录下的C文件。
方法2:将子目录C文件打包为静态库
- 进入lib目录生成静态库:
cd lib gcc -c lib.c -o lib.o ar rcs libmy.a lib.o
- 在main.go的cgo注释中链接该静态库:
package main // #cgo LDFLAGS: ${SRCDIR}/lib/libmy.a // #include "lib/lib.h" // #include <stdio.h> // #include <stdlib.h> import "C" // 剩余代码不变
此方式适合C代码较多的场景,便于管理。
内容的提问来源于stack exchange,提问作者unicorn
相关产品推荐
相关产品推荐

