如何在 C 的多个包中重用 Go 回调?
How to reuse a Go callback in several packages from C?
有没有一种构建 Go + C 应用程序的方法:
- 从主包 X 导入包 Y 和 Z。
- 包 M 导出一个 go 回调 F。
- 包 X 和 Y 都是用随附的 C 文件构建的,都需要
从 C 源代码调用 F。
一般来说,我正在尝试弄清楚如何从用于构建最终应用程序的其他模块中的随附 C 文件调用回调。我不知道如何实现这个或类似的东西。我也对复杂的解决方案感兴趣。
这是一个示例,它将接受任何 go 回调(非线程安全)。
b.go:
package b
// typedef void (*cbFunc) ();
// void do_run(cbFunc);
// void goCallback();
import "C"
//export goCallback
func goCallback() {
if goCallbackHolder != nil {
goCallbackHolder()
}
}
var goCallbackHolder func()
func Run(callback func()) {
goCallbackHolder = callback
C.do_run(C.cbFunc(C.goCallback))
}
b.c:
#include "_cgo_export.h"
void do_run(void (*callback)())
{
callback();
}
我无法让它以简单的方式工作 IMO。
给定导入 Y
和 Z
的主包 X
,两者都必须调用(从 C 源代码)在包 M
中声明的 F
,
我不得不:
- 在
Y
中为 F
创建一个小包装器 W1
并将其导出以从 Y
的 C 源代码中调用。
- 在
Z
中为 F
创建一个小包装器 W2
并将其导出以从 Z
的 C 源代码中调用。
- 在
Y
CGO CPPFLAGS中定义-DCALLBACK=W1
- 在
Z
CGO CPPFLAGS中定义-DCALLBACK=W2
- 从任何地方的 C 源代码,我现在都可以将
F
称为 CALLBACK
(是的,在内部它是所有不同的东西,我指的是一次使用一个名称端调用另一端的单个函数)。
这很复杂,但它确实有效,尽管配置了这样的宏并生成了一些包装器
不理想。如果有人能详细说明一个更简单的程序,我会很高兴。一切
我试过以重复的符号或不可见的声明结束。
我没有看到跨包调用 Go 函数的方法,但所有 cgo 包都链接到同一个二进制文件中并且可以相互调用。这意味着您可以将 M.F 导出到包 M 中的 C 函数,并从包 Y 和 Z 中调用该 C 函数。
m/m.go:
package m
// void F();
import "C"
import "fmt"
//export F
func F() {
fmt.Println("m.f")
}
m/m.h:
void m_f();
m/m.c:
#include <stdio.h>
#include "_cgo_export.h"
#include "m.h"
void m_f() {
printf("m_f\n")
F();
}
y/y.go:
package y
// The LDFLAGS lines below are needed to prevent linker errors
// since not all packages are present while building intermediate
// packages. The darwin build tag is used as a proxy for clang
// versus gcc because there doesn't seem to be a better way
// to detect this.
// #cgo darwin LDFLAGS: -Wl,-undefined -Wl,dynamic_lookup
// #cgo !darwin LDFLAGS: -Wl,-unresolved-symbols=ignore-all
// #include "y.h"
import "C"
import (
"fmt"
_ "m"
)
func Y() {
fmt.Println("y.Y")
C.y()
}
y/y.h:
void y();
y/y.c:
#include <stdio.h>
#include "../m/m.h"
void y() {
printf("y.C.y\n");
m_f();
}
有没有一种构建 Go + C 应用程序的方法:
- 从主包 X 导入包 Y 和 Z。
- 包 M 导出一个 go 回调 F。
- 包 X 和 Y 都是用随附的 C 文件构建的,都需要 从 C 源代码调用 F。
一般来说,我正在尝试弄清楚如何从用于构建最终应用程序的其他模块中的随附 C 文件调用回调。我不知道如何实现这个或类似的东西。我也对复杂的解决方案感兴趣。
这是一个示例,它将接受任何 go 回调(非线程安全)。
b.go:
package b
// typedef void (*cbFunc) ();
// void do_run(cbFunc);
// void goCallback();
import "C"
//export goCallback
func goCallback() {
if goCallbackHolder != nil {
goCallbackHolder()
}
}
var goCallbackHolder func()
func Run(callback func()) {
goCallbackHolder = callback
C.do_run(C.cbFunc(C.goCallback))
}
b.c:
#include "_cgo_export.h"
void do_run(void (*callback)())
{
callback();
}
我无法让它以简单的方式工作 IMO。
给定导入 Y
和 Z
的主包 X
,两者都必须调用(从 C 源代码)在包 M
中声明的 F
,
我不得不:
- 在
Y
中为F
创建一个小包装器W1
并将其导出以从Y
的 C 源代码中调用。 - 在
Z
中为F
创建一个小包装器W2
并将其导出以从Z
的 C 源代码中调用。 - 在
Y
CGO CPPFLAGS中定义-DCALLBACK=W1
- 在
Z
CGO CPPFLAGS中定义-DCALLBACK=W2
- 从任何地方的 C 源代码,我现在都可以将
F
称为CALLBACK
(是的,在内部它是所有不同的东西,我指的是一次使用一个名称端调用另一端的单个函数)。
这很复杂,但它确实有效,尽管配置了这样的宏并生成了一些包装器 不理想。如果有人能详细说明一个更简单的程序,我会很高兴。一切 我试过以重复的符号或不可见的声明结束。
我没有看到跨包调用 Go 函数的方法,但所有 cgo 包都链接到同一个二进制文件中并且可以相互调用。这意味着您可以将 M.F 导出到包 M 中的 C 函数,并从包 Y 和 Z 中调用该 C 函数。
m/m.go:
package m
// void F();
import "C"
import "fmt"
//export F
func F() {
fmt.Println("m.f")
}
m/m.h:
void m_f();
m/m.c:
#include <stdio.h>
#include "_cgo_export.h"
#include "m.h"
void m_f() {
printf("m_f\n")
F();
}
y/y.go:
package y
// The LDFLAGS lines below are needed to prevent linker errors
// since not all packages are present while building intermediate
// packages. The darwin build tag is used as a proxy for clang
// versus gcc because there doesn't seem to be a better way
// to detect this.
// #cgo darwin LDFLAGS: -Wl,-undefined -Wl,dynamic_lookup
// #cgo !darwin LDFLAGS: -Wl,-unresolved-symbols=ignore-all
// #include "y.h"
import "C"
import (
"fmt"
_ "m"
)
func Y() {
fmt.Println("y.Y")
C.y()
}
y/y.h:
void y();
y/y.c:
#include <stdio.h>
#include "../m/m.h"
void y() {
printf("y.C.y\n");
m_f();
}