C в Go программах

8 minute read

Статья, которая послужит памяткой о использовании сишного кода в программах на 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

Почитать по теме: