Go with Cgo 動態連結 (dynamic linking) 函式庫建置範例與筆記
在上一篇文章中,已經知道如何在 Windows 中,利用 gcc/g++ 建置動態連結函式庫 (dynamic-link library),本篇文章筆記如何在 Go (Golang) 中,利用 cgo 來動態連結函式庫,呼叫使用其函式。
建置環境
在 Windows 環境中,若要在 go 使用 cgo 來串接 C 的函式庫,必須先安裝 gcc compiler (例如 mingw-w64),且必須在環境變數 PATH 中,加入 gcc.exe 的路徑,才能確保 go build
能成功編譯 cgo 的程式碼。
其安裝方法可參考上篇文章的 Install MinGW-w64 章節。
在 Linux 環境中,gcc 應該都有安裝為成預設的編譯器 (?),這問題可以不用煩惱。
簡易範例
函式庫標頭程式碼 example.h
:
#ifndef EXAMPLE_H__
#define EXAMPLE_H__
#ifdef WINDOWS
#define API __declspec(dllexport)
#else
#define API extern
#endif
#define int64 long long
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
API int64 Sum(int64 a, int64 b);
API int64 SumAll(const int64* nums, int n);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // EXAMPLE_H__
其實做程式碼:
#include "example.h"
API int64 Sum(int64 a, int64 b){
return a + b;
}
API int64 SumAll(const int64* nums, int n){
int64 r = 0;
for (int i = 0; i < n; i++){
r += nums[i];
}
return r;
}
以上 C++ 程式碼使用 gcc/g++ 在各平台建置成動態連結函式庫 (dynamic-link library)。在此範例中,Windows 平台建置為 example.x64.dll
,而 Linux 平台則是為 libexample.so
,關於建置方式可參考上一篇文章。
其 go 程式碼 main.go
:
package main
/*
#cgo windows LDFLAGS: -lexample.x64
#cgo windows CFLAGS: -DWINDOWS
#cgo linux LDFLAGS: -lexample
#cgo LDFLAGS: -L"${SRCDIR}/libs"
#cgo CFLAGS: -I"${SRCDIR}/includes"
#include "example.h"
*/
import "C"
func Sum(a, b int) int {
return int(C.Sum(C.longlong(a), C.longlong(b)))
}
func SumAll(nums ...int) int {
n := len(nums)
v := make([]C.longlong, n)
for i, _ := range nums {
v[i] = C.longlong(nums[i])
}
return int(C.SumAll(&v[0], C.int(n)))
}
- Line 4: Windows 環境中,連結函式庫 example.x64.dll
- Line 5: Windows 環境中,編譯定義符號 WINDOWS
- Line 6: Linux 環境中,連結函式庫 libexample.so
- Line 8: 函式庫所在目錄位置,
${SRCDIR}
表示 main.go 檔案相對位置 - Line 9: include 程式碼所在目錄位置
- Line 21-24: 考慮 Go 型別 int size,在 32-bit systems 中通常是 32 bits,而在 64-bit systems 中通常為 64 bits,因此採用此方式準備資料,而不是直接傳入
nums
slice 內部的 pointer
此專案的檔案架構:
- example
- main.go
- libs/example.x64.dll
- libs/libexample.so
- includes/example.h
如此一來,其所建置的執行檔 (executable file) 來會採用動態連結 (dynamic linking) 該 C 函式庫。
執行環境
執行時,應該注意函式庫能被 linker 找到,避免出現找不該函式庫的錯誤。
在 Windows 中,可以設定環境變數 PATH 加入該函式庫的所在資料夾位置,或是將函式庫與執行檔放置在同一個資料夾下。
在 Linux 中,修改 /etc/ld.so.conf 加入函式庫的所在資料夾位置,或是執行前設定環境變數 LD_LIBRARY_PATH 指向函數庫位置。
$ LD_LIBRARY_PATH={LIBRARY_PATH} ./example
例如指向當前工作目錄:
$ LD_LIBRARY_PATH=$(pwd) ./example
如果建置失敗…
若遇到未預期的編譯錯誤,加入參數印出建置所執行的指令,藉此來檢查可能是哪裡出錯:
$ go build -x -ldflags '-v'
使用 cgo 需要檢查 gcc/g++ 的指令錯誤,可能是 compilation error,也有可能是 linking error...。
系列筆記
- 在 Windows 環境建置動態連結函式庫 (Dynamic-link library),使用 MinGW gcc/g++ 以及 CodeBlock
- Go with Cgo 動態連結 (dynamic linking) 函式庫建置範例與筆記
- Go with Cgo 靜態連結 (static linking) 函式庫建置範例與筆記
沒有留言: