Golang程序中使用CGO共享库的方法
Golang程序中使用CGO共享库的方法
尝试测试 cgo,因此我编写了以下代码:
//go:build lib
// +build lib
package main
import "C"
import "fmt"
//export HelloWorld
func HelloWorld() {
fmt.Printf("hello world")
}
func main() {}
// go build -tags lib -buildmode=c-shared -o golib.a lib.go
并按如下方式编译:
$ go build -tags lib -buildmode=c-shared -o golib.a lib.go
尝试在另一个代码中使用生成的共享库:
//go:build app
// +build app
package main
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "golib.h"
import "C"
func main() {
C.HelloWorld()
}
// go run main.go
但我遇到了以下错误:
# command-line-arguments
Undefined symbols for architecture x86_64:
"_HelloWorld", referenced from:
__cgo_a844f0d618a1_Cfunc_HelloWorld in _x002.o
(maybe you meant: __cgo_a844f0d618a1_Cfunc_HelloWorld)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
# command-line-arguments
cgo-gcc-prolog:47:33: warning: unused variable '_cgo_a' [-Wunused-variable]
此外,我在 Mac 上的 VS Code 中遇到了以下错误:
go list failed to return CompiledGoFiles. This may indicate failure to perform cgo processing; try building at the command line. See https://golang.org/issue/38990

更多关于Golang程序中使用CGO共享库的方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
抱歉,我刚刚更新了上一个回答。我漏掉了 rpath 前面的 -。
更多关于Golang程序中使用CGO共享库的方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我在处理我的项目时,在 Git 中也遇到了同样的问题,我通过相同的步骤解决了它。
看起来Go的语法有所不同;将
-Wl,-rpath=.
改为
-Wl,-rpath,.
skillian:
-Wl,rpath,.
我的朋友也遇到了同样的问题:invalid flag in #cgo LDFLAGS: -Wl,rpath,.
// go run main.go
这意味着仅运行 main.go 文件(而忽略任何其他的 .go 或 .c 文件)。你应该使用 go run . 来编译当前目录下包含所有文件的包。
我认为你可能需要在 LDFLAGS 中指定你的 “lib” 库。类似这样:
#cgo LDFLAGS: -L. -llib -Wl,-rpath,.
我的理解是:
-L选项告诉链接器在链接时去哪里查找库,-llib表示包含lib库,-Wl,-rpath,.告诉编译后的二进制文件,在它执行时,在与你的 Go 程序相同的文件夹中查找你的共享库。
skillian:
#cgo LDFLAGS: -L. -llib -Wl,-rpath=.
我遇到了错误:invalid flag in #cgo LDFLAGS: -Wl,-rpath=.
更新后的代码如下:
package main
// #cgo LDFLAGS: -L. -llib -Wl,-rpath=.
// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "golib.h"
import "C"
func main() {
C.HelloWorld()
}
同样的问题。
我尝试了:
package main
//#cgo CFLAGS: -g -Wall
//#cgo LDFLAGS: -L. -lgo
//#include "libgo.h"
import "C"
import "fmt"
func main() {
C.HelloWorld()
}
但得到了:
➜ gocallclib git:(master) ✗ go run main-dl.go
# command-line-arguments
cgo-gcc-prolog:67:33: warning: unused variable '_cgo_a' [-Wunused-variable]
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x43fd5e2]
goroutine 1 [running, locked to thread]:
runtime.throw({0x40a875b?, 0x1c00011b800?})
/usr/local/go/src/runtime/panic.go:992 +0x71 fp=0x1c00004a960 sp=0x1c00004a930 pc=0x402f6d1
runtime: unexpected return pc for runtime.sigpanic called from 0x43fd5e2
stack: frame={sp:0x1c00004a960, fp:0x1c00004a9b0} stack=[0x1c00004a000,0x1c00004b000)
....
0x000001c00004aaa0: 0x0000000000000000 0x0000000000000000
runtime.sigpanic()
/usr/local/go/src/runtime/signal_unix.go:781 +0x3a9 fp=0x1c00004a9b0 sp=0x1c00004a960 pc=0x4043449
exit status 2
go run .
仍然是同样的错误。
➜ ffi git:(master) ✗ go run .
# github.io/hajsf/ffi
Undefined symbols for architecture x86_64:
"_HelloWorld", referenced from:
__cgo_da04f5d85884_Cfunc_HelloWorld in _x002.o
(maybe you meant: __cgo_da04f5d85884_Cfunc_HelloWorld)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
# github.io/hajsf/ffi
cgo-gcc-prolog:47:33: warning: unused variable '_cgo_a' [-Wunused-variable]
➜ ffi git:(master) ✗ clang --version
Apple clang version 12.0.5 (clang-1205.0.22.9)
Target: x86_64-apple-darwin21.2.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin
我猜测(但不完全确定),cgo 无法调用由另一个 cgo 生成的函数。
我能够轻松地使用普通的 .c 和 .h 文件(这里的“普通”指的是不由 cgo 生成)完成所需的功能。
// main.h
int Add(int, int);
//main.c
#include <stdio.h>
int Add(int a, int b){
printf("Welcome from external C function\n");
return a + b;
}
package main
// #include "main.h"
// #include <stdio.h>
// int Add2(int x)
// {
// printf("Welcome from inline C function\n");
// return x + 2;
// }
import "C"
import "fmt"
func main() {
fmt.Println(C.Add(1, 2))
fmt.Println(C.Add2(5))
}
它运行顺利,并给出了以下输出:
➜ ffi git:(master) ✗ go run .
Welcome from external C function
3
Welcome from inline C function
7
在CGO中,当使用-buildmode=c-shared生成共享库时,需要确保头文件正确生成并被引用。你的问题在于生成的golib.h头文件中函数声明缺少extern前缀。
首先检查生成的golib.h文件内容:
$ cat golib.h
应该类似这样:
/* Code generated by cmd/cgo; DO NOT EDIT. */
#line 1 "cgo-builtin-export-prolog"
#include <stddef.h> /* for ptrdiff_t below */
#ifndef GO_CGO_EXPORT_PROLOGUE_H
#define GO_CGO_EXPORT_PROLOGUE_H
#ifndef GO_CGO_GOSTRING_TYPEDEF
typedef struct { const char *p; ptrdiff_t n; } _GoString_;
#endif
#endif
/* Start of preamble from import "C" comments. */
/* End of preamble from import "C" comments. */
#ifdef __cplusplus
extern "C" {
#endif
extern void HelloWorld();
#ifdef __cplusplus
}
#endif
注意extern void HelloWorld();这一行。如果你的头文件缺少extern,需要手动修复。
正确的使用示例:
lib.go:
//go:build lib
// +build lib
package main
import "C"
import "fmt"
//export HelloWorld
func HelloWorld() {
fmt.Println("hello world")
}
func main() {}
编译共享库:
go build -tags lib -buildmode=c-shared -o libgolib.dylib lib.go
main.go:
//go:build app
// +build app
package main
// #cgo CFLAGS: -g -Wall
// #cgo LDFLAGS: -L. -lgolib
// #include "libgolib.h"
import "C"
func main() {
C.HelloWorld()
}
编译并运行:
go build -tags app -o app main.go
./app
对于Mac系统,共享库扩展名应为.dylib而不是.a。.a是静态库,.dylib是动态库。修改编译命令:
go build -tags lib -buildmode=c-shared -o libgolib.dylib lib.go
然后更新main.go中的链接标志:
// #cgo LDFLAGS: -L. -lgolib
// #include "libgolib.h"
如果问题仍然存在,尝试清理并重新构建:
rm -f *.h *.dylib
go build -tags lib -buildmode=c-shared -o libgolib.dylib lib.go
go build -tags app -o app main.go
对于VS Code的错误,可以尝试在终端中直接构建来验证CGO处理是否正常。

