golang 調(diào)用c語言動態(tài)庫方式實(shí)現(xiàn)
下面我們自己在 Linux 下做一個動態(tài)庫(.so 文件 - Shared Object),然在用 Go 來使用它。本文所用的操作系統(tǒng)為 Ubuntu18.04, 以 gcc 作為編譯器。
1.實(shí)現(xiàn)頭文件,聲明文件中函數(shù)。這里創(chuàng)建一個add.h文件。
#ifndef __ADD_H__ #define __ADD_H__ char* Add(char* src, int n); #endif
2.實(shí)現(xiàn)add主體函數(shù)add.c
#include <string.h> #include <stdio.h> #include <stdlib.h> char* Add(char* src, int n) { char str[20]; sprintf(str, "%d", n); char *result = malloc(strlen(src)+strlen(str)+1); strcpy(result, src); strcat(result, str); return result; }
3.用命令生成動態(tài)庫,在linux下文件名稱是libadd.so
gcc -fPIC -shared -o lib/libadd.so include/add.c
會在當(dāng)前目錄下生成 libadd.so 文件, 在 Linux 下可用 nm -D libadd.so 查看其中的方法
4.編寫一個庫來測試一下
#include <stdio.h> #include "add.h" int main(int argc, char *argv[]) { char* aa = "giter"; printf("%s\n", Add(aa, 8)); return 0; }
鏈接動態(tài)庫生成可執(zhí)行文件
gcc include/test.c -L lib/ -ladd -o test
- -L .表示搜索要鏈接的庫文件時包含當(dāng)前目錄
- -ladd 表示要鏈接動態(tài)庫 libadd.so (備注:默認(rèn)lib + xxx + .so ,中間的xxx就是庫名)
- -o test 生成可執(zhí)行文件 test
錯誤:運(yùn)行出錯的情況
# 運(yùn)行 ./test,出錯
./test: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
出現(xiàn)以上的錯誤。有可能是環(huán)境變量沒弄好導(dǎo)致的,找不到動態(tài)庫 libadd.so, Linux 通過 ldconfig 的指示在某些目錄中(如 /lib, /user/lib) 搜索動態(tài)庫。更簡單的辦法是用 LD_LIBRARY_PATH 環(huán)境變量。解決辦法,
$ LD_LIBRARY_PATH=lib/ ./test giter8
至此,動態(tài)庫 libadd.so 準(zhǔn)備好了,并且用 test 驗證了它是可用的,接下來就在 Go 語言中使用該動態(tài)庫的函數(shù)。
5.golang調(diào)用c動態(tài)庫
demo1 ├── include │ └── add.c │ └── add.h │ └── test.c ├── lib │ └── libadd.so └── main.go
main.go 的代碼如下:
package main /* // 頭文件的位置,相對于源文件是當(dāng)前目錄,所以是 .,頭文件在多個目錄時寫多個 #cgo CFLAGS: ... #cgo CFLAGS: -I./include // 從哪里加載動態(tài)庫,位置與文件名,-ladd 加載 libadd.so 文件 #cgo LDFLAGS: -L./lib -ladd -Wl,-rpath,lib #include "add.h" */ import "C" import "fmt" func main() { val := C.Add(C.CString("go"), 2021) fmt.Println("run c: ", C.GoString(val)) }
通過注釋代碼來告訴 Go 編譯器從哪里引入頭文件與加載動態(tài)庫. 本例中 *.h 和 *.go 文件在同一個目錄的情況下, #cgo CFLAGS: -I. 可不寫。
CFLAGS: -I 和 LDFLAGS: -L 都是相對于源文件 main.go 的位置
./demo1 run c: go2021
成功調(diào)用 C 實(shí)現(xiàn)的 add 函數(shù)
下面列出一些問題
import "C" 要緊挨著 /*...*/ 注釋塊,如果寫成
/* #cgo ... */ import "C"
出現(xiàn)下面的報錯信息
# demo1
./main.go:15:10: could not determine kind of name for C.Add
import "C" 要獨(dú)占一行, 試圖同時引入其他的庫,如 import ("C"; "fmt") 也會報上面同樣的錯誤
加載不到頭文件的錯誤很明顯,#include "add.h" 時會告訴你該文件不存在,如果沒有加載到正確的頭文件調(diào)用 C.Add() 函數(shù)時就會報錯
# demo1
./main.go:15:10: could not determine kind of name for C.Add
還有一個關(guān)鍵是能否加載到動態(tài)庫 libadd.so, 參考了網(wǎng)上一些例子,如果把第五行改為
cgo LDFLAGS: -L./lib -ladd
編譯不會報錯,執(zhí)行時會出錯。
./demo1: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
但如果設(shè)置了環(huán)境變量 LD_LIBRARY_PATH=/home/vagrant/testgo/lib 也能讓它跑起來
LD_LIBRARY_PATH=lib/ ./demo1
到此這篇關(guān)于golang 調(diào)用c語言動態(tài)庫方式實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang 調(diào)用c語言動態(tài)庫內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang微服務(wù)框架Kratos實(shí)現(xiàn)Kafka消息隊列的方法
消息隊列是大型分布式系統(tǒng)不可缺少的中間件,也是高并發(fā)系統(tǒng)的基石中間件,所以掌握好消息隊列MQ就變得極其重要,在本文當(dāng)中,您將了解到:什么是消息隊列?什么是Kafka?怎樣在微服務(wù)框架Kratos當(dāng)中應(yīng)用Kafka進(jìn)行業(yè)務(wù)開發(fā),需要的朋友可以參考下2023-09-09Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究
這篇文章主要介紹了Golang實(shí)現(xiàn)自己的Redis(TCP篇)實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01Golang學(xué)習(xí)之反射機(jī)制的用法詳解
反射的本質(zhì)就是在程序運(yùn)行的時候,獲取對象的類型信息和內(nèi)存結(jié)語構(gòu),反射是把雙刃劍,功能強(qiáng)大但可讀性差。本文將詳細(xì)講講Golang中的反射機(jī)制,感興趣的可以了解一下2022-06-06go程序測試CPU占用率統(tǒng)計ps?vs?top兩種不同方式對比
這篇文章主要為大家介紹了go程序測試CPU占用率統(tǒng)計ps?vs?top兩種不同方式對比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作
這篇文章主要介紹了xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12Skywalking-go自動監(jiān)控增強(qiáng)使用探究
這篇文章主要介紹了Skywalking-go自動監(jiān)控增強(qiáng)使用深入探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01