如何从我的 Go 代码中调用 Java Native Interface C 函数?
How do I call a Java Native Interface C function from my Go code?
我打算使用 golang C
库在 Golang 中实现我的 Java 本机接口函数。
现在我想使用 JNI 函数 GetStringUTFChars
将 jstring
转换为 UTF-8 字符串,但在执行此操作时出现错误。这些是我完成的步骤:
在我定义 JNI 方法的 Java class(称为 MyClass)中,我有:
public static native void print(String msg);
使用 javah
,我生成了 .h
-文件,其中包含 C 语言定义的函数:
JNIEXPORT void JNICALL Java_com_mypackage_MyClass_print
(JNIEnv *, jclass, jstring);
然后,在我的 Go 代码中有以下代码:
package main
// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include
// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include/darwin
/*
#include <jni.h>
*/
import "C"
//export Java_com_mypackage_MyClass_print
func Java_com_mypackage_MyClass_print(env *C.JNIEnv, clazz C.jclass, str C.jstring) {
_ = C.GetStringUTFChars(env, str, 0)
}
当我构建 go
文件时使用:
go build -buildmode=c-shared -o libmyclass.dylib libmyclass.go
然后我得到以下错误:
could not determine kind of name for C.GetStringUTFChars
我应该如何调用 JNI spec 中定义的 GetStringUTFChars
以便我可以使用 fmt.println
打印字符串?
编辑 2
删除了 "edit 1" 因为上面的过程是正确的,只是没有设置 LD_LIBRARY_PATH 变量。
像GetStringUTFChars
这样的JNI函数是函数指针,不能直接从Go中调用。您必须将所需的函数包装在一个单独的 C 文件中。例如
jx.c
#include <jni.h>
const char* jx_GetStringUTFChars(JNIEnv *env, jstring str, jboolean *isCopy) {
return (*env)->GetStringUTFChars(env, str, isCopy);
}
从 C 文件创建库后,您的 Go 文件将如下所示:
package main
/*
#cgo CFLAGS: -I/usr/java/jdk1.8.0_162/include/ -I/usr/java/jdk1.8.0_162/include/linux/
#cgo LDFLAGS: -L${SRCDIR}/ -ljx
#include "jx.h"
*/
import "C"
import (
"fmt"
)
//export Java_com_mypackage_MyClass_print
func Java_com_mypackage_MyClass_print(env *C.JNIEnv, clazz C.jclass, str C.jstring) {
s := C.jx_GetStringUTFChars(env, str, (*C.jboolean)(nil))
fmt.Println(C.GoString(s))
}
func main() {}
之所以有一个单独的 C 文件只是为了包装函数,是因为文档中的这个条款:
Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not contain any definitions, only declarations.
我打算使用 golang C
库在 Golang 中实现我的 Java 本机接口函数。
现在我想使用 JNI 函数 GetStringUTFChars
将 jstring
转换为 UTF-8 字符串,但在执行此操作时出现错误。这些是我完成的步骤:
在我定义 JNI 方法的 Java class(称为 MyClass)中,我有:
public static native void print(String msg);
使用 javah
,我生成了 .h
-文件,其中包含 C 语言定义的函数:
JNIEXPORT void JNICALL Java_com_mypackage_MyClass_print
(JNIEnv *, jclass, jstring);
然后,在我的 Go 代码中有以下代码:
package main
// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include
// #cgo CFLAGS: -I/Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/include/darwin
/*
#include <jni.h>
*/
import "C"
//export Java_com_mypackage_MyClass_print
func Java_com_mypackage_MyClass_print(env *C.JNIEnv, clazz C.jclass, str C.jstring) {
_ = C.GetStringUTFChars(env, str, 0)
}
当我构建 go
文件时使用:
go build -buildmode=c-shared -o libmyclass.dylib libmyclass.go
然后我得到以下错误:
could not determine kind of name for C.GetStringUTFChars
我应该如何调用 JNI spec 中定义的 GetStringUTFChars
以便我可以使用 fmt.println
打印字符串?
编辑 2
删除了 "edit 1" 因为上面的过程是正确的,只是没有设置 LD_LIBRARY_PATH 变量。
像GetStringUTFChars
这样的JNI函数是函数指针,不能直接从Go中调用。您必须将所需的函数包装在一个单独的 C 文件中。例如
jx.c
#include <jni.h>
const char* jx_GetStringUTFChars(JNIEnv *env, jstring str, jboolean *isCopy) {
return (*env)->GetStringUTFChars(env, str, isCopy);
}
从 C 文件创建库后,您的 Go 文件将如下所示:
package main
/*
#cgo CFLAGS: -I/usr/java/jdk1.8.0_162/include/ -I/usr/java/jdk1.8.0_162/include/linux/
#cgo LDFLAGS: -L${SRCDIR}/ -ljx
#include "jx.h"
*/
import "C"
import (
"fmt"
)
//export Java_com_mypackage_MyClass_print
func Java_com_mypackage_MyClass_print(env *C.JNIEnv, clazz C.jclass, str C.jstring) {
s := C.jx_GetStringUTFChars(env, str, (*C.jboolean)(nil))
fmt.Println(C.GoString(s))
}
func main() {}
之所以有一个单独的 C 文件只是为了包装函数,是因为文档中的这个条款:
Using //export in a file places a restriction on the preamble: since it is copied into two different C output files, it must not contain any definitions, only declarations.