Search code examples
cgoldapcgo

Go cgo ldap_init could not determine kind of name for C.ldap_init


I was trying to learn and understand cgo. I am writing a program in Go where I connect to AD and parse the output. I tested the code in C, which is working fine as expected. The relevant part in C is

char *ldap_host = "x.x.x.x";
int   ldap_port     = 389;
ldap = ldap_init(ldap_host, ldap_port)) 

Now I am trying to get the same working in go as

//#cgo CFLAGS: -lldap 
//#include <ldap.h>
import "C"
func main() {
    var hostname *string
    hostname = &os.Args[1]
    ldap_port := 389
    ldap := C.ldap_init(*hostname, ldap_port)
}

But I am getting the following error

could not determine kind of name for C.ldap_init

What am I doing wrong here?


Solution

  • I would start by getting the basics of Go and cgo working before adding the individual peculiarities of a library like ldap. Some good starting points, especially the official cgo doc page.

    Starting from the top:

    You don't need the CFLAGS here, but you will need LDFLAGS for the linker, and liblber for this to run.

    #cgo LDFLAGS: -lldap -llber
    

    You can't pass a pointer to a Go string as a C *char, they are different types. Strings in Go actually aren't addressable at all, so this would be a compile error if the build process got that far. Use C.CString, and C.free if you need to create C strings. You will also need to include stdlib.h for C.free.

        url := C.CString(os.Args[1])
        defer C.free(unsafe.Pointer(url))
    

    Go's int size varies by architecture, and is not C's int type. ldap_port in your example is converted to the default type of int, where you would have needed C.int.

    Finally, the original error in your question has nothing to do with Go or cgo. The ldap_init function is deprecated, and does not exist without setting LDAP_DEPRECATED. You should use the ldap_initialize function. Here is a minimal example that compiles:

    package main
    
    import (
        "log"
        "unsafe"
    )
    
    /*
    #include <stdlib.h>
    #include <ldap.h>
    
    #cgo LDFLAGS: -lldap -llber
    */
    import "C"
    
    func main() {
        url := C.CString("ldap://127.0.0.1:389/")
        defer C.free(unsafe.Pointer(url))
    
        var ldap *C.LDAP
    
        rv := C.ldap_initialize(&ldap, url)
        if rv != 0 {
            log.Fatalf("ldap_initialize() error %d", rv)
        }
        log.Println("initialized")
    }