Директива #cgo pkg-config

Директива #cgo pkg-config позволяет автоматически получать флаги компиляции и линковки для системных библиотек через утилиту pkg-config. В качестве параметра указывается имя пакета, для которого нужно получить настройки. Директива упрощает интеграцию с популярными библиотеками, такими как GTK, GLib, SDL и другими.

Синтаксис

go// #cgo pkg-config: package-name
import "C"

Директива располагается в комментарии перед объявлением импорта C. При сборке пакета Go автоматически выполнит команду pkg-config --cflags package-name для получения флагов компилятора и pkg-config --libs package-name для флагов линковщика.

Пример со встроенной библиотекой

Давайте используем библиотеку libsqlite3 для работы с SQLite через pkg-config:

gopackage main

/*
#cgo pkg-config: sqlite3
#include <sqlite3.h>
#include <stdlib.h>
*/
import "C"
import (
  "fmt"
  "unsafe"
)

func main() {
  var db *C.sqlite3
  path := C.CString(":memory:")
  defer C.free(unsafe.Pointer(path))
  
  result := C.sqlite3_open(path, &db)
  if result != C.SQLITE_OK {
    fmt.Println("Failed to open database")
    return
  }
  defer C.sqlite3_close(db)
  
  fmt.Println("Database opened successfully")
}

Пример с несколькими пакетами

Можно указать несколько пакетов через пробел. Тогда флаги будут объединены:

gopackage main

/*
#cgo pkg-config: gtk+-3.0 glib-2.0
#include <gtk/gtk.h>
#include <glib.h>
*/
import "C"
import (
  "fmt"
)

func main() {
  version := C.gtk_get_major_version()
  fmt.Printf("GTK version: %d\n", version)
}

Условная компиляция

Директиву можно комбинировать с условиями для разных платформ:

gopackage main

/*
#cgo linux pkg-config: glib-2.0
#cgo darwin pkg-config: glib-2.0
#cgo windows pkg-config: glib-2.0
#include <glib.h>
*/
import "C"
import (
  "fmt"
)

func main() {
  major := C.glib_major_version()
  minor := C.glib_minor_version()
  micro := C.glib_micro_version()
  fmt.Printf("GLib version: %d.%d.%d\n", major, minor, micro)
}

Обработка ошибок

Если пакет не найден в системе, сборка завершится с ошибкой. Рассмотрим обработку такой ситуации:

gopackage main

/*
#cgo pkg-config: nonexistent-package
*/
import "C"
import (
  "fmt"
)

func main() {
  fmt.Println("This will fail to build")
}

Результат выполнения сборки:

go"package nonexistent-package not found"

Смотрите также

  • директиву #cgo CFLAGS,
    которая позволяет задать флаги компилятора напрямую
  • директиву #cgo LDFLAGS,
    которая позволяет задать флаги линковщика напрямую
  • раздел преамбулы cgo,
    где можно размещать произвольный C-код
  • раздел импорта "C",
    который обеспечивает связь между Go и C