C в Go программах
Статья, которая послужит памяткой о использовании сишного кода в программах на Go. Для профи тут мало чего интересного, но новичкам будет полезно.
Cgo
Go настолько замечательный язык, что его можно использовать не только вместо языка Си но и вместе с Си. Для этого есть специальная тулза cgo. И есть замечательная статья, которая объясняет основы использования cgo. Но там, как пример, приводится использование только стандартных библиотечных функций. В этой же статье я попытался показать маленький пример, как использовать cgo для работы со своими кусками сишного кода.
C в go
Для использования Си кода проще всего создать библиотеку, которую можно будет линковать с нашей программой.
Сперва напишем два файла: example.c
int x( int y ) {
return y+1;
}
и example.h:
int x(int);
Теперь компилируем и создаем нашу библиотеку, которую потом будем использовать.
$ gcc -O2 -c example.c
$ ar q libexample.a example.o
Название библиотеки должно начинаться с lib иначе линкер не сможет ее найти.
package main
// #cgo CFLAGS: -I.
// #cgo LDFLAGS: -L. -lexample
// #include <example.h>
import "C"
import "fmt"
func main() {
fmt.Printf("Invoking c library...\n")
fmt.Println("Done ", C.x(10) )
}
#cgo CFLAGS: -I.
- Добавляет каталог 'директория' в начало списка каталогов, используемых для поиска заголовочных файлов. #cgo LDFLAGS: -L. -lexample
- Флаги линковщика, которые указывают в какой папке следует искать библиотеки(-L.
) и какую библиотеку нужно подключать(-lexample
).
Следует обратить внимание, что импорт виртуального пакета "С" (import "C"
) проходит отдельно от импорта всех других пакетов. Кроме того, все комментарии с сишным кодом должны идти сразу над инструкцией импорта виртуального пакета "С", без пропуска строк.
Теперь попробуем собрать все вместе
$ go build test.go
$ ./test
Invoking c library...
Done 11
Вуаля! все прекрасно работает.
Go в C
Кроме использования Си в программах на Go, так же можно использовать Go в программах на Си.
package main
// extern void Use_In_C();
import "C"
import "fmt"
func main() {
C.Use_In_C()
}
//export UseInC
func UseInC() {
fmt.Println("UseInC()")
}
//export UseInC
- это наш хендлер, который мы будем использовать в Си коде.
Используем нашу Go функцию:
#include <stdio.h>
#include "_cgo_export.h"
void Use_In_C() {
UseInC();
}
Для того, чтобы собрать все это добро, проект должен обязательно находится в $GOPATH
или подпапке $GOPATH/src
. Если исходники лежать прям в корне $GOPATH
, то собираем все одной командой
$ go build .
Если в подпапке $GOPATH/src/projectname
, тогда собираем так:
$ go build projectname