问题

最近在用kotlin写jni,但是生成头文件的时候遇到了些问题。

首先 javah 在java >= 1.9 就被取消用javac -h代替,但是javac对kotlin不适用,kotlinc也没有 -h 这个生成头文件的选项。

解决方法

在stackoverflow论坛找到了个解决方案,那个人提供了一个gradle task,大概原理是先用complieKotlin任务(或kotlinc)生成class字节码,再用javac编译回java文件,然后再调用javac -h 针对那个java文件生成jni头文件,我稍微修复了下,然后迁移到gradle kotlin dsl(就kts脚本),代码在下面。

使用方法

复制到build.gradle.kts的最外层就可以了,然后sync一下gradle,然后在gradle task里的build分类下就有generate jniheader这个任务了,StackOverflow原贴地址https://stackoverflow.com/a/65661275/14646226

需要改下代码里的inputs.dir("src/main/kotlin")到你的kt源码文件夹, outputs.dir("src/main/generated/jni")到你想的输出文件夹

代码

val generateJniHeaders: Task by tasks.creating {
group = "build"
dependsOn(tasks.getByName("compileKotlin")) // For caching
inputs.dir("src/main/kotlin")
outputs.dir("src/main/generated/jni") doLast {
val javaHome = org.gradle.internal.jvm.Jvm.current().javaHome
val javap = javaHome.resolve("bin").walk().firstOrNull { it.name.startsWith("javap") }?.absolutePath ?: error("javap not found")
val javac = javaHome.resolve("bin").walk().firstOrNull { it.name.startsWith("javac") }?.absolutePath ?: error("javac not found")
val buildDir = file("build/classes/kotlin/main")
val tmpDir = file("build/tmp/jvmJni").apply { mkdirs() } val bodyExtractingRegex = """^.+\Rpublic \w* ?class ([^\s]+).*\{\R((?s:.+))\}\R$""".toRegex()
val nativeMethodExtractingRegex = """.*\bnative\b.*""".toRegex() buildDir.walkTopDown()
.filter { "META" !in it.absolutePath }
.forEach { file ->
if (!file.isFile) return@forEach val output = com.gradle.publish.plugin.dep.org.apache.commons.io.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 {
appendLine("package $packageName;")
appendLine("public class $className {")
for (method in nativeMethods) {
if ("()" in method) appendLine(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++
}
}
appendLine(updatedMethod)
}
}
appendLine("}")
}
val outputFile = tmpDir.resolve(packageName.replace(".", "/")).apply { mkdirs() }.resolve("$className.java").apply { delete() }.apply { createNewFile() }
outputFile.writeText(source) project.exec {
commandLine(javac, "-h", "src/main/generated/jni", outputFile.absolutePath)
}.assertNormalExitValue()
}
}
}

gradle task位置截图

kotlin gradle 生成jni头文件的更多相关文章

  1. ubuntu下整合eclipse和javah生成jni头文件开发android的native程序(转)

    本文介绍两种利用javah命令生成jni头文件的方法,第一种为大众所知的javah命令,第二种为整合javah到eclipse里面.推荐第二种方式,方便快捷,随时修改随时生成 0:前提和条件: 1:u ...

  2. ubuntu下整合eclipse和javah生成jni头文件开发android的native程序

    0:前言: 这两天一直在研究用android的jni调用第三方库,上网搜方法,但是都是泛泛而谈,没有demo,经过我几番折磨,写了n多的helloword工程,总是不成功,工程名字也就由helloow ...

  3. Android NDK入门实例 计算斐波那契数列一生成jni头文件

    最近要用到Android NDK,调用本地代码.就学了下Android NDK,顺便与大家分享.下面以一个具体的实例计算斐波那契数列,说明如何利用Android NDK,调用本地代码.以及比较本地代码 ...

  4. Java 生成 JNI 头文件

    [参考文章]:javah javac 命令行生成native的方法教程 [参考文章]:用javah 导出类的头文件, 常见的错误及正确的使用方法 项目需要调用 C++动态库,由于项目包结构发生变化,需 ...

  5. javah生成jni头文件时报错 Error: cannot access android.support...

    javah生成jni头文件时报错: Error: cannot access android.support.v7.app.AppCompatActivity class file for andro ...

  6. [转]ubuntu下整合eclipse和javah生成jni头文件开发android的native程序

    转载自:http://blog.csdn.net/jiuyueguang/article/details/9404237 本文介绍两种利用javah命令生成jni头文件的方法,第一种为大众所知的jav ...

  7. 一键生成JNI头文件方法二

    经常使用java的同学一定都接触过JNI(Java Native Interface)吧.JNI为我们提供了java<---->C/C++之间的接口,使得我们可以在java中调用C程序,以 ...

  8. 使用javah生成jni 头文件和使用ndk编译so库

    1.jni 首先clean Project,在makeProject生成对应的class文件 然后点出命名框,输入命令: cd app/build/intermediates/classes/debu ...

  9. Android NDK学习(3)使用Javah命令生成JNI头文件 .

    转:http://www.cnblogs.com/fww330666557/archive/2012/12/14/2817387.html 第一步: 在Eclipse中创建android项目,并声明N ...

随机推荐

  1. fragment之间相互传数据、共享数据

    在 Fragment 之间共享数据 Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象.想象一下拆分视图 (master-detail) Fragment 的常见情况, ...

  2. C语言编译器开发之旅(开篇)

    编译器写作之旅   最近在Github上看到一个十分有趣的项目acwj(A Compiler Writing Journey),一个用C语言编写编译器的项目.身为一个程序员,这在我看来是一件十分酷的事 ...

  3. Camera噪声问题

    Camera噪声问题 Camera RGB 域的噪声 以上部分属于sensor processing,接下来的部分属于color.luminance processing. gamma gamma是在 ...

  4. 人脸真伪验证与识别:ICCV2019论文解析

    人脸真伪验证与识别:ICCV2019论文解析 Face Forensics++: Learning to Detect Manipulated Facial Images 论文链接: http://o ...

  5. CUDA上的量化深度学习模型的自动化优化

    CUDA上的量化深度学习模型的自动化优化 深度学习已成功应用于各种任务.在诸如自动驾驶汽车推理之类的实时场景中,模型的推理速度至关重要.网络量化是加速深度学习模型的有效方法.在量化模型中,数据和模型参 ...

  6. TensorFlow csv读取文件数据(代码实现)

    TensorFlow csv读取文件数据(代码实现) 大多数人了解 Pandas 及其在处理大数据文件方面的实用性.TensorFlow 提供了读取这种文件的方法. 前面章节中,介绍了如何在 Tens ...

  7. python应用_读取Excel数据【二】_二次封装之函数式封装

    目的:想要把对Excel文件读取做成一个通用的函数式封装,便于后续简单调用,隔离复杂性. 未二次封装前原代码: #coding=gbkimport osimport xlrdcurrent_path= ...

  8. Java日期时间API系列39-----中文语句中的时间语义识别(time NLP 输入一句话,能识别出话里的时间)原理分析

    NLP (Natural Language Processing) 是人工智能(AI)的一个子领域.自然语言是人类智慧的结晶,自然语言处理是人工智能中最为困难的问题之一(来自百度百科). 其中中文更是 ...

  9. java后端知识点梳理——多线程与高并发

    进程与线程 进程是一个"执行中的程序",是系统进行资源分配和调度的一个独立单位 线程是进程的一个实体,一个进程中一般拥有多个线程. 线程和进程的区别 进程是操作系统分配资源的最小单 ...

  10. 【工具解析】瑞士军刀bettercap2.X解析_第一期_编写HTTP代理注入模块_http(s).proxy.script

    /文章作者:Kali_MG1937 CNBLOG博客号:ALDYS4 QQ:3496925334/ 前言 bettercap已经从1.6更新至2.0版本 语言也从ruby改为了go 编写注入模块指定的 ...