Pergunta

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 ("")
#define CONSTANT2 ""
#define CONSTANT3 ((char*)0)
#define CONSTANT4 (char*)0

#endif /* HEADER_H */

And test.go contains

package main

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

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'
... _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

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      ("")

The LDAP_SASL_NULL constant gives the same error.

A minimal demonstrative go program:

package main

/*
#cgo LDFLAGS: -lldap

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

func main() {
    _ = C.LDAP_SASL_SIMPLE
}
Foi útil?

Solução

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 = "";
const char *CONSTANT2 = "";
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 = "",
     CONSTANT2 = "",
     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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top