C常量上的Cgo链接器错误

C常量上的Cgo链接器错误,c,linker,go,ld,cgo,C,Linker,Go,Ld,Cgo,我使用cgo包装一个C库,遇到了一组奇怪的链接器错误。我把问题归结为以下几点: 文件头.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 "heade

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

文件头.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运行测试时。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
关于这一点,我有两个问题:

  • 为什么链接器与预定义的常量有关
  • 为什么
    CONSTANT1
    CONSTANT3
    CONSTANT4
    显示为未定义,而不是
    CONSTANT2
  • 提前谢谢

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

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

    *Edit3:一个完整的失败示例:

    我正在使用C OpenLDAP库,并希望使用
    LDAP\u SASL\u SIMPLE
    常量。它在
    ldap.h
    中定义为

    #define LDAP_SASL_SIMPLE    ((char*)0)
    #define LDAP_SASL_NULL      ("")
    
    LDAP\u SASL\u NULL
    常量给出了相同的错误

    最低限度的演示性围棋程序:

    package main
    
    /*
    #cgo LDFLAGS: -lldap
    
    #include <ldap.h>
    */
    import "C"
    
    func main() {
        _ = C.LDAP_SASL_SIMPLE
    }
    
    主程序包
    /*
    #cgo LDFLAGS:-lldap
    #包括
    */
    输入“C”
    func main(){
    _=C.LDAP\u SASL\u SIMPLE
    }
    
    根据我认为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,但这可能会带来比解决问题更多的麻烦。

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