在 Go 程序中使用 cgo 共享库
Using a cgo shared library in a Go program
试图测试 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 代码中收到以下错误
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
您不能在 Go 程序中使用 cgo 共享库,因为您不能在同一个进程中有多个 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 调用 c 代码,有 3 种可能的方法:
- 行内编码,如:
package main
//#include <stdio.h>
//int Add(int a, int b){
// printf("Welcome from external C function\n");
// return a + b;
//}
import "C"
import "fmt"
func main() {
fmt.Println(C.Add(5, 2))
}
- 静态链接,您同时拥有
.c
和 .h
文件,如:
// lib.c
#include <stdio.h>
int Add(int a, int b){
printf("Welcome from external C function\n");
return a + b;
}
和
// libadd.h
int Add(int, int);
Go 文件为:
// main.go
package main
// #include "libadd.h"
import "C"
import "fmt"
func main() {
x := C.Add(1, 2)
fmt.Println(x)
}
我们必须 运行 文件为 go run .
或 go run github.io/xxx
// go 运行 main.go 将不起作用,因为它只会考虑 main.go,而不考虑 C 文件
- 动态链接,将上面的
c
文件编译为 clang -shared -fpic -Wall -g lib.c -o libadd.so
并将 go 文件编译为:
// main.go
package main
//#cgo CFLAGS: -g -Wall
//#cgo LDFLAGS: -L. -ladd
//#include "libadd.h"
import "C"
import "fmt"
func main() {
x := C.Add(1, 2)
fmt.Println(x)
}
这里可以使用go run main.go
因为库是通过硬编码连接的,要分发二进制文件,共享库loadadd.so
需要用相同的二进制文件分发并且存在于同一个文件夹。
我为每个案例上传了单独的文件夹[此处][1]
奖金
要使用c程序在go中调用生成的共享库,我们可以使用如下:
// main.c
#include <stdio.h>
#include "libadd.h" // calling C file
#include "libgo.h" // calling shared library generated by GO
int main()
{
HelloWorld();
int x = Add(1, 2);
printf("%d",x);
return 0;
}
将文件编译为:
``bash
clang -o main -L. -ladd -lgo main.c // -ladd => -l(库)是 libadd
[1]: https://github.com/hajsf/tutorial/tree/master/ffi
试图测试 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 代码中收到以下错误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
您不能在 Go 程序中使用 cgo 共享库,因为您不能在同一个进程中有多个 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 调用 c 代码,有 3 种可能的方法:
- 行内编码,如:
package main
//#include <stdio.h>
//int Add(int a, int b){
// printf("Welcome from external C function\n");
// return a + b;
//}
import "C"
import "fmt"
func main() {
fmt.Println(C.Add(5, 2))
}
- 静态链接,您同时拥有
.c
和.h
文件,如:
// lib.c
#include <stdio.h>
int Add(int a, int b){
printf("Welcome from external C function\n");
return a + b;
}
和
// libadd.h
int Add(int, int);
Go 文件为:
// main.go
package main
// #include "libadd.h"
import "C"
import "fmt"
func main() {
x := C.Add(1, 2)
fmt.Println(x)
}
我们必须 运行 文件为 go run .
或 go run github.io/xxx
// go 运行 main.go 将不起作用,因为它只会考虑 main.go,而不考虑 C 文件
- 动态链接,将上面的
c
文件编译为clang -shared -fpic -Wall -g lib.c -o libadd.so
并将 go 文件编译为:
// main.go
package main
//#cgo CFLAGS: -g -Wall
//#cgo LDFLAGS: -L. -ladd
//#include "libadd.h"
import "C"
import "fmt"
func main() {
x := C.Add(1, 2)
fmt.Println(x)
}
这里可以使用go run main.go
因为库是通过硬编码连接的,要分发二进制文件,共享库loadadd.so
需要用相同的二进制文件分发并且存在于同一个文件夹。
我为每个案例上传了单独的文件夹[此处][1]
奖金 要使用c程序在go中调用生成的共享库,我们可以使用如下:
// main.c
#include <stdio.h>
#include "libadd.h" // calling C file
#include "libgo.h" // calling shared library generated by GO
int main()
{
HelloWorld();
int x = Add(1, 2);
printf("%d",x);
return 0;
}
将文件编译为: ``bash clang -o main -L. -ladd -lgo main.c // -ladd => -l(库)是 libadd
[1]: https://github.com/hajsf/tutorial/tree/master/ffi