从Go代码中调用C函数指针作为回调函数。

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

Calling C function pointer as callback from Go code

问题

我尝试从Go函数中调用一个C函数指针作为回调,但是遇到了一个我不理解的链接器错误。

错误信息如下:

c:/mingw32/bin/../lib/gcc/i686-w64-mingw32/11.2.0/../../../../i686-w64-mingw32/bin/ld.exe: $WORK\b001\_x002.o: in function `bridge_int_int':
./test.go:6: multiple definition of `bridge_int_int'; $WORK\b001\_x001.o:/tmp/test.go:6: first defined here
collect2.exe: error: ld returned 1 exit status

我不明白这个多重定义问题是从哪里来的。

英文:

I try to call a C function pointer as a callback from a Go function but get a linker error I don't understand.

package main

/*
typedef void (*int_int)(int, int);
void bridge_int_int(int a, int b, int_int f){
	f(a, b);
}
*/
import "C"

//export IntIntCallback
func IntIntCallback(a, b C.int, cb C.int_int) {
	C.bridge_int_int(a, b, cb)
}

func main() {
	// Noop, required to make CGO happy: `-buildmode=c-*` requires exactly one
	// main package, which in turn needs a `main` function`.
}

The error is:

c:/mingw32/bin/../lib/gcc/i686-w64-mingw32/11.2.0/../../../../i686-w64-mingw32/bin/ld.exe: $WORK\b001\_x002.o: in function `bridge_int_int':
./test.go:6: multiple definition of `bridge_int_int'; $WORK\b001\_x001.o:/tmp/test.go:6: first defined here
collect2.exe: error: ld returned 1 exit status

I don't understand where this multiple definition problem comes from.

答案1

得分: 2

问题已解决。请参阅:https://pkg.go.dev/cmd/cgo#hdr-C_references_to_Go

在文件中使用//export会对前言产生限制:由于它被复制到两个不同的C输出文件中,它不能包含任何定义,只能包含声明。如果一个文件既包含定义又包含声明,那么两个输出文件将产生重复的符号,链接器将失败。为了避免这种情况,定义必须放在其他文件的前言中,或者放在C源文件中。

将以下代码移动到一个单独的.go文件中:

/*
typedef void (*int_int)(int, int);
void bridge_int_int(int a, int b, int_int f){
    f(a, b);
}
*/
import "C"

并将其更改为:

/*
typedef void (*int_int)(int, int);
extern bridge_int_int(int a, int b, int_int f);
}
*/
import "C"
...

在原始文件中解决了这个问题。

英文:

Problem solved. See: https://pkg.go.dev/cmd/cgo#hdr-C_references_to_Go

> Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not contain any definitions, only declarations. If a file contains both definitions and declarations, then the two output files will produce duplicate symbols and the linker will fail. To avoid this, definitions must be placed in preambles in other files, or in C source files.

Moving the following code into a separate .go file:

/*
typedef void (*int_int)(int, int);
void bridge_int_int(int a, int b, int_int f){
    f(a, b);
}
*/
import "C"

and changing it to

/*
typedef void (*int_int)(int, int);
extern bridge_int_int(int a, int b, int_int f);
}
*/
import "C"
...

in the original file solved the problem

huangapple
  • 本文由 发表于 2021年12月26日 00:54:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/70481474.html
匿名

发表评论

匿名网友

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

确定