Golang生成共享库(shared library)以及Golang生成C可调用的动态库.so和静态库.a

来源:互联网 发布:linux tmp目录怎么进入 编辑:程序博客网 时间:2024/05/22 17:40

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 mainimport "fmt"int main(){    fmt.Println("hello world")}

这里的fmt就是一个share library,这是go里面自带的,现在如果想自定义一个共享库,应该怎么做?
假设在$GOPATH/src下有:

--myAdd        --add.go--myCall        --main.go

详细目录如下:

jack@jack-VirtualBox:~/mygo/src$ echo $GOPATH/home/jack/mygojack@jack-VirtualBox:~/mygo$ lsbin  pkg  srcjack@jack-VirtualBox:~/mygo/src$ ls myAddadd.gojack@jack-VirtualBox:~/mygo/src$ ls myCallmain.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。

下面就按官方要求先来编译一下:

jack@jack-VirtualBox:~/mygo/src/myAdd$ go install -buildmode=shared -linkshared std

编译后会在GOROOT的pkg目录下安装标准共享库, 这里对应linux_386_dynlink这个目录:

jack@jack-VirtualBox:~/mygo/src/golib$ ll ~/go/pkgtotal 28drwxr-xr-x  7 jack jack 4096 125 09:21 ./drwxr-xr-x 11 jack jack 4096 525  2017 ../drwxr-xr-x  2 jack jack 4096 525  2017 include/drwxr-xr-x 30 jack jack 4096 525  2017 linux_386/drwxrwxr-x 29 jack jack 4096 125 09:22 linux_386_dynlink/drwxr-xr-x  3 jack jack 4096 525  2017 obj/drwxr-xr-x  3 jack jack 4096 525  2017 tool/jack@jack-VirtualBox:~/mygo/src/golib$ ll ~/go/pkg/linux_386_dynlink/total 31252drwxrwxr-x 29 jack jack     4096 125 09:22 ./drwxr-xr-x  7 jack jack     4096 125 09:21 ../drwxrwxr-x  2 jack jack     4096 125 09:22 archive/-rw-rw-r--  1 jack jack   121966 125 09:21 bufio.a-rw-rw-r--  1 jack jack       10 125 09:22 bufio.shlibname-rw-rw-r--  1 jack jack   111466 125 09:21 bytes.a-rw-rw-r--  1 jack jack       10 125 09:22 bytes.shlibnamedrwxrwxr-x  2 jack jack     4096 125 09:22 compress/drwxrwxr-x  2 jack jack     4096 125 09:22 container/-rw-rw-r--  1 jack jack    94220 125 09:21 context.a-rw-rw-r--  1 jack jack       10 125 09:22 context.shlibnamedrwxrwxr-x  4 jack jack     4096 125 09:22 crypto/-rw-rw-r--  1 jack jack    20014 125 09:21 crypto.a-rw-rw-r--  1 jack jack       10 125 09:22 crypto.shlibnamedrwxrwxr-x  3 jack jack     4096 125 09:22 database/drwxrwxr-x  2 jack jack     4096 125 09:22 debug/drwxrwxr-x  2 jack jack     4096 125 09:22 encoding/-rw-rw-r--  1 jack jack     5494 125 09:21 encoding.a-rw-rw-r--  1 jack jack       10 125 09:22 encoding.shlibname-rw-rw-r--  1 jack jack     3846 125 09:21 errors.a-rw-rw-r--  1 jack jack       10 125 09:22 errors.shlibname-rw-rw-r--  1 jack jack    84486 125 09:21 expvar.a-rw-rw-r--  1 jack jack       10 125 09:22 expvar.shlibname-rw-rw-r--  1 jack jack   155402 125 09:21 flag.a-rw-rw-r--  1 jack jack       10 125 09:22 flag.shlibname

//GOROOT如下:

jack@jack-VirtualBox:~/samba_share/golang$ echo $GOROOT/home/jack/go

接下来,就可以编译自定义的共享库,并link到标准std库:

jack@jack-VirtualBox:~/mygo/src$ go install -buildmode=shared -linkshared myAddjack@jack-VirtualBox:~/mygo/src$ lsgithub.com  golang.org  myAdd  testjack@jack-VirtualBox:~/mygo/src$ ls myAdd/add.go //这里并没有产生仍何文档,产生在那里接着向下看

实际产生共享是在GOPATH/pkg目录下:

jack@jack-VirtualBox:~/mygo$ lsbin  pkg  srcjack@jack-VirtualBox:~/mygo$ ls pkglinux_386  linux_386_dynlinkjack@jack-VirtualBox:~/mygo$ ls pkg/linux_386_dynlink/libmyAdd.so  myAdd.a  myAdd.shlibname //这些库在编译时已经链接到标准std库,所以下面在应用程序中可以直接使用。

下面是应用程序的代码:

jack@jack-VirtualBox:~/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 } jack@jack-VirtualBox:~/mygo/src$ ./main my Call applicationSum: 5

Golang生成C可调用的动态库so

假设代码结构如下:

jack@jack-VirtualBox:~/mygo/src/mylib$ lsexptest.gojack@jack-VirtualBox:~/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 <your_function_name>

//export your_function_name目的是产生对应的头文件函数声明,以及cgo的与C之间一些转换规则,详细可以参考生成的头文件。
另外,import “C”这个也是不能少的,表示导入一个C库

下面就是编译共享库:

//The packaged should be compiled with buildmode flags c-shared or c-archive:jack@jack-VirtualBox:~/mygo/src/mylib$ go build -buildmode=c-shared -o libexptest.so exptest.go jack@jack-VirtualBox:~/mygo/src/mylib$ lsexptest.go  libexptest.h  libexptest.so

下面写一个C程序调用这个so动态库:

jack@jack-VirtualBox:~/mygo/src/mylib$ vim exptest.c  1 #include <stdio.h>  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 } jack@jack-VirtualBox:~/mygo/src/mylib$ export LD_LIBRARY_PATH=./jack@jack-VirtualBox:~/mygo/src/mylib$ echo $LD_LIBRARY_PATH ./jack@jack-VirtualBox:~/mygo/src/mylib$ ./exptest This is exptest application.Hello: Hi JXESsum: 5

这里需要说明下,在linux系统中应用程序关联到共享库时,都是从LD_LIBRARY_PATH环境变量指定的目录下找需要的.so,所以这里一定要指定在当前目录,如果不指定,可以把产生的so文件复制到/usr/lib下也可以。

Golang调用静态库.a

产生静态库只是编译的时候产生.a的静态库,库与测试程序代码如上,编译方法是:

jack@jack-VirtualBox:~/mygo/src/mylib$ go build -buildmode=c-archive -o libexptest.so exptest.go jack@jack-VirtualBox:~/mygo/src/mylib$ lsexptest.go  libexptest.h  libexptest.a````应用程序编译的方法如下:<div class="se-preview-section-delimiter"></div>

$ gcc -o exptest exptest.c libexptest.a
“`

阅读全文
0 0
原创粉丝点击