Golang類似于C的靜态語言,效率也接近于C,如果Golang也可以導出可供C調用的庫,那可以和很多進階語言say goodbye了,goodbye似乎又有點武斷,但至少說,Golang可以做很多事,而且效率優于很多進階語言,這樣說應該沒有問題。
接下來,就從三個方面分别來介紹Golang中關于庫的使用。
Using Share Library
The latest Go 1.5 version is out. As part of the new features, Go compiler can compile packages as a shared libraries.
It accepts -buildmode argument that determines how a package is compiled. These are the following options:
* archive: Build the listed non-main packages into .a files. Packages named main are ignored.
* c-archive: Build the listed main package, plus all packages it imports, into a C archive file.
* c-shared: Build the listed main packages, plus all packages that they import, into C shared libraries.
* shared: Combine all the listed non-main packages into a single shared library.
* exe: Build the listed main packages and everything they import into executables. Packages not named main are ignored.
By default, listed main packages are built into executables and listed non-main packages are built into .a files.
平時編譯、運作golang,可能用得比較多的是下面這些:
go run xxx.go //直接運作xxx.go,有點類似解釋語言,比如lua, python,其實執行go run,是對源檔案做了build,然後再run執行檔案的,隻是這些都在背景做了
go build xxx.go //編譯産生同名的執行檔,如果在源檔案目錄下直接go build會産生與目錄名同名的可執行檔
go install xxx.go //也是編譯,隻是編譯後會将同名的執行檔安裝到$GOPATH/bin下面,同樣在源檔案目錄下直接go install,會把與目錄同名的可執行檔安裝在$GOPATH/bin下
以上的go build都是預設的編譯,也就是-buildmode是default的
By default, listed main packages are built into executables and listed non-main packages are built into .a files.
現在進入正題,這裡我主要是要說明下面這個選項的使用方法:
* shared: Combine all the listed non-main packages into a single shared library.
我們先看一個hello world的例子:
package main
import "fmt"
int main(){
fmt.Println("hello world")
}
這裡的fmt就是一個share library,這是go裡面自帶的,現在如果想自定義一個共享庫,應該怎麼做?
假設在$GOPATH/src下有:
--myAdd --add.go--myCall --main.go
詳細目錄如下:
[email protected]:~/mygo/src$echo $GOPATH
/home/jack/mygo
[email protected]:~/mygo$ls
bin pkg src
[email protected]:~/mygo/src$ls myAdd
add.go
[email protected]:~/mygo/src$ls myCall
main.go
現在我們要自定義一個myAdd的package,像fmt一樣的使用,先看下myAdd/add.go的内容:
1 package myAdd
2
3 func Sum(x, y int) int {
4 return x + y
5 }
在編譯自定義package前,先看下官方怎麼說:
Before compile any shared library, the standard builtin packages should be installed as shared library. This will allow any other shared library to link with them.
意思是在編譯任何共享包前,先要把官方自身的标準包先以共享包方式安裝下,這樣其他的包就可以與它們做link。
下面就按官方要求先來編譯一下:
[email protected]:~/mygo/src/myAdd$go install -buildmode=shared -linkshared std
編譯後會在GOROOT的pkg目錄下安裝标準共享庫, 這裡對應linux_386_dynlink這個目錄:
[email protected]:~/mygo/src/golib$ ll ~/go/pkg
total 28
drwxr-xr-x 7 jack jack 4096 12月 5 09:21 ./
drwxr-xr-x 11 jack jack 4096 5月 25 2017 ../
drwxr-xr-x 2 jack jack 4096 5月 25 2017 include/
drwxr-xr-x 30 jack jack 4096 5月 25 2017 linux_386/
drwxrwxr-x 29 jack jack 4096 12月 5 09:22 linux_386_dynlink/
drwxr-xr-x 3 jack jack 4096 5月 25 2017 obj/
drwxr-xr-x 3 jack jack 4096 5月 25 2017 tool/
[email protected]:~/mygo/src/golib$ ll ~/go/pkg/linux_386_dynlink/
total 31252
drwxrwxr-x 29 jack jack 4096 12月 5 09:22 ./
drwxr-xr-x 7 jack jack 4096 12月 5 09:21 ../
drwxrwxr-x 2 jack jack 4096 12月 5 09:22 archive/
-rw-rw-r-- 1 jack jack 121966 12月 5 09:21 bufio.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 bufio.shlibname
-rw-rw-r-- 1 jack jack 111466 12月 5 09:21 bytes.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 bytes.shlibname
drwxrwxr-x 2 jack jack 4096 12月 5 09:22 compress/
drwxrwxr-x 2 jack jack 4096 12月 5 09:22 container/
-rw-rw-r-- 1 jack jack 94220 12月 5 09:21 context.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 context.shlibname
drwxrwxr-x 4 jack jack 4096 12月 5 09:22 crypto/
-rw-rw-r-- 1 jack jack 20014 12月 5 09:21 crypto.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 crypto.shlibname
drwxrwxr-x 3 jack jack 4096 12月 5 09:22 database/
drwxrwxr-x 2 jack jack 4096 12月 5 09:22 debug/
drwxrwxr-x 2 jack jack 4096 12月 5 09:22 encoding/
-rw-rw-r-- 1 jack jack 5494 12月 5 09:21 encoding.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 encoding.shlibname
-rw-rw-r-- 1 jack jack 3846 12月 5 09:21 errors.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 errors.shlibname
-rw-rw-r-- 1 jack jack 84486 12月 5 09:21 expvar.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 expvar.shlibname
-rw-rw-r-- 1 jack jack 155402 12月 5 09:21 flag.a
-rw-rw-r-- 1 jack jack 10 12月 5 09:22 flag.shlibname
//GOROOT如下:
[email protected]:~/samba_share/golang$echo $GOROOT
/home/jack/go
接下來,就可以編譯自定義的共享庫,并link到标準std庫:
[email protected]:~/mygo/src$go install -buildmode=shared -linkshared myAdd
[email protected]:~/mygo/src$ls
github.com golang.org myAdd test
[email protected]:~/mygo/src$ls myAdd/
add.go //這裡并沒有産生仍何文檔,産生在那裡接着向下看
實際産生共享是在GOPATH/pkg目錄下:
[email protected]:~/mygo$ls
bin pkg src
[email protected]:~/mygo$ls pkg
linux_386 linux_386_dynlink
[email protected]:~/mygo$ls pkg/linux_386_dynlink/
libmyAdd.so myAdd.a myAdd.shlibname //這些庫在編譯時已經連結到标準std庫,是以下面在應用程式中可以直接使用。
下面是應用程式的代碼:
[email protected]:~/mygo/src$ vim myCall/main.go
1 package main
2
3 import (
4 "fmt"
5 "myAdd" //這就是上面自定義package,如果這裡不import,隻要下面用了包裡面的函數,gofmt也會自動把這個包加進來,是不是有點跟使用fmt等其他包一樣的用法
6 )
7
8 func main() {
9 fmt.Println("my Call application")
10 fmt.Printf("Sum: %d\n", myAdd.Sum(2, 3))
11 }
[email protected]:~/mygo/src$ ./main
my Call application
Sum: 5
Golang生成C可調用的動态庫so
假設代碼結構如下:
[email protected]:~/mygo/src/mylib$ ls
exptest.go
[email protected]:~/mygo/src/mylib$ vim exptest.go
1 package main
2
3 import "C"
4 import "fmt"
5
6 //export Summ
7 func Summ(x, y int) int {
8 return x + y
9 }
10
11 //export Hello
12 func Hello(str string) {
13 fmt.Printf("Hello: %s\n", str)
14 }
15
16 func main() {
17 // We need the main function to make possible
18 // CGO compiler to compile the package as C shared library
19}
官方說法:
Go functions can be executed from C applications. They should be exported by using the following comment line://export
//export your_function_name目的是産生對應的頭檔案函數聲明,以及cgo的與C之間一些轉換規則,詳細可以參考生成的頭檔案。
另外,import “C”這個也是不能少的,表示導入一個C庫
下面就是編譯共享庫:
//The packaged should be compiled with buildmode flags c-shared or c-archive:
[email protected]:~/mygo/src/mylib$ go build -buildmode=c-shared -o libexptest.so exptest.go
[email protected]:~/mygo/src/mylib$ ls
exptest.go libexptest.h libexptest.so
下面寫一個C程式調用這個so動态庫:
[email protected]:~/mygo/src/mylib$vim exptest.c
1 #include
2 #include "libexptest.h" //上面産生的頭檔案
3
4 int main() {
5 printf("This is exptest application.\n");
6 GoString str = {"Hi JXES", 7};
7 Hello(str); //調用的函數
8 printf("sum: %d\n", Summ(2, 3)); //調用的函數
9 return 0;
10 }
[email protected]:~/mygo/src/mylib$export LD_LIBRARY_PATH=./
[email protected]:~/mygo/src/mylib$echo $LD_LIBRARY_PATH
./
[email protected]:~/mygo/src/mylib$./exptest
This is exptest application.
Hello: Hi JXES
sum: 5
這裡需要說明下,在linux系統中應用程式關聯到共享庫時,都是從LD_LIBRARY_PATH環境變量指定的目錄下找需要的.so,是以這裡一定要指定在目前目錄,如果不指定,可以把産生的so檔案複制到/usr/lib下也可以。
Golang調用靜态庫.a
産生靜态庫隻是編譯的時候産生.a的靜态庫,庫與測試程式代碼如上,編譯方法是:
[email protected]:~/mygo/src/mylib$ go build -buildmode=c-archive -o libexptest.so exptest.go
[email protected]:~/mygo/src/mylib$ ls
exptest.go libexptest.h libexptest.a
````
應用程式編譯的方法如下:
$ gcc -o exptest exptest.c libexptest.a “`