<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文介紹一種 Golang 程式在執行時載入 C 動態庫的技術,跳過了 Golang 專案編譯階段需要連結 C 動態庫的過程,提高了 Golang 專案開發部署的靈活性。
Golang 程式呼叫 OpenCC 動態庫的函數,執行文字繁體轉簡體操作。 需要在編譯時不連結動態庫,只在程式執行時載入 OpenCC 動態庫。
OpenCC 庫是使用 C++ 編寫的繁簡體轉換程式,提供 C 語言 API 介面。 開源專案地址
CGO 技術是讓 Golang 語言使用 C 語言程式碼的一種方式,可以在 Golang 程式編譯的時候連結 C 動態庫。C 語言經過數十年的發展,有豐富的開源專案。在 Golang 生態還不是很完善的情況下,我們經常需要使用一些成熟的C開源專案。
Plugin 是 Golang 1.8 版本引入了一個新的外掛系統,允許程式設計師使用動態連結庫構建鬆散耦合的模組化程式,在程式執行時動態載入和繫結。
本文循序漸進地講解 2 種解決方案:
方案 1 是最初的解決方案,使用 CGO 技術,在編譯的時候繫結 OpenCC 的介面。
Golang -> CGO -> libopencc.so
編寫CGO介面定義檔案:
// opencc.h #include <stdlib.h> void* Opencc_New(const char *configFile); void* Opencc_Delete(void *id); const char *Opencc_Convert(void *id, const char *input); void Opencc_Free_String(char *p);
// opencc.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include "opencc/src/opencc.h" const char *Convert(const char *input, const char *config) { if(strlen(config) > 16) { return 0; } char configFile[256] = "/usr/share/opencc/"; strcat(configFile, config); strcat(configFile, ".json"); opencc_t p = opencc_open(configFile); char *out = opencc_convert_utf8(p, input, strlen(input)); out[strlen(input)] = ' '; opencc_close(p); return out; } void Convert_free_string(char *p) { opencc_convert_utf8_free(p); } void* Opencc_New(const char *configFile) { return opencc_open(configFile); } void Opencc_Delete(void *id) { opencc_close(id); } const char *Opencc_Convert(void *id, const char *input) { char *output = opencc_convert_utf8(id, input, strlen(input)); output[strlen(input)] = ' '; return output; } void Opencc_Free_String(char *p) { opencc_convert_utf8_free(p); }
// opencc.go package opencc import "unsafe" // #cgo LDFLAGS: -L${SRCDIR}/output/lib -lopencc // #include "opencc.h" import "C" func NewConverter(config string) unsafe.Pointer { return C.Opencc_New(C.CString(config)) } func Convert(p unsafe.Pointer, input string) string { inputChars := C.CString(input) outputChars := C.Opencc_Convert(p, inputChars) defer C.Opencc_Free_String(inputChars) defer C.Opencc_Free_String(outputChars) result := C.GoString(outputChars) return result } func Close(p unsafe.Pointer) { C.Opencc_Delete(p) } func ConvertOneTime(input string, config string) string { p := NewConverter(config) defer Close(p) return Convert(p, input) } func ConvertAsync(input string, config string, callback func(output string)) { go func() { callback(ConvertOneTime(input, config)) }() }
// test.go 呼叫OpenCC動態庫的函數。 package main import "fmt" import "your/repository/go-opencc" const ( input = "中國滑鼠軟體印表機" config_s2t = "/usr/share/opencc/s2t.json" config_t2s = "/usr/share/opencc/t2s.json" ) func main() { fmt.Println("Test Converter class:") c := opencc.NewConverter(config_s2t) defer c.Close() output := c.Convert(input) fmt.Println(output) fmt.Println("Test Convert function:") s := opencc.Convert(input, config_s2t) fmt.Println(s) fmt.Println(opencc.Convert(s, config_t2s)) fmt.Println("Test ConvertAsync function:") retChan := make(chan string) opencc.ConvertAsync(input, config_s2t, func(output string) { retChan <- output }) fmt.Println(<- retChan) }
方案 1,可以正確連結 libopencc.so 檔案,併成功執行 Convert 函數進行繁簡體轉換。 但是有個問題,該方案在 Mac 系統上不容易進行編譯,需要在 Mac 系統裡安裝 OpenCC 專案。假如呼叫 OpenCC 的專案有 10 人共同開發,就需要在 10 人的 Mac 電腦上進行編譯,開發共同作業困難,不方便部署。
引入 Plugin 技術,程式執行時載入動態庫。
Golang -> Plugin -> libgo_opencc.so -> CGO -> libopencc.so
編寫 Plugin 動態連結庫。
// opencc_lib.go package main import ( "unsafe" opencc "your/repository/go-opencc" ) type openccConverter string // NewConverter 建立Converter func (s openccConverter) NewConverter(config string) unsafe.Pointer { return opencc.NewConverter(config) } // Convert 轉換函數 func (s openccConverter) Convert(p unsafe.Pointer, input string) string { return opencc.Convert(p, input) } // Close 釋放Converter佔用的記憶體資源(不再使用Converter了) func (s openccConverter) Close(p unsafe.Pointer) { opencc.Close(p) } // ConvertOneTime 轉換函數(轉換一次,該函數每次呼叫都會載入組態檔,有效能影響) func (s openccConverter) ConvertOneTime(input string, config string) string { return opencc.ConvertOneTime(input, config) } // OpenccConverter export symble var OpenccConverter openccConverter
編譯動態庫 build.sh 建立 output 目錄,編譯生成 ./output/lib/libgo_opencc.so 動態庫。
#!/bin/bash mkdir -p output cd opencc ./build.sh cd .. cp -rf opencc/output/* ./output go build -buildmode=plugin -o ./output/lib/libgo_opencc.so ./lib/opencc_lib.go
使用 Plugin 載入 libgo_opencc.so,呼叫 OpenCC 的函數。
package main import ( "os" "plugin" "testing" "unsafe" "fmt" ) // 實現 opencc_lib.go 的介面 type OpenccConverter interface { NewConverter(config string) unsafe.Pointer Convert(p unsafe.Pointer, input string) string Close(p unsafe.Pointer) ConvertOneTime(input string, config string) string } func TestOpenccSo(t *testing.T) { openccPlugin, pluginErr := plugin.Open("/your/path/to/go-opencc/output/lib/libgo_opencc.so") if pluginErr != nil { panic(pluginErr) } symbol, cerr := openccPlugin.Lookup("OpenccConverter") if cerr != nil { fmt.Errorf("%+v", cerr) os.Exit(1) } plug, ok := symbol.(OpenccConverter) if !ok { fmt.Errorf("unexpected type from module symbol") os.Exit(1) } config := "/usr/share/opencc/hk2s.json" pointer := plug.NewConverter(config) defer plug.Close(pointer) input := "傳統漢字" output := plug.Convert(pointer, input) fmt.Printf("output: %s", output) } // 執行測試 TestOpenccSo,輸出 「傳統漢字」。
方案 2,實現了在程式執行時通過 Plugin 技術載入 libgo_opencc.so 動態庫,再由 libgo_opencc.so 連結到 libopencc.so,即可在 Mac、Linux 系統上編譯 Golang 程式,無需每臺開發機都部署 OpenCC 專案。最終釋出到生產環境時,由編譯打包平臺將 libgo_opencc.so 和 libopencc.so 一起打包釋出。
到此這篇關於Golang使用CGO與Plugin技術執行載入C動態庫的文章就介紹到這了,更多相關Go載入C動態庫內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45