golang學習筆記-golang調用c實現的.so接口細節

目的

之前有一篇關於 在windows平臺下golang調用dll的具體實現 ,列舉了常見的幾種參數傳遞方式,本篇文章就針對在linux平臺下使用cgo調用c實現的.so的一些具體的方式。比如值傳遞、參數傳遞、指針等等的一些使用。

環境:centos 7.6.18
編譯環境:go1.11.4 linux/amd644.8.5 20150623 (Red Hat 4.8.5-36) (GCC)

一、動態庫的實現

動態庫實現了三個功能,單個無參函數的;單個結構體函數;多個結構體函數
def.h

#ifndef _DEF_H_
#define _DEF_H_
// 結構體
struct userinfo
{
    char* username;
    int len;
};
#endif

hello.h

#ifndef _CALL_H_
#define _CALL_H_
#include "def.h"

void helloworld();
void store_jpg(char* name , int len);
void only_struct(struct userinfo* u);
void multi_struct(struct userinfo* u,int size);
#endif //_CALL_H_

hello.c

#include "hello.h"
#include <stdio.h>
#include <stdlib.h>

// helloworl
void helloworld()
{
    printf("hello world.\n");
}

// 指針和int 模擬存文件
void store_jpg(char* name ,int len)
{
    FILE *fp = NULL;
    fp = fopen( "file.jpg" , "w" );
    fwrite(name, len , 1, fp );
    fclose(fp); 
}

// 調用結構體指針
void only_struct(struct userinfo* u)
{
    char* name =u->username;
    int len = u->len;
    printf("call_only_struct:%s %d\n",name,len);
}

// 調用結構體指針,模擬結構體數組
void multi_struct(struct userinfo* u,int size)
{
    int i = 0;
    printf("call_multi_struct\n");
    while (i < size)
    {
        char* name = u[i].username;
        int len = u[i].len;
        printf("username:%s, len:%d, size:%d\n",name,len,size);
        i++;
    }    
}

測試動態庫是否正常的c代碼main.c

#include <stdio.h>
#include "def.h"

// 調用 libhello.so  測試動態庫
int main()
{
    helloworld();
    struct userinfo u = {"shadiao wangyou",sizeof("shadiao wangyou")};
    only_struct(&u);
    return 0;
}

實現兩個接口,一個打印hello world,一個存儲文件。

二、golang代碼

1、golang調用.so的代碼

1)調用單個的無參函數
2)調用指針和長度,在大部分的場景中都會用到
3)調用單個的結構體,數據結構使用的是c代碼中定義的結構
4)調用多個結構體

package main
/*
#cgo CFLAGS : -I../c
#cgo LDFLAGS: -L../c -lhello

#include "hello.h"
#include <stdio.h>
#include <stdlib.h>
*/
import "C"
import (
	"os"
	"unsafe"
	"fmt"
)
func main(){
	call_helloworl()
	call_store_file()
	call_only_struct()
	call_multi_struct()
}

func call_helloworl(){
	C.helloworld()
}

func call_store_file(){
	f,err:=os.Open("1.jpg")
	if err!=nil{
		panic(err)
	}
	defer f.Close()
	buf:=make([]byte,1024*10)
	if n,err:=f.Read(buf);err!=nil{
		panic(err)
	}else{
		cs:=C.CString(string(buf[0:n]))
		defer C.free(unsafe.Pointer(cs))
		C.store_jpg(cs, C.int(n))
	}
}

func call_only_struct(){
	var userinfo C.struct_userinfo
	cs:= C.CString("shadiao wangyou")
	defer C.free(unsafe.Pointer(cs))
	userinfo.username =cs
	userinfo.len = C.int(len("shadiao wangyou"))
	C.only_struct(&userinfo)
}

func call_multi_struct(){
	var userinfos []C.struct_userinfo
	for i:=0;i<2;i++{
		var ui C.struct_userinfo
		s:=fmt.Sprintf("%s-%d","shadiao wangyou",i)
		cs:= C.CString(s)
		defer C.free(unsafe.Pointer(cs))
		ui.username =cs
		ui.len = C.int(len(s))

		userinfos=append(userinfos,ui)
	}
	C.multi_struct(&userinfos[0],C.int(len(userinfos)))
}

2、代碼結構和編譯腳本:

cgo
├── c
│   ├── hello.c
│   ├── hello.h
│   ├── libhello.a
│   ├── libhello.so
│   ├── main
│   ├── main.c
│   ├── make.sh
│   └── static_main
└── go
    ├── libhello.so
    ├── main
    └── main.go

編譯腳本make.sh

#/bin/bash
echo "static lib"
rm -rf ./*.o 
rm -rf ./*.a
rm -rf main

gcc -c -o hello.o hello.c
ar -rc libhello.a hello.o
gcc main.c libhello.a -L. -o static_main

rm -rf ./*.o 
echo "lib"
rm -rf /usr/lib64/libhello.so
gcc -fPIC -shared hello.c -o libhello.so
sudo cp libhello.so /usr/lib64/
gcc main.c -L. -lhello -o main

三、結果

生成的動態庫:

在這裏插入圖片描述

調用的結果:

在這裏插入圖片描述
參考鏈接:
http://blog.codeg.cn/post/blog/2016-04-20-golang-cgo/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章