使用 Go 語言構建 C 庫
使用 Go 語言構建 C 庫
CGO is an official builtin feature of Go, it enables the creation of Go packages that reference to C libraries. But it isn’t just that, it is achievable in the opposite direction, too. It enables creation of C libraries from Go packages so that C code can reference to Go, which is mind-blowing.
CGO 不但可以使 Go 包訪問 C 庫,還可以通過 Go 包建立 C 庫,進而使 C/C++ 程式可呼叫 Go 語言程式。
1.How to
1.1.Build Go package as C shared library (or shared object)
Every Go main package can be built as a C shared library.
任何 Go main 包都可以建立 C 庫。
go build -buildmode=c-shared -o <c-lib>.so
Executing above command builds target Go main
以上命令可以建立共享庫,該共享庫可以被 C、C++、Python、Javascript 等語言訪問。
Note: Output C shared libraries should be named in standard form lib*.so.
1.2.Generate C header and export Go functions as C functions
Building a Go main package as C shared library doesn’t automatically neither generate C header nor expose any Go function as C symbol. Developers have to explicitly indicate which Go functions to be exposed.
To export a Go function as a C symbol:
- The function must belong to main package.
- The Go code file containing the function has to import “C”.
- Add comment //export FuncName on top of the Go function.
- The function signature must not include neither Go struct nor* Go interface nor Go array nor variadic argument.
上述命令不會生成 C 標頭檔案並匯出符號。若想匯出符號並自動生成標頭檔案需要滿足以下條件:
- 要匯出的函式必須屬於 main 包;
- Go 原始碼檔案包含 import “C”;
- 在要匯出的函式使用 //export FuncName 註釋;
- 不能使用 Go struct、Go interface、Go arra、以及可變引數。
2.Example
package main
import "C"
import (
"math/rand"
"time"
)
//export cgoCurrentMillis
func cgoCurrentMillis() C.long {
return C.long(time.Now().Unix())
}
//export cgoSeed
func cgoSeed(m C.long) {
rand.Seed(int64(m))
}
//export cgoRandom
func cgoRandom(m C.int) C.int {
return C.int(rand.Intn(int(m)))
}
func main() {}
Building above Go main package generates a C header file <output>.h along with a C shared object <output>.so.
構建以上示例將自動產生標頭檔案和共享庫。
// Other stuff.
extern long int cgoCurrentMillis();
extern void cgoSeed(long int p0);
extern int cgoRandom(int p0);
cgoCurrentMilli, cgoSeed and cgoRandom are exposed as C symbols in <output>.so, too.
Now, every C application can include the generated C header, link to the output C shared library and use exposed C symbols.
#include <stdio.h>
int main() {
cgoSeed(cgoCurrentMillis());
printf("Hello World from C!\n");
printf("cgoRandom() -> %d\n", cgoRandom(256));
return 0;
}
編譯方法如下:
gcc main.c -l<c-lib> -o <exe-file>