網站首頁 編程語言 正文
下面我們自己在 Linux 下做一個動態庫(.so 文件 - Shared Object),然在用 Go 來使用它。本文所用的操作系統為 Ubuntu18.04, 以 gcc 作為編譯器。
1.實現頭文件,聲明文件中函數。這里創建一個add.h文件。
#ifndef __ADD_H__ #define __ADD_H__ char* Add(char* src, int n); #endif
2.實現add主體函數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.用命令生成動態庫,在linux下文件名稱是libadd.so
gcc -fPIC -shared -o lib/libadd.so include/add.c
會在當前目錄下生成 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; }
鏈接動態庫生成可執行文件
gcc include/test.c -L lib/ -ladd -o test
- -L .表示搜索要鏈接的庫文件時包含當前目錄
- -ladd 表示要鏈接動態庫 libadd.so (備注:默認lib + xxx + .so ,中間的xxx就是庫名)
- -o test 生成可執行文件 test
錯誤:運行出錯的情況
# 運行 ./test,出錯
./test: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
出現以上的錯誤。有可能是環境變量沒弄好導致的,找不到動態庫 libadd.so, Linux 通過 ldconfig 的指示在某些目錄中(如 /lib, /user/lib) 搜索動態庫。更簡單的辦法是用 LD_LIBRARY_PATH 環境變量。解決辦法,
$ LD_LIBRARY_PATH=lib/ ./test giter8
至此,動態庫 libadd.so 準備好了,并且用 test 驗證了它是可用的,接下來就在 Go 語言中使用該動態庫的函數。
5.golang調用c動態庫
demo1 ├── include │ └── add.c │ └── add.h │ └── test.c ├── lib │ └── libadd.so └── main.go
main.go 的代碼如下:
package main /* // 頭文件的位置,相對于源文件是當前目錄,所以是 .,頭文件在多個目錄時寫多個 #cgo CFLAGS: ... #cgo CFLAGS: -I./include // 從哪里加載動態庫,位置與文件名,-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 編譯器從哪里引入頭文件與加載動態庫. 本例中 *.h 和 *.go 文件在同一個目錄的情況下, #cgo CFLAGS: -I. 可不寫。
CFLAGS: -I 和 LDFLAGS: -L 都是相對于源文件 main.go 的位置
./demo1 run c: go2021
成功調用 C 實現的 add 函數
下面列出一些問題
import "C" 要緊挨著 /*...*/ 注釋塊,如果寫成
/* #cgo ... */ import "C"
出現下面的報錯信息
# demo1
./main.go:15:10: could not determine kind of name for C.Add
import "C" 要獨占一行, 試圖同時引入其他的庫,如 import ("C"; "fmt") 也會報上面同樣的錯誤
加載不到頭文件的錯誤很明顯,#include "add.h" 時會告訴你該文件不存在,如果沒有加載到正確的頭文件調用 C.Add() 函數時就會報錯
# demo1
./main.go:15:10: could not determine kind of name for C.Add
還有一個關鍵是能否加載到動態庫 libadd.so, 參考了網上一些例子,如果把第五行改為
cgo LDFLAGS: -L./lib -ladd
編譯不會報錯,執行時會出錯。
./demo1: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
但如果設置了環境變量 LD_LIBRARY_PATH=/home/vagrant/testgo/lib 也能讓它跑起來
LD_LIBRARY_PATH=lib/ ./demo1
原文鏈接:https://juejin.cn/post/7047405294107754533
相關推薦
- 2022-04-08 Python實現自定義異常實例_python
- 2023-06-13 C++?ncnn模型驗證精度實現代碼_C 語言
- 2022-05-28 Python讀取文件的四種方式的實例詳解_python
- 2022-05-21 C++實現教職工信息管理系統_C 語言
- 2022-06-06 webpack5.6.0解決報The ‘mode‘ option has not been set,
- 2022-03-13 用Docker搭建nextcloud個人網盤教程_docker
- 2022-06-25 python多進程和多線程介紹_python
- 2022-07-04 Python如何查看兩個數據庫的同名表的字段名差異_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支