美文网首页
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