вторник, 19 февраля 2013 г.

Go + C = cgo

       Иногда возникает задача использовать какую-нибуть C библиотеку из Go. К примеру мне понадобилось использовать ImageMagick. Но это в общем-то применимо к любой библиотеке написанной на C. В моем случае уже существовала Go обертка вокруг ImageMagick - Canvas
но в ней не было нужного мне метода - поэтому пришлось написать его самому.
       Попробую в кратце описать как это сделать.  Если вы хорошо владеете английским, лучше пропустить мой эпос и сразу читать оригинал:
    http://golang.org/doc/articles/c_go_cgo.html
    http://golang.org/cmd/cgo/
Если в кратце - то в Go есть специальный псевдо пакет C. Соответсвенно для того чтобы обратится к какой нибуть функции, описанной в C библиотеке, вам нужно подключить .h файл в котором описана эта функция:
/*
#include
*/
import "C"

Последняя строчка говорит Go компилятору что в этом пакете будут вызовы сишных функций и что необходимо специальным образом обрабатывать комментарии начинающиеся с #. Поэтому комментарий #include будет обработан как подключение заголовочного файла, и все символы, объявленные в нем будут добавлены в талицу символов псевдомодуля C. После этого вы сможете вызывать таким образом:
C.fputs(...)

Чтобы все это работало как надо нужно чтобы подключаемый заголовочный файл был установлен у вас в системе и компилятор мог его найти. То же самое относится непосредственно к самой библиотеке - линкер должен ее находить. Если что-то не находится, нужно с помощью специальных комментариев вида:

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo LDFLAGS: -lpng
указать соответсвенно компилятору и линкеру где лежат соответсвующие подключаемые файлы и файлы библиотек.
Еще одна особенность связанная с подключение C библиотек состоит в том что они в отличии от обычных пакетов Go, которые линкуются статически, подключаемые библиотеки линкуются динамически. Соответственно нужно чтобы подключаемая библиотека была установлена на том сервере где вы планируете запускать бинарник.

Еще одна особенность состоит в том что вам придется как в C - самостоятельно управлять памятью. Go runtime не имеет не малейшего представления о памяти которая была выделена с помощью сишных функций или где-то в недрах  сишной библиотеки - и поэтому вам необходимо самим освободить ее.
      Но если быть внимательным и понимать что делаешь - возможность подключать сишные библиотеки дает очень большие возможности. У меня это вот уже с месяц работает в продакшене - и очень даже успешно.