суббота, 13 июля 2019 г.

Команда cgo, использование cgo с командой go

Cgo позволяет создавать пакеты Go, которые вызывают C код.

Использование cgo с командой go

Чтобы использовать cgo, напишите обычный код Go, который импортирует псевдопакет "C". Затем код Go может ссылаться на типы, такие как C.size_t, переменные, такие как C.stdout, или функции, такие как C.putchar.

Если импорту "C" сразу предшествует комментарий, этот комментарий, называемый преамбулой, используется в качестве заголовка при компиляции частей C пакета. Например:

// #include <stdio.h>
// #include <errno.h>
import "C"

Преамбула может содержать любой код на C, включая объявления и определения функций и переменных. Затем они могут быть переданы из кода Go, как если бы они были определены в пакете "C". Могут использоваться все имена, объявленные в преамбуле, даже если они начинаются со строчной буквы. Исключение: на статические переменные в преамбуле нельзя ссылаться из кода Go; статические функции разрешены.

Смотрите примеры в $GOROOT/misc/cgo/stdio и $GOROOT/misc/cgo/gmp.

CFLAGS, CPPFLAGS, CXXFLAGS, FFLAGS и LDFLAGS могут быть определены с помощью псевдо-директив #cgo в этих комментариях для настройки поведения компилятора C, C++ или Fortran. Значения, определенные в нескольких директивах, объединяются вместе. Директива может включать список ограничений сборки, ограничивающих его действие системами, удовлетворяющими одному из ограничений. Например:

// #cgo CFLAGS: -DPNG_DEBUG=1
// #cgo amd64 386 CFLAGS: -DX86=1
// #cgo LDFLAGS: -lpng
// #include <png.h>
import "C"

В качестве альтернативы, CPPFLAGS и LDFLAGS можно получить с помощью инструмента pkg-config, используя директиву #cgo pkg-config:, за которой следуют имена пакетов. Например:

// #cgo pkg-config: png cairo
// #include <png.h>
import "C"

Инструмент pkg-config по умолчанию можно изменить, установив переменную среды PKG_CONFIG.

По соображениям безопасности разрешен только ограниченный набор флагов, в частности -D, -I и -l. Чтобы разрешить дополнительные флаги, установите для CGO_CFLAGS_ALLOW регулярное выражение, совпадающее с новыми флагами. Чтобы запретить флаги, которые в противном случае были бы разрешены, установите для CGO_CFLAGS_DISALLOW регулярное выражение, совпадающее с аргументами, которые должны быть запрещены. В обоих случаях регулярное выражение должно соответствовать полному аргументу: чтобы разрешить -mfoo=bar, используйте CGO_CFLAGS_ALLOW='-mfoo.*', А не только CGO_CFLAGS_ALLOW='-mfoo'. Переменные с одинаковыми именами управляют разрешенными CPPFLAGS, CXXFLAGS, FFLAGS и LDFLAGS.

Также по соображениям безопасности разрешен только ограниченный набор символов, в частности буквенно-цифровые символы и несколько символов, таких как '.', которые не будут интерпретироваться неожиданным образом. Попытки использовать запрещенные символы приведут к ошибке "malformed #cgo argument".

При сборке переменные среды CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS и CGO_LDFLAGS добавляются к флагам, полученным из этих директив. Флаги, специфичные для пакета, должны быть установлены с использованием директив, а не переменных среды, чтобы сборки работали в неизмененных средах. Флаги, полученные из переменных среды, не подпадают под ограничения безопасности, описанные выше.

Все директивы cgo CPPFLAGS и CFLAGS в пакете объединяются и используются для компиляции файлов C в этом пакете. Все директивы CPPFLAGS и CXXFLAGS в пакете объединяются и используются для компиляции файлов C++ в этом пакете. Все директивы CPPFLAGS и FFLAGS в пакете объединяются и используются для компиляции файлов Fortran в этом пакете. Все директивы LDFLAGS в любом пакете программы объединяются и используются во время соединения (link time). Все директивы pkg-config объединяются и отправляются в pkg-config одновременно для добавления к каждому соответствующему набору флагов командной строки.

Когда директивы cgo анализируются, любое вхождение строки ${SRCDIR} будет заменено абсолютным путем к каталогу, содержащему исходный файл. Это позволяет предварительно скомпилированным статическим библиотекам быть включенными в каталог пакета и правильно связанными. Например, если пакет foo находится в каталоге /go/src/foo:

// #cgo LDFLAGS: -L${SRCDIR}/libs -lfoo

Будет расширен до:

// #cgo LDFLAGS: -L/go/src/foo/libs -lfoo

Когда инструмент Go видит, что один или несколько файлов Go используют специальный импорт "C", он ищет другие не-Go файлы в каталоге и компилирует их как часть пакета Go. Любые файлы .c, .s или .S будут скомпилированы с помощью компилятора C. Любые файлы .cc, .cpp или .cxx будут скомпилированы с помощью компилятора C++. Любые файлы .f, .F, .for или .f90 будут скомпилированы с помощью компилятора fortran. Любые файлы .h, .hh, .hpp или .hxx не будут скомпилированы отдельно, но, если эти файлы заголовков будут изменены, пакет (включая его исходные файлы не из Go) будет перекомпилирован. Обратите внимание, что изменения файлов в других каталогах не приводят к перекомпиляции пакета, поэтому весь не-Go исходный код для пакета должен храниться в каталоге пакета, а не в подкаталогах. Компиляторы C и C++ по умолчанию могут быть изменены переменными среды CC и CXX соответственно; эти переменные среды могут включать параметры командной строки.

Инструмент cgo включен по умолчанию для собственных сборок в системах, где он должен работать. По умолчанию это отключено при кросс-компиляции. Вы можете управлять этим, установив переменную окружения CGO_ENABLED при запуске инструмента go: установите его в 1, чтобы разрешить использование cgo, и в 0, чтобы отключить его. Инструмент go установит ограничение сборки "cgo", если включен cgo. Специальный импорт "C" подразумевает ограничение сборки "cgo", как будто файл также говорит "// +build cgo". Поэтому, если cgo отключен, файлы, импортирующие "C", не будут создаваться инструментом go.

При кросс-компиляции вы должны указать кросс-компилятор C для использования cgo. Вы можете сделать это, установив универсальную переменную среды CC_FOR_TARGET или более конкретную переменную среды CC_FOR_${GOOS}_${GOARCH} (например, CC_FOR_linux_arm) при построении цепочки инструментов с помощью make.bash, или вы можете установить переменную среды CC в любое время когда вы запускаете инструмент Go.

Переменные окружения CXX_FOR_TARGET, CXX_FOR_${GOOS}_${GOARCH} и CXX работают аналогичным образом для кода C++.


Читайте также:


Комментариев нет:

Отправить комментарий