为 Kotlin android 编译库,rust and go

Compile libraries for Kotlin android,rust and go

这个问题本质上是探索性的,不确定这是否适合堆栈溢出问答。

上下文:

我有一个用 golang 编写的库,我需要编译它以供多个服务使用。

这些服务在 Kotlin android、Rust、Golang 中。

我知道的唯一选择是使用类似 SWIG 的东西来编译不同语言的 go 库。

问题:

  1. 我认为 SWIG 不适用于 Kotlin。

我正在努力寻找最好的方法来做到这一点以及可以做到这一点的不同方法。

对于任何可以生成 C 共享库和头文件的语言,您都可以使用 SWIG 对其进行包装。同样,对于 运行 在 JVM 中并且可以调用 Java 类 的任何语言,您都可以使用 SWIG 自动生成的 Java 绑定。

因此我们可以做一系列看起来像这样的事情:

Go -> C -> JNI -> Java -> Kotlin

它实际上是相当理智的。我在下面整理了一个示例来展示它是如何工作的,因为我很好奇以前从未写过 Go 或 Kotlin。 (因此,请稍加怀疑,我可能都没有达到“最佳实践”!)

此示例假设您有一个可用的 JDK/JRE、C 编译器、Go 安装和 kotlinc。

我的 demo.go 看起来像这样:

package main

import ("C"
        "fmt")

//export TestGoFunc
func TestGoFunc(str *C.char) *C.char {
        fmt.Printf("Got string: %s\n", C.GoString(str))
        return nil
}

func main() {}

而 hello.kt 看起来像这样:

fun main() {
    println("Hello, World!")
    test.TestGoFunc("Another string")
}

为了包装这个,我编写了以下 SWIG 接口:

%module test

%{
#include "golib.h"
%}

%include <typemaps.i>

%pragma(java) jniclasscode=%{
  static {
    System.loadLibrary("test");
  }
%}

// Assuming you don't care about these in your library silence/neaten stuff
#define _Complex
%ignore _GoString_;
%ignore GoComplex64;
%ignore GoComplex128;
%ignore GoSlice;
%ignore GoInterface;

%include "golib.h"

这是一个相当标准的 SWIG 接口,用于定位 Java - 它在生成的头文件中隐藏了一些我们不关心的内容,并使用 Java 自动加载 .so 文件给我们的 pragma。

然后我整理了一个小的 Makefile 来构建所有内容,因为这个构建有很多步骤:

all: libtest.so hello.jar

golib.so: demo.go
        go build -o golib.so -buildmode=c-shared demo.go

test_wrap.c: golib.so test.i
        swig3.0 -java -Wall test.i

libtest.so: test_wrap.c
        gcc -shared -Wall -Wextra test_wrap.c -o libtest.so ./golib.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux

hello.jar: hello.kt
        javac *.java
        kotlinc hello.kt -include-runtime -d hello.jar -cp .
        jar uvf hello.jar *.class

如果我们构建并 运行 这一切都会很好地工作:

$ make
go build -o golib.so -buildmode=c-shared demo.go
swig3.0 -java -Wall test.i
gcc -shared -Wall -Wextra test_wrap.c -o libtest.so ./golib.so -I/usr/lib/jvm/default-java/include/ -I/usr/lib/jvm/default-java/include/linux
javac *.java
kotlinc hello.kt -include-runtime -d hello.jar -cp .
jar uvf hello.jar *.class
adding: test.class(in = 302) (out= 216)(deflated 28%)
adding: testJNI.class(in = 389) (out= 268)(deflated 31%)
$ LD_LIBRARY_PATH=. java -jar hello.jar
Hello, World!
Got string: Another string

我很想使用 -buildmode=c-archive 去构建一个静态库,然后 link 将其放入 SWIG 共享对象中,而不是只是为了让事情在这方面更简单。