2

我正在使用 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. 为什么CONSTANT1, CONSTANT3,CONSTANT4显示为未定义,但不是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
}
4

1 回答 1

0

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

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

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


原始答案

如果使用#define,则不会建立编译器实际看到的任何内容。A#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,但这可能会导致比解决问题更多的麻烦。

于 2013-10-01T21:38:42.413 回答