Предполагая, что вы установили соответствующие функции как экспортированные и создали части 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.