【问题标题】:Cgo linker errors on C constantsC 常量上的 Cgo 链接器错误
【发布时间】:2013-10-08 04:50:24
【问题描述】:

我正在使用 cgo 包装一个 C 库并遇到了一组奇怪的链接器错误。我将问题归结为以下几点:

一个文件 header.h 包含

#ifndef HEADER_H
#define HEADER_H

#define CONSTANT1 ("")
#define CONSTANT2 ""
#define CONSTANT3 ((char*)0)
#define CONSTANT4 (char*)0

#endif /* HEADER_H */

并且 test.go 包含

package main

/*
#include "header.h"
*/
import "C"

func main() {
    _ = C.CONSTANT1
    _ = C.CONSTANT2
    _ = C.CONSTANT3
    _ = C.CONSTANT4
}

运行go run test.go 时出现以下错误:

# command-line-arguments
... _cgo_main.o:(.data.rel+0x0): undefined reference to `CONSTANT4'
... _cgo_main.o:(.data.rel+0x8): undefined reference to `CONSTANT3'
... _cgo_main.o:(.data.rel+0x10): undefined reference to `CONSTANT1'
collect2: ld returned 1 exit status

对此我有两个问题:

  1. 为什么链接器与预定义的常量有任何关系?
  2. 为什么CONSTANT1CONSTANT3CONSTANT4 显示为未定义,而不显示CONSTANT2

提前致谢。

*编辑:定义为其他值(例如整数)的常量可以正常工作。

*Edit2:使用 go 版本 go1.1.2 linux/amd64

*Edit3:失败的完整示例:

我正在使用 C OpenLDAP 库并希望使用 LDAP_SASL_SIMPLE 常量。它在ldap.h 中定义为

#define LDAP_SASL_SIMPLE    ((char*)0)
#define LDAP_SASL_NULL      ("")

LDAP_SASL_NULL 常量给出了同样的错误。

一个最小的演示 go 程序:

package main

/*
#cgo LDFLAGS: -lldap

#include <ldap.h>
*/
import "C"

func main() {
    _ = C.LDAP_SASL_SIMPLE
}

【问题讨论】:

  • 疯狂猜测;如果正确:Go 希望通过 ABI(正确的链接)访问数据,使用符号名称。这不是预处理器宏所做的。 (我可能错了,因为我从未使用过 Go。)
  • @FUZxxl(现在猜猜谁在不了解这些语言的情况下解决了几个 Java、Python 和 Lua“问题”...:P)
  • 嗯...我猜这是因为其他常量封装在大括号中或包含可能会使 cgo 混淆的强制转换。如果您能展示一个展示您的问题的最小完整示例,那就太好了。最好能链接到实际的库。
  • 备案:我删除的评论(原来是第二条)写着:@H2CO3 你是对的。我把它删除了,因为我被OP的问题弄糊涂了,并质疑了自己。
  • 您说其中一个常数有效,而另一个常数无效。哪一个起作用了?对于您提供的示例,我的原始示例适用。您需要在 Go 代码中重新定义常量。

标签: c linker go ld cgo


【解决方案1】:

我最初确实根据我认为 cgo 的工作方式回答了一些不同的问题。但是如果 CONSTANT2 被 cgo 识别,可能是不同的原因。请问:

  • 在库文件上运行工具nm 并判断输出是否包含CONSTANT2 或您引用的任何其他同时通过#define 建立的常量。一个库可能会同时声明一个 #define 常量作为全局符号来解决兼容性问题。

  • 如果可能,请提供您的问题的最小工作示例。这是一个可以由阅读您的帖子并展示您的问题的人编译的示例。您的问题看起来可能会错过一些重要的部分来回答它。例如,很高兴知道您遇到问题的实际库。


原答案

如果您使用#define,您不会建立编译器实际看到的任何内容。 #define 是一个预处理指令,在解析之前被删除。为了建立编译器(以及 cgo)可以看到的常量,实际声明它们:

const char *CONSTANT1 = "";
const char *CONSTANT2 = "";
const char *CONSTANT3 = (char*)0;
const char *CONSTANT4 = (char*)0;

如果您无法触摸页眉,通常您无能为力;您基本上必须在代码的 Go 部分中复制所有常量:

const (
     CONSTANT1 = "",
     CONSTANT2 = "",
     CONSTANT3 = nil,
     CONSTANT4 = nil,
 )

您可以尝试复杂的技巧,例如在您的 Go 代码上运行 cpp,但这可能会带来比解决问题更多的麻烦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 2012-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-07
    • 2011-10-24
    相关资源
    最近更新 更多