Cgo链接器在C常量上出现错误。

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

Cgo linker errors on C constants

问题

我正在使用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没有?

提前感谢。

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

*编辑2:使用的go版本为go1.1.2 linux/amd64。

*编辑3:一个完整的失败示例:

我正在使用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
}
英文:

I'm using cgo to wrap a C library and have run into a strange set of linker errors. I've boiled the problem down to the following:

A file header.h contains

#ifndef HEADER_H
#define HEADER_H

#define CONSTANT1 (&quot;&quot;)
#define CONSTANT2 &quot;&quot;
#define CONSTANT3 ((char*)0)
#define CONSTANT4 (char*)0

#endif /* HEADER_H */

And test.go contains

package main

/*
#include &quot;header.h&quot;
*/
import &quot;C&quot;

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

Upon running go run test.go I get the following error:

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

I have two questions about this:

  1. Why does the linker have anything to do with pre-defined constants?
  2. Why do CONSTANT1, CONSTANT3, CONSTANT4 show up as undefined, but not CONSTANT2?

Thanks in advance.

*Edit: Constants defined as other values (e.g. ints) work fine.

*Edit2: Using go version go1.1.2 linux/amd64

*Edit3: A complete example of failure:

I'm working with the C OpenLDAP library and would like to use the LDAP_SASL_SIMPLE constant. It's defined in ldap.h as

#define LDAP_SASL_SIMPLE	((char*)0)
#define LDAP_SASL_NULL		(&quot;&quot;)

The LDAP_SASL_NULL constant gives the same error.

A minimal demonstrative go program:

package main

/*
#cgo LDFLAGS: -lldap

#include &lt;ldap.h&gt;
*/
import &quot;C&quot;

func main() {
	_ = C.LDAP_SASL_SIMPLE
}

答案1

得分: 0

根据我对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,但这可能会引起更多麻烦,而不是解决问题。

英文:

I did originally answer something different based on how I thought cgo works. But if CONSTANT2 is recognized by cgo, something different might be the reason. Could you please:

  • run the tool nm on the library file and tell whether the output contains CONSTANT2 or any other constants you refer to that were at the same time established through #define. A library might declare a #define constant at the same time as a global symbol to get around compatibility issues.

  • provide a minimal working example of your problem if possible. This is, an example that can be compiled by someone who reads your post and exhibits your problem. Your question looks like it may miss some important parts to answer it. For instance, it would be nice to know the actual library you have problems with.


original answer

If you use #define, you do not establish anything the compiler will actually see. A #define is a preprocessing directive that is removed before parsing. To establish constants the compiler (and thus cgo) can see, actually declare them:

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

If you cannot touch the header, there is typically not much you can do; you basically have to duplicate all constants in the Go part of your code:

const (
     CONSTANT1 = &quot;&quot;,
     CONSTANT2 = &quot;&quot;,
     CONSTANT3 = nil,
     CONSTANT4 = nil,
 )

You could try complex tricks like running cpp over your Go code, but this is likely to cause more trouble than it would solve problems.

huangapple
  • 本文由 发表于 2013年10月2日 05:21:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/19126160.html
匿名

发表评论

匿名网友

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

确定