Я пытаюсь создать статический объект, написанный на Go, для взаимодействия с программой на C (скажем, модулем ядра или чем-то еще).
Я нашел документацию по вызову функций C из Go, но я не нашел много о том, как пойти другим путем. Я обнаружил, что это возможно, но сложно.
Вот что я нашел:
Сообщение в блоге о колбэках между C и Go
У кого-нибудь есть опыт с этим? Короче говоря, я пытаюсь создать модуль PAM, полностью написанный на Go.
c
shared-libraries
go
dynamic-linking
beatgammit
источник
источник
Ответы:
Вы можете назвать код Go из C. Это сложное предложение.
Процесс описан в сообщении в блоге, на которое вы ссылаетесь. Но я вижу, как это не очень полезно. Вот короткий фрагмент без лишних битов. Это должно сделать вещи немного яснее.
Порядок, в котором все вызывается, выглядит следующим образом:
Здесь следует помнить, что функция обратного вызова должна быть помечена
//export
комментарием на стороне Go и какextern
на стороне C. Это означает, что любой обратный вызов, который вы хотите использовать, должен быть определен внутри вашего пакета.Чтобы позволить пользователю вашего пакета предоставлять пользовательскую функцию обратного вызова, мы используем тот же подход, что и выше, но мы предоставляем пользовательский обработчик пользователя (который является просто обычной функцией Go) в качестве параметра, который передается в C сторона как
void*
. Затем он принимается обработчиком вызовов в нашем пакете и вызывается.Давайте использовать более сложный пример, с которым я сейчас работаю. В этом случае у нас есть функция C, которая выполняет довольно сложную задачу: она читает список файлов с USB-устройства. Это может занять некоторое время, поэтому мы хотим, чтобы наше приложение было уведомлено о своем прогрессе. Мы можем сделать это, передав указатель функции, который мы определили в нашей программе. Он просто отображает некоторую информацию о прогрессе пользователю всякий раз, когда его вызывают. Поскольку он имеет хорошо известную подпись, мы можем назначить ему собственный тип:
Этот обработчик получает некоторую информацию о ходе выполнения (текущее количество полученных файлов и общее количество файлов) вместе со значением интерфейса {}, которое может содержать все, что нужно пользователю.
Теперь нам нужно написать сантехнику C и Go, чтобы мы могли использовать этот обработчик. К счастью, функция C, которую я хочу вызвать из библиотеки, позволяет нам передавать структуру типа userdata
void*
. Это означает, что он может хранить то, что мы хотим, без вопросов, и мы вернем его обратно в мир Go как есть. Чтобы все это работало, мы не вызываем библиотечную функцию непосредственно из Go, но создаем для нее обертку C, которую мы назовемgoGetFiles()
. Именно эта обертка фактически передает наш обратный вызов Go в библиотеку C вместе с объектом пользовательских данных.Обратите внимание, что
goGetFiles()
функция не принимает никаких указателей на функции для обратных вызовов в качестве параметров. Вместо этого обратный вызов, предоставленный нашим пользователем, упакован в пользовательскую структуру, которая содержит и этот обработчик, и собственное значение пользовательских данных. Мы передаем это вgoGetFiles()
качестве параметра userdata.Вот и все для наших C-привязок. Код пользователя теперь очень прост:
Все это выглядит намного сложнее, чем есть. Порядок вызовов не изменился в отличие от нашего предыдущего примера, но мы получаем два дополнительных вызова в конце цепочки:
Порядок следующий:
источник
Это не запутанное предложение, если вы используете gccgo. Это работает здесь:
foo.go
bar.c
Makefile
источник
go package main func Add(a, b string) int { return a + b }
я получаю ошибку «undefined _go_string_plus»cgo
аgo
неgccgo
. Смотрите golang.org/cmd/cgo . Когда это сказано, вполне возможно использовать тип «string» в файле .go и изменить ваш файл .c, чтобы включить__go_string_plus
функцию. Это работает: ix.io/dZBОтвет изменился с выходом Go 1.5
Этот ТАК вопрос, который я задал некоторое время назад, снова решает проблему в свете добавленных возможностей 1.5
Использование кода Go в существующем проекте C
источник
Насколько я понимаю, это невозможно:
источник: https://github.com/golang/go/wiki/cgo
источник