我们使用第三方Tcl解析库来验证Tcl脚本的语法和语义检查。该驱动程序是用C编写的,并定义了一组实用程序功能。然后它调用Tcl_CreateObjCommand
,因此脚本可以调用这些C函数。现在我们正在移植要运行的主程序,而我找不到执行此操作的方法。有谁知道从Tcl脚本调用golang函数的方法吗?
static int
create_utility_tcl_cmds(Tcl_Interp* interp)
{
if (Tcl_CreateObjCommand(interp, "ip_v4_address",
ip_address, (ClientData)AF_INET, NULL) == NULL) {
TCL_CHECKER_TCL_CMD_EVENT(0, "ip_v4_address");
return -1;
}
.....
return 0;
}
答案 0 :(得分:1)
假设您已将相关功能设置为已导出,并像
中那样构建了项目的Go部分。[…]
要注意的重要事项是:
- 该软件包需要命名为
main
- 您需要具有
main
函数,尽管它可以为空。- 您需要导入软件包
C
- 您需要特殊的
//export
注释来标记要从C调用的函数。我可以使用以下命令将其编译为C可调用静态库:
go build -buildmode=c-archive foo.go
然后要做的核心是从Tcl的API向您的Go代码编写C胶水功能。这将涉及到类似以下的功能:
static int ip_address_glue(
ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *const *objv) {
// Need an explicit cast; ClientData is really void*
GoInt address_family = (GoInt) clientData;
// Check for the right number of arguments
if (objc != 2) {
Tcl_WrongNumArgs(interp, 1, objv, "address");
return TCL_ERROR;
}
// Convert the argument to a Go string
GoString address;
int len;
address.p = Tcl_GetStringFromObj(objv[1], &len);
address.n = len; // This bit is hiding a type mismatch
// Do the call; I assume your Go function is called ip_address
ip_address(address_family, address);
// Assume the Go code doesn't fail, so no need to map the failure back to Tcl
return TCL_OK;
}
(向https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf致谢,以为我提供足够的信息来解决某些类型绑定。)
这就是您在Tcl中注册为回调的函数。
Tcl_CreateObjCommand(interp, "ip_v4_address", ip_address_glue, (ClientData)AF_INET, NULL);
理论上,命令注册可能会失败。实际上,只有在删除Tcl解释器(或其中的一些关键名称空间)时,这种情况才会发生。
如果在Go级别将其编码为枚举,则将故障映射到Tcl将是最容易的。可能最容易将成功表示为零。这样,您就可以这样做:
GoInt failure_code = ip_address(address_family, address);
switch (failure_code) {
case 0: // Success
return TCL_OK;
case 1: // First type of failure
Tcl_SetResult(interp, "failure of type #1", TCL_STATIC);
return TCL_ERROR;
// ... etc for each expected case ...
default: // Should be unreachable, yes?
Tcl_SetObjResult(interp, Tcl_ObjPrintf("unexpected failure: %d", failure_code));
return TCL_ERROR;
}
也可以传递带有元组值(特别是成功指标和“实际”结果值的组合)的更复杂的返回类型,但是我没有Go开发环境来探究它们的方式在C级别映射。