douqian9729 2019-05-30 20:13
浏览 247

从Tcl脚本调用golang函数

We use a third party Tcl parsing library to validation Tcl script for both syntax and semantic checking. The driver was written in C and defined a set of utility functions. Then it calls Tcl_CreateObjCommand so the script could call these C functions. Now we are in the process of porting the main program to go and I could not find a way to do this. Anyone know a way to call golang functions from Tcl script?

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;
}
  • 写回答

1条回答 默认 最新

  • dongluedeng1524 2019-06-01 06:59
    关注

    Assuming you've set the relevant functions as exported and built the Go parts of your project as in

    Using Go code in an existing C project

    […]

    The important things to note are:

    • The package needs to be called main
    • You need to have a main function, although it can be empty.
    • You need to import the package C
    • You need special //export comments to mark the functions you want callable from C.

    I can compile it as a C callable static library with the following command:

    go build -buildmode=c-archive foo.go
    

    Then the core of what remains to be done is to write the C glue function from Tcl's API to your Go code. That will involve a function something like:

    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;
    }
    

    (Credit to https://medium.com/learning-the-go-programming-language/calling-go-functions-from-other-languages-4c7d8bcc69bf for providing enough information for me to work out some of the type bindings.)

    That's then the function that you register with Tcl as the callback.

    Tcl_CreateObjCommand(interp, "ip_v4_address", ip_address_glue, (ClientData)AF_INET, NULL);
    

    Theoretically, a command registration can fail. Practically, that only happens when the Tcl interpreter (or a few critical namespaces within it) is being deleted.


    Mapping a failure into Tcl is going to be easiest if it is encoded at the Go level as an enumeration. Probably easiest to represent success as zero. With that, you'd then do:

    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;
    }
    

    Passing back more complex return types with tuples of values (especially a combination of a success indicator and a “real” result value) should also be possible, but I've not got a Go development environment in order to probe how they're mapped at the C level.

    评论

报告相同问题?

悬赏问题

  • ¥15 WPF使用Canvas绘制矢量图问题
  • ¥15 用三极管设计一个单管共射放大电路
  • ¥15 孟德尔随机化r语言运行问题
  • ¥15 pyinstaller编译的时候出现No module named 'imp'
  • ¥15 nirs_kit中打码怎么看(打码文件是csv格式)
  • ¥15 怎么把多于硬盘空间放到根目录下
  • ¥15 Matlab问题解答有两个问题
  • ¥15 LCD12864中文显示
  • ¥15 在使用CH341SER.EXE时不小心把所有驱动文件删除了怎么解决
  • ¥15 gsoap生成onvif框架