$ rustup --version rustup 1.27.0 (bbb9276d2 2024-03-08) info: This is the version for the rustup toolchain manager, not the rustc compiler. info: The currently active `rustc` version is `rustc 1.76.0 (07dca489a 2024-02-04)`
val output = ByteArrayOutputStream().use { project.exec { commandLine(javap, "-private", "-cp", buildDir.absolutePath, file.absolutePath) standardOutput = it }.assertNormalExitValue() it.toString() }
val (qualifiedName, methodInfo) = bodyExtractingRegex.find(output)?.destructured ?: return@forEach
val lastDot = qualifiedName.lastIndexOf('.') val packageName = qualifiedName.substring(0, lastDot) val className = qualifiedName.substring(lastDot+1, qualifiedName.length)
val nativeMethods = nativeMethodExtractingRegex.findAll(methodInfo).mapNotNull { it.groups }.flatMap { it.asSequence().mapNotNull { group -> group?.value } }.toList() if (nativeMethods.isEmpty()) return@forEach
val source = buildString { appendln("package $packageName;") appendln("public class $className {") for (method in nativeMethods) { if ("()"in method) appendln(method) else { val updatedMethod = StringBuilder(method).apply { var count = 0 var i = 0 while (i < length) { if (this[i] == ',' || this[i] == ')') insert(i, " arg${count++}".also { i += it.length + 1 }) else i++ } } appendln(updatedMethod) } } appendln("}") } val outputFile = tmpDir.resolve(packageName.replace(".", "/")).apply { mkdirs() }.resolve("$className.java").apply { delete() }.apply { createNewFile() } outputFile.writeText(source)
println("Generating for ${outputFile.absolutePath} into ${jniHeaderDir.absolutePath}") project.exec { commandLine(javac, "-h", jniHeaderDir.absolutePath, outputFile.absolutePath) }.assertNormalExitValue() } } }
application { // Define the main class for the application. mainClass = "top.srcres.apps.rustjnidemo.App" applicationDefaultJvmArgs = listOf( "-Djava.library.path=../../rust/target/release/" ) }
运行 ./gradlew run , Java 程序出现以下输出,代表成功调用 Rust 代码所编写的 native 实现。
#[allow(non_snake_case)] #[no_mangle] pubextern"system"fnJava_top_srcres_apps_rustjnidemo_App_helloFromTestIntField<'a>( mut env: JNIEnv<'a>, class: JClass<'a> ) -> jint { lettestInt = env.get_static_field(&class, "testInt", "I") .expect("Failed to get static field testInt") .i() .expect("Failed to convert testInt into jint"); testInt + 114 }
#[allow(non_snake_case)] #[no_mangle] pubextern"system"fnJava_top_srcres_apps_rustjnidemo_App_helloFromTestStringField<'a>( mut env: JNIEnv<'a>, class: JClass<'a> ) -> jstring { lettestStringObj = env.get_static_field(&class, "testString", "Ljava/lang/String;") .expect("Failed to get static field testString") .l() .expect("Failed to convert testString into JObject"); lettestString: String = env.get_string(&JString::from(testStringObj)) .expect("Failed to get the value of testString") .into(); letoutput = env.new_string(create_rust_string(&testString)).expect("Failed to create Rust string."); output.into_raw() }
#[allow(non_snake_case)] #[no_mangle] pubextern"system"fnJava_top_srcres_apps_rustjnidemo_App_modifyTestStringFromRust<'a>( mut env: JNIEnv<'a>, class: JClass<'a>, input: JString<'a> ) { letinputStr: String = env.get_string(&input).expect("Failed to receive the argument: input").into(); lettestStringFromRust = env.new_string(create_rust_string(&inputStr)).expect("Failed to create Rust string."); lettestStringFromRustObj = JObject::from(testStringFromRust); lettestStringFromRustId = env.get_static_field_id(&class, "testStringFromRust", "Ljava/lang/String;") .expect("Failed to get the ID of static field testStringFromRust"); env.set_static_field(&class, &testStringFromRustId, JValue::from(&testStringFromRustObj)) .expect("Failed to set static field testStringFromRust"); }
#[allow(non_snake_case)] #[no_mangle] pubextern"system"fnJava_top_srcres_apps_rustjnidemo_App_actCallFromRust<'a>( mut env: JNIEnv<'a>, class: JClass<'a>, input: JString<'a> ) -> jstring { letinputStr: String = env.get_string(&input).expect("Failed to receive the argument: input").into(); lettestStringFromRust = env.new_string(create_rust_string(&inputStr)).expect("Failed to create Rust string."); lettestStringFromRustObj = JObject::from(testStringFromRust); letcallFromRustResult = env.call_static_method(&class, "callFromRust", "(Ljava/lang/String;)Ljava/lang/String;", &[JValue::from(&testStringFromRustObj)]) .expect("Failed to invoke static method callFromRust"); letcallFromRustResultObj = callFromRustResult.l().expect("Failed to convert the method result into JObject."); JString::from(callFromRustResultObj).into_raw() }