【问题标题】:How do you statically link a c library in go using cgo?你如何使用 cgo 在 go 中静态链接一个 c 库?
【发布时间】:2021-08-13 11:58:03
【问题描述】:

所以小组中有很多东西建议您可以在 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                <------- Exists
                 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

我做错了什么?

对于 ref,c 标头:

int x(int y);

和代码:

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

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

--

编辑:

不,-L 和 -l 也不起作用;实际上在 google group 上有一些具体的讨论,这个 (-l/blah/blah.a) 不适用于 cgo,正确的语法 is 实际上是省略 -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。

【问题讨论】:

  • 您在LDFLAGS: 之后缺少-L 吗?

标签: go cgo


【解决方案1】:

事实证明我的代码 100% 没问题;它是 Go 1.0 的副本;在 go 1.1 下这个工作。 在 go 1.0 下,它没有。

(我知道,回答我自己的问题有点蹩脚;但下面的 'use -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

【讨论】:

    【解决方案2】:

    你只需要链接 -Ldirectory -lgb。

    $ cat >toto.c
    int x( int y ) { return y+1; }
    $ cat >toto.h
    int x(int);
    $ gcc -O2 -c toto.c
    $ ar q libgb.a toto.o
    $ cat >test.go
    package main
    
    import "fmt"
    
    // #cgo CFLAGS: -I.
    // #cgo LDFLAGS: -L. -lgb 
    // #include <toto.h>
    import "C"
    
    func main() {
      fmt.Printf("Invoking c library...\n")
      fmt.Println("Done ", C.x(10) )
    }
    $ go build test.go
    $ ./test
    Invoking c library...
    Done  11
    

    【讨论】:

    • @Victor 是 cgo 查找要链接和调用的正确文件所必需的“元数​​据”
    【解决方案3】:

    将 Go 代码与动态 静态库链接的简单 Makefile:

    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
    

    bridge.go 中的指令:

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

    【讨论】:

    • 有趣的是,在-L . 下它会检查/usr/lib/
    【解决方案4】:

    试试:

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

    您错过了 LDFLAGS 指令中的 -l

    【讨论】:

    • 该死,希望这只是一个错字,除此之外我不明白为什么它不起作用
    • 你不是同时需要 -L/Users/doug/projects/c/go-bridge/build/ 和 -lgb 吗? (第一个属于LDFLAGS,第二个你通常放入LDLIBS)。
    猜你喜欢
    • 2014-09-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 1970-01-01
    • 2011-11-14
    相关资源
    最近更新 更多