如何使用 cgo 在 go 中静态链接 c 库? [英] How do you statically link a c library in go using cgo?
问题描述
因此,该组中有很多内容表明您可以在 go 中执行此操作(尽管 cgo 文档中没有):
So there's a bunch of stuff on the group that suggests you can do this in go (although not on the cgo documentation):
package bridge
import "fmt"
// #cgo CFLAGS: -I/Users/doug/projects/c/go-bridge/include
// #cgo LDFLAGS: /Users/doug/projects/c/go-bridge/build/libgb.a
// #include <junk.h>
import "C"
func Run() {
fmt.Printf("Invoking c library...
")
C.x(10)
fmt.Printf("Done
")
}
但是,它似乎不起作用:
However, it doesn't seem to work:
/var/folders/.../bridge.a(bridge.cgo2.o)(__TEXT/__text): x: not defined
使用动态库似乎可以正常工作,并检查生成的文件,它实际上在那里有符号x":
This seems to work fine using a dynamic library, and inspecting the generated files, it actually has the symbol 'x' in there:
/var/folders/rg/hj4s3qlj3sz1d1b5p50ws0vc0000gn/T/go-build442792776/bridge/_obj/_cgo_.o:
0000000100001048 S _NXArgc
0000000100001050 S _NXArgv
0000000100001060 S ___progname
0000000100000dc0 T __cgo_2d7eefe3d6d4_Cfunc_x
0000000100000da0 T __cgo_allocate
0000000100000db0 T __cgo_panic
0000000100000000 T __mh_execute_header
0000000100000d90 T _crosscall2
0000000100001058 S _environ
U _exit
0000000100000d80 T _main
U _puts
0000000100001000 s _pvars
0000000100000de0 T _x <------- Exists
U dyld_stub_binder
0000000100000d40 T start
但显然只是bridge.cgo2.o中的一个标记:
but obviously is just a marker in bridge.cgo2.o:
/var/folders/rg/hj4s3qlj3sz1d1b5p50ws0vc0000gn/T/go-build442792776/bridge.a(bridge.cgo2.o):
0000000000000368 s EH_frame0
0000000000000000 T __cgo_2d7eefe3d6d4_Cfunc_x
0000000000000380 S __cgo_2d7eefe3d6d4_Cfunc_x.eh
U _x
我做错了什么?
对于 ref,c 标头:
For ref, the c header:
int x(int y);
和代码:
#include <junk.h>
#include <stdio.h>
int x(int y) {
printf("Hello World
");
return y;
}
--
不,-L 和 -l 也不起作用;实际上在 google group 上有一些具体的讨论,这个 (-l/blah/blah.a) 不适用于 cgo,而正确的语法 实际上是省略 -l 并只列出.a 文件...但是嘿,如果它有效,我完全会使用它.但它没有:
No, -L and -l don't work either; there's actually some specific discussion on the google group that this (-l/blah/blah.a) does not work for cgo, and the correct syntax is in fact to omit the -l and just list the .a file... but hey, if it'd worked, I'd totally just use it. But it doesn't:
dougs-mini:go doug$ go run test.go
# bridge
ld: library not found for -l/Users/doug/projects/c/go-bridge/build/libgb.a
collect2: ld returned 1 exit status
dougs-mini:go doug$ ls -l /Users/doug/projects/c/go-bridge/build/libgb.a
-rw-r--r-- 1 doug staff 872 25 May 14:02 /Users/doug/projects/c/go-bridge/build/libgb.a
详细版本:
dougs-mini:go doug$ go build -work -x test.go
WORK=/var/folders/rg/hj4s3qlj3sz1d1b5p50ws0vc0000gn/T/go-build354497708
mkdir -p $WORK/bridge/_obj/
cd /Users/doug/projects/c/go-bridge/go/src/bridge
/Users/doug/projects/go/go/pkg/tool/darwin_amd64/cgo -objdir $WORK/bridge/_obj/ -- -I/Users/doug/projects/c/go-bridge/include -I $WORK/bridge/_obj/ bridge.go
/Users/doug/projects/go/go/pkg/tool/darwin_amd64/6c -FVw -I $WORK/bridge/_obj/ -I /Users/doug/projects/go/go/pkg/darwin_amd64 -o $WORK/bridge/_obj/_cgo_defun.6 -DGOOS_darwin -DGOARCH_amd64 $WORK/bridge/_obj/_cgo_defun.c
gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -I/Users/doug/projects/c/go-bridge/include -I $WORK/bridge/_obj/ -o $WORK/bridge/_obj/_cgo_main.o -c $WORK/bridge/_obj/_cgo_main.c
gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -I/Users/doug/projects/c/go-bridge/include -I $WORK/bridge/_obj/ -o $WORK/bridge/_obj/_cgo_export.o -c $WORK/bridge/_obj/_cgo_export.c
gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -I/Users/doug/projects/c/go-bridge/include -I $WORK/bridge/_obj/ -o $WORK/bridge/_obj/bridge.cgo2.o -c $WORK/bridge/_obj/bridge.cgo2.c
gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -o $WORK/bridge/_obj/_cgo_.o $WORK/bridge/_obj/_cgo_main.o $WORK/bridge/_obj/_cgo_export.o $WORK/bridge/_obj/bridge.cgo2.o -l/Users/doug/projects/c/go-bridge/build/libgb.a
# bridge
ld: library not found for -l/Users/doug/projects/c/go-bridge/build/libgb.a
collect2: ld returned 1 exit status
值得注意的是,当您尝试像这样(使用 -l)链接时失败是典型的 gcc 链接失败,因为您试图组合一组目标文件.
It's worth noting that the failure when you try to link like this (using -l) is typical of gcc failing to link because you're attempting to combine a set of object files.
即.这:
gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -o ... -l/path/libgb.a
永远不会在gcc下编译;你必须像这样链接一个静态库:
Will never compile under gcc; you must link a static library like this:
gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -o ... /path/libgb.a
即.绝对不是我缺少 -l 或 -L.
ie. It is absolutely not that I'm missing a -l or -L.
推荐答案
结果我的代码 100% 没问题;它是 Go 1.0 的副本;在 go 1.1 下这有效.在 go 1.0 下,它不会.
Turns out my code is 100% fine; it was a copy of Go 1.0; under go 1.1 this works. Under go 1.0, it doesn't.
(我知道,回答我自己的问题有点蹩脚;但是下面的使用 -L -l 答案也不正确;这与此无关).
(it's a bit lame answering my own question, I know; but the 'use -L -l answers below aren't right either; it had nothing to do with that).
github 上提供了一个可行的解决方案示例,供以后发现此问题的任何人使用:
A working solution example is up on github here for anyone who find's this question later:
https://github.com/shadowmint/go-static-linking
简而言之:
CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags '-s' src/myapp/myapp.go
另见:https://github.com/golang/go/issues/9344
这篇关于如何使用 cgo 在 go 中静态链接 c 库?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!