網站首頁 編程語言 正文
開坑說明
最近在編寫客戶端程序或與其他部門做功能集成時多次碰到了跨語言的sdk集成,雖說方案很多諸如rpc啊,管道啊,文件io啊,unix socket啊之類的不要太多,但最完美的基礎方式還是讓程序與sdk結合到一起(個人觀點,不喜勿噴),順便研究了下在go調用標準c接口的種種方法與坑,內容不少,有空便慢慢更新了。
內嵌形式
先讓我們來看一個最簡單的cgo實例
package main //#include <stdio.h> import "C" func main() { C.puts(C.CString("Hello World")) }
輸出
Hello World
通過"C包"調用了c中常見的puts函數同時傳入通過C.Cstring把go 中string轉化為的c string(相當于char *)。其實“C”這個并不是一個包,而是通過import "C"語句啟用了go編譯器cgo相關的功能讓gcc也參與到了編譯中。這種方式通過緊貼在import "C"語句上面的注釋中編寫c代碼并在后續代碼中使用C對象調用。當然也可以通過這種方式調用自定義的c函數。
package main import "C" /*#include <stdio.h> void say_hello_with_name(char * name){ printf("hello %s\n", name); } */ import "C" func main() { C.say_hello_with_name(C.CString("oscar")) }
輸出
hello oscar
外置的C代碼
內置的C代碼固然很方便,但用到cgo大多數的使用場景是我有一個需要復用的c代碼庫,像是c++的stl庫亦或者是linux c中的什么已經封裝好的第三方依賴。這些時候便需要外置一些c的文件.h .c .cpp之類與.go文件混編。先看一個最簡單的例子(調用linux的系統賬戶認證)。
// auth.h
int auth(char *user, char *passwd);
// auth.c
#include <shadow.h>
#include <stdio.h>
#include <unistd.h>
int auth(char *user, char *passwd){
char *obtpwd;
struct spwd *spasswd;
spasswd = getspnam(user);
obtpwd = crypt(passwd, spasswd->sp_pwdp);
if(strcmp(spasswd->sp_pwdp, obtpwd) == 0)
return 0;
else return 1;
}
// main.go
package main
/*
#cgo LDFLAGS: -lcrypt
#include "auth.h"
*/
import "C"
import "fmt"
func main() {
var username, password string
fmt.Println("Please enter your username and password: ")
_, _ = fmt.Scanln(&username, &password)
rst := C.auth(C.CString(username), C.CString(password))
fmt.Println(rst)
}
保證上述三個文件在同一個go工程目錄下運行?go build -o main?構建工程。#cgo LDFLAGS: -lcrypt?這個一行是cgo給gcc的編譯參數,相關的編譯參數與連接參數有空了在后面的文章里說明,-lcrypt 表示編譯時需要去連接libcrypt這個庫。
注意,這種c go 混編的方式個人是不建議的,cgo對外置c代碼片構建支持非常差,我無法在cgo中通過編譯參數指定c代碼片的搜索路徑(頭文件倒是沒啥問題),這也就意味著當項目被調用的c代碼片都得在項目根目錄下,這可太糟糕了。個人覺得如果有大量的外部依賴c語言的庫請分開編譯,c庫使用gcc編譯成靜態或動態庫在讓go在編譯時連接為好,寫個makefile分開分步編譯也不是什么麻煩事,還是上面的例子,讓我們把編譯的過程稍加修改。
1. 構建libauth.a靜態庫
gcc -c -o auth.o -lcrypt auth.c
ar rcs libauth.a auth.o
得到libauth.a
2. 對main.go稍加修改
package main /* #cgo CFLAGS: -I./ #cgo LDFLAGS: -L. -lauth -lcrypt #include "auth.h" */ import "C" import "fmt" func main() { var username, password string fmt.Println("Please enter your username and password: ") _, _ = fmt.Scanln(&username, &password) rst := C.auth(C.CString(username), C.CString(password)) fmt.Println(rst) }
此處修改主要是新增了libauth.a靜態庫的鏈接參數
3. 編譯
go build -o main main.go
可以把上述的步驟整下寫個簡單的makefile
.PHONY : all
all: main
libauth.a: auth.c
gcc -c -o auth.o -lcrypt auth.c
ar rcs libauth.a auth.o
main: main.go libauth.a
go build -o main main.go
clean:
rm -f auth.o libauth.a main
這樣也讓我們得出產物的過程變得相對簡單快捷
原文鏈接:https://www.cnblogs.com/oscar2960/p/16242310.html
相關推薦
- 2022-12-29 解決React報錯Property?value?does?not?exist?on?type?HTM
- 2022-05-24 python中的元組與列表及元組的更改_python
- 2022-09-26 Redis刪除策略的三種方法及逐出算法_Redis
- 2022-06-27 Python利用re模塊實現簡易分詞(tokenization)_python
- 2023-03-25 詳解Typescript?嚴格模式有多嚴格_其它
- 2022-07-07 基于Python制作一個文件解壓縮工具_python
- 2023-04-26 C++利用伴隨陣法實現矩陣求逆_C 語言
- 2022-09-26 shell變量,shell函數,shell數組,shell常用命令,shell流程控制語句
- 最近更新
-
- 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同步修改后的遠程分支