Go cgo ldap_init 无法确定 C.ldap_init 的名称类型。

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

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

问题

我正在尝试学习和理解cgo。
我正在用Go编写一个程序,其中我连接到AD并解析输出。我在C中测试了代码,按预期工作得很好。在C中的相关部分是:

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

现在我正在尝试在Go中实现相同的功能:

//#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)
}

但是我得到了以下错误:

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 = &quot;x.x.x.x&quot;;
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 &lt;ldap.h&gt;
import &quot;C&quot;
func main() {
    var hostname *string
    hostname = &amp;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?

答案1

得分: 4

我会开始先让Go和cgo的基础工作正常运行,然后再添加类似ldap这样的库的个别特性。一些很好的起点,尤其是官方的cgo文档页面。

从头开始:

这里不需要CFLAGS,但是你需要LDFLAGS来链接器,并且需要liblber才能运行。

#cgo LDFLAGS: -lldap -llber

你不能将Go字符串的指针传递给C的*char,它们是不同的类型。实际上,Go中的字符串根本不可寻址,所以如果构建过程到达这一步,这将是一个编译错误。使用C.CString,如果需要创建C字符串,则使用C.free。你还需要包含stdlib.h以使用C.free

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

Go的int大小因架构而异,不是C的int类型。你的示例中的ldap_port被转换为默认类型int,而你需要的是C.int

最后,你问题中的原始错误与Go或cgo无关。ldap_init函数已被弃用,并且在没有设置LDAP_DEPRECATED的情况下不存在。你应该使用ldap_initialize函数。这是一个可以编译的最小示例:

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")
}
英文:

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 (
	&quot;log&quot;
	&quot;unsafe&quot;
)

/*
#include &lt;stdlib.h&gt;
#include &lt;ldap.h&gt;

#cgo LDFLAGS: -lldap -llber
*/
import &quot;C&quot;

func main() {
	url := C.CString(&quot;ldap://127.0.0.1:389/&quot;)
	defer C.free(unsafe.Pointer(url))

	var ldap *C.LDAP

	rv := C.ldap_initialize(&amp;ldap, url)
	if rv != 0 {
		log.Fatalf(&quot;ldap_initialize() error %d&quot;, rv)
	}
	log.Println(&quot;initialized&quot;)
}

huangapple
  • 本文由 发表于 2016年2月8日 14:22:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/35263506.html
匿名

发表评论

匿名网友

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

确定