C常量上的Cgo链接器错误

时间:2013-10-01 21:21:21

标签: c linker go ld cgo

我正在使用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
  3. 提前致谢。

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

    * 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常量给出相同的错误。

    最小的示范性计划:

    package main
    
    /*
    #cgo LDFLAGS: -lldap
    
    #include <ldap.h>
    */
    import "C"
    
    func main() {
        _ = C.LDAP_SASL_SIMPLE
    }
    

1 个答案:

答案 0 :(得分:0)

我最初根据我认为cgo的工作原理回答了不同的问题。但是如果cgo识别出CONSTANT2,那么可能是不同的原因。你能不能请:

  • 在库文件上运行工具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,但这可能比解决问题更麻烦。