Go/Cgo:生成没有 Go 运行时函数定义的静态库

问题描述

有没有办法从 Go 代码生成 C 静态库,但没有 Go 运行时函数定义

理由

  • Project A 使用 go build -buildmode=c-archive,libA.a 创建 C 静态库。
  • 效果很好:project B 使用纯 C 语言,能够轻松创建可执行文件,与 libA.a 静态链接,一切正常。
  • 问题 1:project C 碰巧也使用 Go,但想使用 libA.a 作为常规 C 库。现在它有一个链接问题:Go 运行时函数,例如_cgo_panic 现在在 project C 运行时(因为它使用 Go)和 libA.a 中都有定义。
  • 问题 2:project D 使用纯 C,与 B 相同。但它想使用 project A 中的两个不同库,例如libA.a 和一些 libA2.a。遗憾的是,它也没有链接,因为现在在 libA.alibA2.a 中都定义了 Go 运行时函数

如果 project C 可以在没有 Go 运行时定义的情况下生成其库,那么 project Dproject A 面临的问题可以轻松解决Project C 可以只与 libA.a 链接Project D 将与 libA.alibA2.a 和一些包含所有 Go 运行时内容的定义的 libGo.a 链接

我尝试了什么:

  • 在“项目 C”级别使用链接器标志,例如 -Wl,--allow-multiple-deFinition。现在它的构建失败,并显示一条神秘消息“函数符号表未按程序计数器排序”。
  • 从“libA.a”中手动删除 go.o(因为它只是一个“ar”存档):不起作用,因为“go.o”还包含我导出的函数的实现,所以我删除了太多了。
  • 使用 go build -buildmode=c-shared。正如预期的那样,它生成一个使用另一种格式的动态库,所以我不能直接将它用作静态库。

客户端的任何解决方案(例如在链接阶段找到忽略 project C 的重复定义的正确方法)也将被视为有效答案。
如果提供足够的证据,我也可以接受否定的答案(无解)。

更新:查看相关问题 Is there a way to include multiple c-archive packages in a single binary

解决方法

正如您所发现的那样,在当前的实现中,多次使用 -buildmode=c-archive 并将结果放入多个共享库中是行不通的。基本问题是必须只有一个 Go 运行时,但您有多个运行时。使用 -buildmode=c-archive 时,无法隔离不同的运行时。

-buildmode=c-shared 库与 buildmode=c-archive 的不同之处在于它们是用 -Bsymbolic 构建的,这会强制它们的所有本地引用都是本地的。效果是我们有多个 Go 运行时,但它们不相互引用,因此不会混淆。

如果您的 C 代码不介意与 -Wl,-Bsymbolic 链接,您可以尝试添加 c-archive 以构建在 -Bsymbolic 中包含 Go 代码的每个共享库.

祝你好运。