Buscar..


Cgo: tutorial de primeros pasos.

Algunos ejemplos para entender el flujo de trabajo de usar los enlaces de Go C

Qué

En Go puedes llamar a programas y funciones C usando cgo . De esta manera, puede crear fácilmente enlaces C a otras aplicaciones o bibliotecas que proporcionen C API.

Cómo

Todo lo que necesita hacer es agregar una import "C" al comienzo de su programa Go justo después de incluir su programa C:

//#include <stdio.h>
import "C"

Con el ejemplo anterior puedes usar el paquete stdio en Go.

Si necesita usar una aplicación que esté en su misma carpeta, use la misma sintaxis que en C (con la " lugar de <> )

//#include "hello.c"
import "C"

IMPORTANTE : No deje una nueva línea entre las declaraciones de include y de import "C" o obtendrá este tipo de errores en la compilación:

# command-line-arguments
could not determine kind of name for C.Hello
could not determine kind of name for C.sum

El ejemplo

En esta carpeta puedes encontrar un ejemplo de enlaces en C. Tenemos dos "bibliotecas" de C muy simples llamadas hello.c :

//hello.c
#include <stdio.h>

void Hello(){
    printf("Hello world\n");
}

Eso simplemente imprime "hola mundo" en la consola y sum.c

//sum.c
#include <stdio.h>

int sum(int a, int b) {
    return a + b;
}

... eso toma 2 argumentos y devuelve su suma (no lo imprima).

Tenemos un programa main.go que hará uso de estos dos archivos. Primero los importamos como mencionamos antes:

//main.go
package main

/*
  #include "hello.c"
  #include "sum.c"
*/
import "C"

Hola Mundo!

Ahora estamos listos para usar los programas de C en nuestra aplicación Go. Primero probemos el programa 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
}

Ahora ejecute el programa main.go utilizando go run main.go para obtener la impresión del programa C: "¡Hola mundo!". ¡Bien hecho!

Suma de ints

Hagámoslo un poco más complejo agregando una función que sume sus dos argumentos.

//sum.c
#include <stdio.h>

int sum(int a, int b) {
  return a + b;
}

Y lo llamaremos desde nuestra aplicación Go anterior.

//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
}

Echa un vistazo a la función "makeSum". Recibe dos parámetros int que deben convertirse a C int antes utilizando la función C.int . Además, la devolución de la llamada nos dará una C int y un error en caso de que algo salga mal. Necesitamos lanzar una respuesta en C a un int de Go usando int() .

Intenta ejecutar nuestra aplicación go run main.go usando go run main.go

$ go run main.go
Hello world!
Sum of 5 + 4 is 9

Generando un binario

Si intentas una compilación de Go, podrías obtener múltiples errores de definición.

$ 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

El truco consiste en referirse directamente al archivo principal cuando se utiliza go build :

$ go build main.go
$ ./main
Hello world!
Sum of 5 + 4 is 9

Recuerde que puede proporcionar un nombre al archivo binario utilizando -o flag go build -o my_c_binding main.go

Espero que disfrutes este tutorial.



Modified text is an extract of the original Stack Overflow Documentation
Licenciado bajo CC BY-SA 3.0
No afiliado a Stack Overflow