サーチ…


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"

重要includeimport "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 flag go build -o my_c_binding main.goを使用して、バイナリファイルに名前を付けることができます。

このチュートリアルを楽しんでいただければ幸いです。



Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow