サーチ…
Cgo:ファーストステップチュートリアル
Go Cバインディングを使用するワークフローを理解するための例
何
Goでは、 cgoを使用してCプログラムと関数を呼び出すことができます。これにより、C APIを提供する他のアプリケーションやライブラリへのCバインディングを簡単に作成できます。
どうやって
Cプログラムをインクルードした直後にGoプログラムの先頭にimport "C"
を追加するだけです。
//#include <stdio.h> import "C"
前の例では、Goでstdio
パッケージを使用できstdio
。
あなたが同じフォルダにあるアプリを使用する必要がある場合は、(とCよりも同じ構文を使用します"
の代わりに<>
)
//#include "hello.c" import "C"
重要 :
include
とimport "C"
文の間に改行を残さないでください。そうしないと、ビルド時にこのタイプのエラーが発生します。
# command-line-arguments could not determine kind of name for C.Hello could not determine kind of name for C.sum
例
このフォルダには、Cバインディングの例があります。 hello.c
という2つの非常にシンプルなCの "ライブラリ"があります。
//hello.c #include <stdio.h> void Hello(){ printf("Hello world\n"); }
これはコンソールとsum.c
"hello world"を表示するだけです
//sum.c #include <stdio.h> int sum(int a, int b) { return a + b; }
... 2つの引数をとり、その合計を返します(印刷しません)。
この2つのファイルを使用するmain.go
プログラムがあります。最初に、前述のようにインポートします。
//main.go package main /* #include "hello.c" #include "sum.c" */ import "C"
"こんにちは世界"
これでGoアプリでCプログラムを使用できるようになりました。最初にHelloプログラムを試してみましょう:
//main.go package main /* #include "hello.c" #include "sum.c" */ import "C" func main() { //Call to void function without params err := Hello() if err != nil { log.Fatal(err) } } //Hello is a C binding to the Hello World "C" program. As a Go user you could //use now the Hello function transparently without knowing that it is calling //a C function func Hello() error { _, err := C.Hello() //We ignore first result as it is a void function if err != nil { return errors.New("error calling Hello function: " + err.Error()) } return nil }
今使ってmain.goプログラムを実行してgo run main.go
Cプログラムの印刷を取得する:「!こんにちは、世界を」。よくやった!
intの合計
その2つの引数を合計する関数を追加することで、もう少し複雑にしましょう。
//sum.c #include <stdio.h> int sum(int a, int b) { return a + b; }
そして、我々は以前のGoアプリからそれを呼び出すでしょう。
//main.go package main /* #include "hello.c" #include "sum.c" */ import "C" import ( "errors" "fmt" "log" ) func main() { //Call to void function without params err := Hello() if err != nil { log.Fatal(err) } //Call to int function with two params res, err := makeSum(5, 4) if err != nil { log.Fatal(err) } fmt.Printf("Sum of 5 + 4 is %d\n", res) } //Hello is a C binding to the Hello World "C" program. As a Go user you could //use now the Hello function transparently without knowing that is calling a C //function func Hello() error { _, err := C.Hello() //We ignore first result as it is a void function if err != nil { return errors.New("error calling Hello function: " + err.Error()) } return nil } //makeSum also is a C binding to make a sum. As before it returns a result and //an error. Look that we had to pass the Int values to C.int values before using //the function and cast the result back to a Go int value func makeSum(a, b int) (int, error) { //Convert Go ints to C ints aC := C.int(a) bC := C.int(b) sum, err := C.sum(aC, bC) if err != nil { return 0, errors.New("error calling Sum function: " + err.Error()) } //Convert C.int result to Go int res := int(sum) return res, nil }
"makeSum"関数を見てください。これは、 C.int
関数を使用してC int
に変換する必要がある2つのint
パラメータをC.int
ます。また、呼び出しの戻り値はC int
を返し、何か問題が生じた場合にエラーを返します。 int()
を使用してGoのintにCレスポンスをキャストする必要があります。
go run main.go
を使ってgoアプリケーションを実行してみてください
$ go run main.go Hello world! Sum of 5 + 4 is 9
バイナリの生成
goビルドを試みると、複数の定義エラーが発生する可能性があります。
$ go build # github.com/sayden/c-bindings /tmp/go-build329491076/github.com/sayden/c-bindings/_obj/hello.o: In function `Hello': ../../go/src/github.com/sayden/c-bindings/hello.c:5: multiple definition of `Hello' /tmp/go-build329491076/github.com/sayden/c-bindings/_obj/main.cgo2.o:/home/mariocaster/go/src/github.com/sayden/c-bindings/hello.c:5: first defined here /tmp/go-build329491076/github.com/sayden/c-bindings/_obj/sum.o: In function `sum': ../../go/src/github.com/sayden/c-bindings/sum.c:5: multiple definition of `sum` /tmp/go-build329491076/github.com/sayden/c-bindings/_obj/main.cgo2.o:/home/mariocaster/go/src/github.com/sayden/c-bindings/sum.c:5: first defined here collect2: error: ld returned 1 exit status
トリックは、 go build
を使用するときにメインファイルを直接参照するgo build
です。
$ go build main.go $ ./main Hello world! Sum of 5 + 4 is 9
-o
flaggo build -o my_c_binding main.go
を使用して、バイナリファイルに名前を付けることができます。
このチュートリアルを楽しんでいただければ幸いです。