関連記事
Goメモ-502 (cgoメモ-01)(cgoヘッダ) - いろいろ備忘録日記
Goメモ-506 (cgoメモ-02)(cgoヘッダ) - いろいろ備忘録日記
Goメモ-507 (cgoメモ-03)(C.int) - いろいろ備忘録日記
Goメモ-508 (cgoメモ-04)(C言語の構造体) - いろいろ備忘録日記
Goメモ-509 (cgoメモ-05)(C.CString)(Cの文字列) - いろいろ備忘録日記
Goメモ-510 (cgoメモ-06)(C.GoString)(Cの文字列をGoの文字列へ) - いろいろ備忘録日記
Goメモ-511 (cgoメモ-07)(C.CBytes)([]byteをCのバイト列に) - いろいろ備忘録日記
Goメモ-512 (cgoメモ-08)(C.GoBytes)(Cのバイト列をGoの[]byteへ) - いろいろ備忘録日記
Goメモ-514 (cgoメモ-09)(C.GoStringN)(C.GoStringのサイズ指定版) - いろいろ備忘録日記
Goメモ-515 (cgoメモ-10)([]byteを(void *)へ変換) - いろいろ備忘録日記
Goメモ-516 (cgoメモ-11)([]byteを(char *)へ変換) - いろいろ備忘録日記
Goメモ-518 (cgoメモ-12)(Cのmallocをcgo経由で呼び出し) - いろいろ備忘録日記
Goメモ-519 (cgoメモ-13)(ポインタ演算) - いろいろ備忘録日記
Goメモ-520 (cgoメモ-14)(Goの関数をCの世界に公開 (export)) - いろいろ備忘録日記
Goメモ-522 (cgoメモ-15)(Goでsoファイルを作成してC言語から呼び出し) - いろいろ備忘録日記
Goメモ-525 (cgoメモ-16)(C側にて関数ポインタを引数に要求する関数にGo側で定義した関数を設定) - いろいろ備忘録日記
Goメモ-526 (cgoメモ-17)(cgoとdlopen関数を使って既存ライブラリの呼び出しをフックする) - いろいろ備忘録日記
Goメモ-527 (cgoメモ-18)(cgoを利用している場合のinit関数について) - いろいろ備忘録日記
Goメモ-528 (cgoメモ-19)(cgoを利用して作成したsoファイル経由でのinit関数の呼び出し) - いろいろ備忘録日記
Goメモ-529 (cgoメモ-20)(C言語のNULLをcgoから渡す) - いろいろ備忘録日記
Goメモ-530 (cgoメモ-21)(CGOヘッダーで指定出来るCFLAGS, LDFLAGS) - いろいろ備忘録日記
Goメモ-531 (cgoメモ-22)(CGOで利用するコンパイラを変更する) - いろいろ備忘録日記
Goメモ-532 (cgoメモ-23)(CGOヘッダで使えるSRCDIR変数) - いろいろ備忘録日記
Goメモ-534 (cgoメモ-24)(C側の構造体にて固定要素数の文字配列をGo側で文字列に変換) - いろいろ備忘録日記
Goメモ-535 (cgoメモ-25)(cgo.Handleを用いてCとGoの間で値をやり取りする) - いろいろ備忘録日記
Goメモ-536 (cgoメモ-26)(C側の構造体をGo側で利用する) - いろいろ備忘録日記
Goメモ-537 (cgoメモ-27)(Go側でCの構造体のサイズを知る方法) - いろいろ備忘録日記
Goメモ-539 (cgoメモ-28)(Go側でCの文字列リスト(**char)を扱う) - いろいろ備忘録日記
Goメモ-623 (cgoメモ-29)(memcpyの呼び出し) - いろいろ備忘録日記
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
概要
以下、自分用のメモです。
今回から複数回に渡って cgo についてメモしていこうと思います。
cgo は、文字通りGoからCにアクセスすることが出来るようになるものなのですが、とても便利な反面、結構クセが強いのでメモでも残しておかないとすぐ頭から消えてしまいそうだなって思いました。
Cgo is not Go
という格言があったりするので、Go界隈で標準で推奨されていない技術かもしれません。が、実務ではC言語で作成されたライブラリなどは山のようにあります。んで、プロジェクトの方針でGoで作り直すことも出来ない場合も多々あります。そのような場合に非常に便利です。
これからのサンプルは以下のリポジトリにアップしてありますので、良ければご参考ください。
今回は C言語でおなじみの静的ライブラリファイルの作成との呼び出しについて。
go build コマンドに -buildmode=c-archive オプションを付けて実行すると、GoのコードはC言語互換のヘッダファイル(.h)と静的ライブラリファイル(.a)を生成します。
サンプル
main.go
package main /* #cgo CFLAGS: -g3 -O0 -Wall -Wextra -fPIC #cgo CPPFLAGS: -I. */ import "C" //export cgo_func func cgo_func(x, y C.int, z *C.int) C.int { var ( goX = int(x) goY = int(y) ans = goX + goY ) *z = C.int(ans) return C.int(0) } func main() {}
app.c
#include <stdio.h> #include <stdlib.h> #include <string.h> extern int cgo_func(int x, int y, int *z); int main(void) { int x = 0x00FF; int y = 0xFF00; int z; cgo_func(x, y, &z); printf("%d\n", z); return EXIT_SUCCESS; }
Taskfile.yml
# https://taskfile.dev version: "3" vars: APP: app LIB: liba.a tasks: default: cmds: - task: clean - task: build - task: verify - task: run run: cmds: - ./{{.APP}} env: LD_LIBRARY_PATH: . build: cmds: - go build -a -x -o {{.LIB}} -buildmode=c-archive main.go > out.txt 2>&1 - gcc -g3 -O0 -Wall -Wextra -I. -L. -o {{.APP}} {{.APP}}.c -la verify: cmds: - nm ./{{.LIB}} | grep -F "T cgo_func" - nm ./{{.APP}} | grep -F "T cgo_func" clean: cmds: - rm -f {{.APP}} {{.LIB}}
実行
$ task task: [clean] rm -f app liba.a task: [build] go build -a -x -o liba.a -buildmode=c-archive main.go > out.txt 2>&1 task: [build] gcc -g3 -O0 -Wall -Wextra -I. -L. -o app app.c -la task: [verify] nm ./liba.a | grep -F "T cgo_func" 0000000000000000 T cgo_func task: [verify] nm ./app | grep -F "T cgo_func" 00000000000193e9 T cgo_func task: [run] ./app 65535
参考情報
- C? Go? Cgo!
- Go Wiki: cgo
- cmd/cgo
- runtime/cgo
- cgoを使ったCとGoのリンクの裏側 (1)
- cgoを使ったCとGoのリンクの裏側 (2)
- ebitengine/purego
- JupiterRider/ffi
個人的Goのおすすめ書籍
個人的に読んでとても勉強になった書籍さんたちです。
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。






