美文网首页
MacOS下使用cgo交叉编译

MacOS下使用cgo交叉编译

作者: 独自天涯_a9ba | 来源:发表于2019-05-29 18:19 被阅读0次

最近研究了一下jna,发现可以用go干点事情。
基本步骤:

  1. 安装go (这句就是废话)
  2. 安装docker(用来下载用户交叉编译的镜像文件,该文件包含各个平台的gcc)
  3. 安装xgo工具(第三方工具,比自己用CC编译方便太多)
  4. 编写计划被编译成动态库文件的go源码
  5. 编写java代码,使用jna连接动态库函数

一、安装go

略过,本人安装的是 go 1.11

二、安装docker

仍然略过

三、安装xgo工具

第三方工具,比自己用CC指定gcc方便太多

  1. 首先使用docker下载含有依赖的各平台gcc工具包镜像
docker pull karalabe/xgo-latest

这个镜像由于属于 all-in-one的形式,所以会很大,请耐心等待。。。。

  1. 安装xgo工具:安装前,如果开启了module的话,建议关闭掉
go get -u github.com/karalabe/xgo
  1. 测试安装是否成功
@admin.local ➜ gopath  xgo
Checking docker installation...
Client: Docker Engine - Community
 Version:           18.09.2
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        6247962
 Built:             Sun Feb 10 04:12:39 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.2
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.6
  Git commit:       6247962
  Built:            Sun Feb 10 04:13:06 2019
  OS/Arch:          linux/amd64
  Experimental:     true

2019/05/29 18:09:35 Usage: xgo [options] <go import path>

至此,xgo安装大功告成;具体使用,后面单说

四、编写要编译为动态库函数的go代码

package main

import "C"
import "fmt"

//export Sum
func Sum(a int, b int) int {
    return a + b
}

//export Name
func Name(fname *C.char) *C.char {
    result := fmt.Sprintf("Hello, %s", C.GoString(fname))
    fmt.Printf(result)
    return C.CString(result)
}

func main()  {
    //fmt.Printf(string(Name("abc")))
}
  1. 其中,如果要将go使用cgo编译为动态库函数,需要源码包中导入C
import "C"
  1. 再次,要导出的函数前必须要进行 export 该函数
//export Sum
  1. 要导出的动态函数,必须在main包下,且必须包含main函数
func main(){}
  1. 关于go语音中的string类型,使用c导出时,使用 *C.char ,方便Java传递和接收String类型参数;go中将 C.char 参数转为string使用 C.GoString() 函数;go中将string类型转为C.char使用 C.CString() 函数

五、编译动态库文件

由于库文件运行的平台不一样,所需文件也不一样,所以我们要确定运行的平台。我这边需要再mac和ubuntu下运行。查看ubuntu系统指令集:

root@a:/usr/local/tomcat/bin# dpkg --print-architecture
amd64

说明我们目标系统

GOOS=linux
GOARCH=amd64

确定好后,回过头来,使用我们的交叉编译工具xgo,进行交叉编译,生成目标平台动态库文件:

bash-3.2$ xgo -buildmode=c-shared -out libwxsum --targets=linux/amd64,darwin/amd64 .
Checking docker installation...
Client: Docker Engine - Community
 Version:           18.09.2
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        6247962
 Built:             Sun Feb 10 04:12:39 2019
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.2
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.6
  Git commit:       6247962
  Built:            Sun Feb 10 04:13:06 2019
  OS/Arch:          linux/amd64
  Experimental:     true

Checking for required docker image karalabe/xgo-latest... found.
Cross compiling wx_mini...
Building locally wx_mini...
Compiling for linux/amd64...
go get: warning: modules disabled by GO111MODULE=auto in GOPATH/src;
    ignoring go.mod;
    see 'go help modules'
Cleaning up build environment...

其中命令为:

xgo -buildmode=c-shared -out libwxsum --targets=linux/amd64,darwin/amd64 .

-buildmode=c-shared : 说明要编译为动态库函数方便jna调用
-out libwxsum : 说明我们要生成的各个平台下动态库函数的前缀
--targets=linux/amd64,darwin/amd64 : 说明我们生成目标为

GOOS=linux GOARCH=amd64 //ubuntu
GOOS=darwin GOARCH=amd64 //MacOS

的动态库函数。
编译完成后可以看到生成的指定平台下的动态库函数:

bash-3.2$ ls
libwxsum-darwin-10.6-amd64.dylib libwxsum-linux-amd64.so
go.mod                           libwxsum-darwin-10.6-amd64.h     main.go
go.sum                           libwxsum-linux-amd64.h           util

其中的 libwxsum-linux-amd64.so 为生成的对应 ubuntu 下的动态库函数,libwxsum-darwin-10.6-amd64.dylibMacOS下 的动态库函数。
至此,动态库函数的交叉编译完成。
注:如果还需要编译其他包下文件(如上的util包依赖了其他的开源框架),需要使用

--pkg util/goimports 开源框架git地址

六、编写Java代码使用动态库函数

  1. java工程使用maven管理,最终部署为web应用,需要添加jna依赖
        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna-platform</artifactId>
            <version>5.3.1</version>
        </dependency>
  1. 创建接口继承jna的Library,并定义出要调用的动态库函数
public interface LibSum extends Library {
    LibSum INSTANCE = (LibSum) Native.loadLibrary("wxsum", LibSum.class);

    int Sum(int a, int b);

    String Name(String fname);
}

其中,loadLibrary函数中的第一个参数,标明动态库函数名,该名称为我们之前生成动态库函数名字,去掉前缀 lib 的名字,并且为了方便跨平台,后面的扩展名也会由 jna 根据当前运行环境自动补齐调用。

  1. 编写web请求调用
    @RequestMapping("sum")
    @ResponseBody
    public ResultModel sum(
            @RequestParam(name = "a", required = true) int a,
            @RequestParam(name = "b", required = true) int b,
            @RequestParam(name = "w", required = true) String w) {
        int result = LibSum.INSTANCE.Sum(a, b);
        String name = LibSum.INSTANCE.Name(w);
        return ResultModel.getSuccess(name + " ; Your score is : " + result);
    }
  1. 将动态库函数放入指定目录,本人编写的是web应用且需要再ubuntu下运行,所以需要将库函数放在 resources/linux-x86-64 下(linux-x86-64是jna根据当前系统自动增加的)。

至此,我们编写的使用go函数生成各平台动态库的列子就算完成了。

注:

  1. 我们可以使用
System.setProperty("jna.debug_load","true");

打印动态库函数调用路径,便于观察库文件加载过程

  1. 可以使用
System.setProperty("jna.library.path", "/usr/local/tomcat/webapps/ROOT/solib/");

指定加载库文件路径

相关文章

网友评论

      本文标题:MacOS下使用cgo交叉编译

      本文链接:https://www.haomeiwen.com/subject/kohutctx.html