简体   繁体   中英

Using a cgo shared library in a Go program

Trying to test cgo , so I wrote the below:

//go:build lib
// +build lib

package main

import "C"
import "fmt"

//export HelloWorld
func HelloWorld() {
    fmt.Printf("hello world")
}

func main() {}

// go build -tags lib -buildmode=c-shared -o golib.a lib.go

And compiled it as:

$ go build -tags lib -buildmode=c-shared -o golib.a lib.go

Trying to use the generated shared lib in another code as:

//go:build app
// +build app

package main

// #cgo CFLAGS: -g -Wall
// #include <stdlib.h>
// #include "golib.h"
import "C"

func main() {
    C.HelloWorld()
}

// go run main.go

But I'm getting the below error:

# command-line-arguments
Undefined symbols for architecture x86_64:
  "_HelloWorld", referenced from:
      __cgo_a844f0d618a1_Cfunc_HelloWorld in _x002.o
     (maybe you meant: __cgo_a844f0d618a1_Cfunc_HelloWorld)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
# command-line-arguments
cgo-gcc-prolog:47:33: warning: unused variable '_cgo_a' [-Wunused-variable]

Moreover, I'm getting the below error with VS code at mac:

go list failed to return CompiledGoFiles. This may indicate failure to perform cgo processing; try building at the command line. See https://golang.org/issue/38990

在此处输入图像描述

You cannot use a cgo shared library in a Go program, because you cannot have multiple Go runtimes in the same process.

Trying to do so will give the error:

# command-line-arguments
cgo-gcc-prolog:67:33: warning: unused variable '_cgo_a' [-Wunused-variable]
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x43fd5e2]

goroutine 1 [running, locked to thread]:
runtime.throw({0x40a875b?, 0x1c00011b800?})
        /usr/local/go/src/runtime/panic.go:992 +0x71 fp=0x1c00004a960 sp=0x1c00004a930 pc=0x402f6d1
runtime: unexpected return pc for runtime.sigpanic called from 0x43fd5e2
stack: frame={sp:0x1c00004a960, fp:0x1c00004a9b0} stack=[0x1c00004a000,0x1c00004b000)
....
0x000001c00004aaa0:  0x0000000000000000  0x0000000000000000 
runtime.sigpanic()
        /usr/local/go/src/runtime/signal_unix.go:781 +0x3a9 fp=0x1c00004a9b0 sp=0x1c00004a960 pc=0x4043449
exit status 2

To call c code from go, there are 3 potential approaches:

  1. Inline coding, as:
package main

//#include  <stdio.h>
//int Add(int a, int b){
//    printf("Welcome from external C function\n");
//    return a + b;
//}
import "C"
import "fmt"

func main() {
    fmt.Println(C.Add(5, 2))
}
  1. Static linking, where you have both .c and .h files, as:
// lib.c
#include  <stdio.h>
int Add(int a, int b){
    printf("Welcome from external C function\n");
    return a + b;
}

And

// libadd.h
int Add(int, int);

And the go file be:

// main.go
package main

// #include "libadd.h"
import "C"
import "fmt"

func main() {
    x := C.Add(1, 2)
    fmt.Println(x)

}

We have to run the file as go run. or go run github.io/xxx // go run main.go will not work as it will consider main.go only, and not consider the C file

  1. Dynamic linking, where you compile the above c file as clang -shared -fpic -Wall -g lib.c -o libadd.so and have the go file as:
// main.go
package main

//#cgo CFLAGS: -g -Wall
//#cgo LDFLAGS: -L. -ladd
//#include "libadd.h"
import "C"
import "fmt"

func main() {
    x := C.Add(1, 2)
    fmt.Println(x)
}

Here you can use go run main.go as the librry is connected through the hard code, to disctrubute the binary, the shared library loadadd.so is required to be distrubuted with the same binary file and existing in the same folder.

I uploaded seperate folders for each case [here][1]

BONUS To call the generated share library in go using a c program, we can use the below:

// main.c
#include <stdio.h>
#include "libadd.h" // calling C file
#include "libgo.h" // calling shared library generated by GO

int main()
{
    HelloWorld();
    int x = Add(1, 2);
    printf("%d",x);
    return 0;
}

Compiling the file as: ``bash clang -o main -L. -ladd -lgo main.c // -ladd => -l (library) is libadd



  [1]: https://github.com/hajsf/tutorial/tree/master/ffi

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM