é¢é£è¨äº
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側で定義した関数を設定) - いろいろ備忘録日記
GitHub - devlights/blog-summary: ブログ「いろいろ備忘録日記」のまとめ
æ¦è¦
以ä¸ãèªåç¨ã®ã¡ã¢ã§ãã
ä»åããè¤æ°åã«æ¸¡ã£ã¦ cgo ã«ã¤ãã¦ã¡ã¢ãã¦ãããã¨æãã¾ãã
cgo ã¯ãæåéãGoããCã«ã¢ã¯ã»ã¹ãããã¨ãåºæ¥ãããã«ãªããã®ãªã®ã§ãããã¨ã¦ã便å©ãªåé¢ãçµæ§ã¯ã»ãå¼·ãã®ã§ã¡ã¢ã§ãæ®ãã¦ãããªãã¨ããé ããæ¶ãã¦ãã¾ãããã ãªã£ã¦æãã¾ããã
Cgo is not Go
ã¨ããæ ¼è¨ããã£ããããã®ã§ãGoçéã§æ¨æºã§æ¨å¥¨ããã¦ããªãæè¡ããããã¾ãããããå®åã§ã¯Cè¨èªã§ä½æãããã©ã¤ãã©ãªãªã©ã¯å±±ã®ããã«ããã¾ãããã§ãããã¸ã§ã¯ãã®æ¹éã§Goã§ä½ãç´ããã¨ãåºæ¥ãªãå ´åãå¤ã ããã¾ãããã®ãããªå ´åã«é常ã«ä¾¿å©ã§ãã
ããããã®ãµã³ãã«ã¯ä»¥ä¸ã®ãªãã¸ããªã«ã¢ãããã¦ããã¾ãã®ã§ãè¯ããã°ãåèãã ããã
ä»å㯠cgoã¨dlopen颿°ã使ã£ã¦ãæ¢ã«åå¨ãã¦ããå ±æã©ã¤ãã©ãªå ã®æ¢å颿°ã¨å ¨ãåã颿°æ¸å¼ãæã¤é¢æ°ãcgoå´ã§å®ç¾©ãã¦ãå¼ã³åºããããã¯ãã¦ã¿ã¾ãã
dlopen颿°ã£ã¦ä½ï¼ã£ã¦æ¹ã¯ã以ä¸ãåç §ãã ããã¾ãã
ããã¯ããã¨ãã«ããå©ç¨ããã¾ããã
ä»åã®ãµã³ãã«ã¯ã¡ãã£ã¨ã½ã¼ã¹ãã¡ã¤ã«æ°ãå¤ãã®ã§ãå®å ¨çã®ãµã³ãã«ãã覧ã«ãªãããå ´å㯠try-golang-cgo 16.C_dlopen_dlsym ãåç §ãã ããã¾ãã
ãµã³ãã«
以ä¸ã®ãµã³ãã«ã¯ãäºã
size_t my_strlen(const char *s);
ã¨ãã颿°ãå®ç¾©ããã soãã¡ã¤ã« ããã (libclib.so) ãcgoå´ã§ my_strlen
颿°ãããã¯ãã¦è¿½å ã®æåãçµã¿è¾¼ãã¨ãããµã³ãã«ã«ãªãã¾ãã
dlopen.go
package dlopen /* #cgo LDFLAGS: -ldl #include <dlfcn.h> #include <stdlib.h> */ import "C" import ( "unsafe" ) func OpenLib(path string) unsafe.Pointer { var ( cPath = C.CString(path) cPathPtr = unsafe.Pointer(cPath) handle unsafe.Pointer ) defer C.free(cPathPtr) handle = C.dlopen(cPath, C.RTLD_LAZY) return handle } func GetSym(handle unsafe.Pointer, symbol string) unsafe.Pointer { var ( cSymbol = C.CString(symbol) cSymbolPtr = unsafe.Pointer(cSymbol) funcPtr unsafe.Pointer ) defer C.free(cSymbolPtr) // æ¬æ¥ãdlsym()ãå¼ã³åºãåã« dlerror() ãå¼ã³åºããã¨ã©ã¼ç¶æ ãã¯ãªã¢ãã¦ãã // dlsym()ãå¼ã³åºãããã®å¾ã«ãdlerror() ã§ã¨ã©ã¼ã確èªããã®ãæ£å½ãªæµãã§ããã岿 funcPtr = C.dlsym(handle, cSymbol) return funcPtr } func CloseLib(handle unsafe.Pointer) { // æ¬æ¥ãdlclose()ãå¼ã³åºãåã« dlerror() ãå¼ã³åºããã¨ã©ã¼ç¶æ ãã¯ãªã¢ãã¦ãã // dlclose()ãå¼ã³åºãããã®å¾ã«ãdlerror() ã§ã¨ã©ã¼ã確èªããã®ãæ£å½ãªæµãã§ããã岿 C.dlclose(handle) }
gofuncs.go
package main /* extern size_t call_my_strlen(void *fn, const char *s); */ import "C" import ( "log" "unsafe" "github.com/devlights/try-golang-cgo/16.C_dlopen_dlsym/dlopen" ) //export my_strlen func my_strlen(cStr *C.char) C.size_t { var ( handle unsafe.Pointer symbol unsafe.Pointer result C.size_t ) handle = dlopen.OpenLib("clib/libclib.so") defer dlopen.CloseLib(handle) symbol = dlopen.GetSym(handle, "my_strlen") result = C.call_my_strlen(symbol, cStr) log.Printf("[Go][ã¤ã³ã¿ã¼ã»ãã][my_strlen] result=%v", result) return result }
cfuncs.go
package main /* size_t call_my_strlen(void *fn, const char *s) { size_t (*my_strlen_fn)(const char *); my_strlen_fn = (size_t (*)(const char *))fn; return my_strlen_fn(s); } */ import "C"
main.c
#include <stdio.h> #include "clib/lib.h" int main() { printf("[ C] my_strlen=%zu\n", my_strlen("helloworld")); }
Taskfile.yml
# https://taskfile.dev version: '3' vars: CAPP_NAME: capp tasks: default: cmds: - task: build-clib - task: build-golib - task: build-cprg - LD_LIBRARY_PATH=. ./{{.CAPP_NAME}} - task: build-cprg-original - LD_LIBRARY_PATH=clib ./{{.CAPP_NAME}} build-clib: dir: clib cmds: - gcc -fPIC -shared -o libclib.so lib.c build-golib: cmds: - go build -o libgolib.so -buildmode=c-shared *.go build-cprg: cmds: - gcc -c -o main.o main.c - gcc -o {{.CAPP_NAME}} main.o -L. -Lclib -lgolib -lclib build-cprg-original: cmds: - gcc -o {{.CAPP_NAME}} main.o -L. -Lclib -lclib
å®è¡
$ task task: [build-clib] gcc -fPIC -shared -o libclib.so lib.c task: [build-golib] go build -o libgolib.so -buildmode=c-shared *.go task: [build-cprg] gcc -c -o main.o main.c task: [build-cprg] gcc -o capp main.o -L. -Lclib -lgolib -lclib task: [default] LD_LIBRARY_PATH=. ./capp [Go][ã¤ã³ã¿ã¼ã»ãã][my_strlen] result=10 [ C] my_strlen=10 task: [build-cprg-original] gcc -o capp main.o -L. -Lclib -lclib task: [default] LD_LIBRARY_PATH=clib ./capp [ C] my_strlen=10
ã¡ããã¨ã¤ã³ã¿ã¼ã»ãããã¦å 颿°ããã³ã¤ã¤ãã°ãåºåãã¦ãã¾ããã
åèæ å ±
- C? Go? Cgo!
- Go Wiki: cgo
- cmd/cgo
- runtime/cgo
- cgoã使ã£ãCã¨Goã®ãªã³ã¯ã®è£å´ (1)
- cgoã使ã£ãCã¨Goã®ãªã³ã¯ã®è£å´ (2)
- ebitengine/purego
- JupiterRider/ffi
Goã®ããããæ¸ç±
éå»ã®è¨äºã«ã¤ãã¦ã¯ã以ä¸ã®ãã¼ã¸ãããåç §ä¸ããã
ãµã³ãã«ã³ã¼ãã¯ã以ä¸ã®å ´æã§å ¬éãã¦ãã¾ãã