你如何使用cgo在Go语言中静态链接一个C库?

huangapple go评论137阅读模式
英文:

How do you statically link a c library in go using cgo?

问题

所以在该组中有一堆东西表明你可以在go中做到这一点(尽管在cgo文档中没有):

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...\n")
  C.x(10)
  fmt.Printf("Done\n")
}

然而,它似乎不起作用:

/var/folders/.../bridge.a(bridge.cgo2.o)(__TEXT/__text): x: not defined

使用动态库似乎可以正常工作,并且检查生成的文件,它实际上在其中有符号'x':

/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                <------- 存在
                 U dyld_stub_binder 
0000000100000d40 T start

但显然只是在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

我做错了什么?

参考一下c头文件:

int x(int y);

和代码:

#include <junk.h>
#include <stdio.h>

int x(int y) {
  printf("Hello World\n");
  return y;
}

--

编辑:

不,-L和-l也不起作用;实际上在谷歌组中有一些具体的讨论,即这个(-l/blah/blah.a)在cgo中不起作用,而正确的语法实际上是省略-l并只列出.a文件...但是,嘿,如果它起作用了,我肯定会使用它。但它没有:

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无法链接,因为你试图组合一组目标文件。

即。这个:

gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -o ... -l/path/libgb.a

永远不会在gcc下编译;你必须像这样链接静态库:

gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -o ... /path/libgb.a

即。绝对不是我缺少-l或-L。

英文:

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 &quot;fmt&quot;

// #cgo CFLAGS: -I/Users/doug/projects/c/go-bridge/include
// #cgo LDFLAGS: /Users/doug/projects/c/go-bridge/build/libgb.a
// #include &lt;junk.h&gt;
import &quot;C&quot;

func Run() {
  fmt.Printf(&quot;Invoking c library...\n&quot;)
  C.x(10)
  fmt.Printf(&quot;Done\n&quot;)
}

However, it doesn't seem to work:

/var/folders/.../bridge.a(bridge.cgo2.o)(__TEXT/__text): x: not defined

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                &lt;------- Exists
                 U dyld_stub_binder 
0000000100000d40 T start

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

What am I doing wrong?

For ref, the c header:

int x(int y);

And code:

#include &lt;junk.h&gt;
#include &lt;stdio.h&gt;

int x(int y) {
  printf(&quot;Hello World\n&quot;);
  return y;
}

--

Edit:

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

verbose version:

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

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.

ie. This:

gcc -I . -g -O2 -fPIC -m64 -pthread -fno-common -o ... -l/path/libgb.a

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

ie. It is absolutely not that I'm missing a -l or -L.

答案1

得分: 58

原来我的代码完全没问题;它是Go 1.0的一个副本;在Go 1.1下可以工作。
在Go 1.0下,它不行。

(我知道自己回答自己的问题有点蠢;但是下面的“使用-L -l”答案也不对;与那个无关)。

一个可行的解决方案示例在这里的github上,供以后遇到这个问题的人使用:

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

英文:

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.

(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).

A working solution example is up on github here for anyone who find's this question later:

https://github.com/shadowmint/go-static-linking

in short that looks like:

CGO_ENABLED=0 go build -a -installsuffix cgo -ldflags &#39;-s&#39; src/myapp/myapp.go

see also:
https://github.com/golang/go/issues/9344

答案2

得分: 13

你只需要使用-Ldirectory -lgb进行链接。

$ cat &gt;toto.c
int x( int y ) { return y+1; }
$ cat &gt;toto.h
int x(int);
$ gcc -O2 -c toto.c
$ ar q libgb.a toto.o
$ cat &gt;test.go
package main

import &quot;fmt&quot;

// #cgo CFLAGS: -I.
// #cgo LDFLAGS: -L. -lgb 
// #include &lt;toto.h&gt;
import &quot;C&quot;

func main() {
  fmt.Printf(&quot;调用C库...\n&quot;)
  fmt.Println(&quot;完成 &quot;, C.x(10) )
}
$ go build test.go
$ ./test
调用C库...
完成  11
英文:

You just have to link with -Ldirectory -lgb.

$ cat &gt;toto.c
int x( int y ) { return y+1; }
$ cat &gt;toto.h
int x(int);
$ gcc -O2 -c toto.c
$ ar q libgb.a toto.o
$ cat &gt;test.go
package main

import &quot;fmt&quot;

// #cgo CFLAGS: -I.
// #cgo LDFLAGS: -L. -lgb 
// #include &lt;toto.h&gt;
import &quot;C&quot;

func main() {
  fmt.Printf(&quot;Invoking c library...\n&quot;)
  fmt.Println(&quot;Done &quot;, C.x(10) )
}
$ go build test.go
$ ./test
Invoking c library...
Done  11

答案3

得分: 11

static:
gcc -c gb.c
ar -rcs libgb.a gb.o
go build -ldflags "-linkmode external -extldflags -static" bridge.go

dynamic:
gcc -shared -o libgb.so gb.c
go build bridge.go

Directives in bridge.go:

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lgb
#include "gb.h"
*/
import "C"
...

英文:

A straightforward Makefile to link Go code with a dynamic or static library:

static:
    gcc -c gb.c
    ar -rcs libgb.a gb.o
    go build -ldflags &quot;-linkmode external -extldflags -static&quot; bridge.go

dynamic:
    gcc -shared -o libgb.so gb.c
    go build bridge.go

Directives in bridge.go:

/*
#cgo CFLAGS: -I.
#cgo LDFLAGS: -L. -lgb
#include &quot;gb.h&quot;
*/
import &quot;C&quot;
...

答案4

得分: 0

你在LDFLAGS指令中漏掉了-l

英文:

Try:

// #cgo LDFLAGS: -l/Users/doug/projects/c/go-bridge/build/libgb.a

You missed the -l in the LDFLAGS directive.

huangapple
  • 本文由 发表于 2013年5月25日 14:21:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/16747021.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定