Вызов функции golang из скрипта Tcl - PullRequest
0 голосов
/ 30 мая 2019

Мы используем стороннюю библиотеку синтаксического анализа Tcl для проверки сценария Tcl как для синтаксической, так и для семантической проверки.Драйвер был написан на C и определил набор служебных функций.Затем он вызывает Tcl_CreateObjCommand, чтобы скрипт мог вызывать эти функции языка Си.Сейчас мы находимся в процессе переноса основной программы, и я не смог найти способ сделать это.Кто-нибудь знает способ вызова функций Голанга из сценария Tcl?

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 Ответ

1 голос
/ 01 июня 2019

Предполагая, что вы установили соответствующие функции как экспортированные и создали части Go вашего проекта, как в

Использование кода Go в существующем проекте C

[...]

Важные вещи, на которые следует обратить внимание:

  • Пакет должен называться main
  • Вам нужна функция main, хотя она может быть пустой.
  • Вам необходимо импортировать пакет C
  • Вам нужны специальные //export комментарии, чтобы отметить функции, которые вы хотите вызвать из C.

Я могу скомпилировать ее как вызываемую статическую библиотеку C с помощью следующей команды:

go build -buildmode=c-archive foo.go

Тогда суть того, что еще нужно сделать, - написать функцию C glue из API Tcl в код Go. Это будет включать в себя что-то вроде:

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 (или нескольких критических пространств имен в нем).


Отображение сбоя в Tcl будет наиболее простым, если оно закодировано на уровне Go в качестве перечисления. Вероятно, проще всего представить успех как ноль. После этого вы сделаете:

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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...