首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Kotlin取代javah

Kotlin取代javah
EN

Stack Overflow用户
提问于 2018-02-15 21:00:49
回答 5查看 2.6K关注 0票数 16

自JDK 8以来已被弃用,并将在JDK 10中删除。,根据JEP 313和弃用文本,应该使用带有-h标志的javac

警告:计划在下一个主要的JDK发行版中删除javah工具。该工具已被JDK 8中添加到javac中的'-h‘选项所取代。建议用户迁移到使用javac '-h’选项;有关更多信息,请参见javac手册页。

问题是,javah对已编译的.class文件进行操作,而javac则对源文件(即.java文件)进行操作。

javah可以很好地处理Kotlin和external函数,因为所有东西最终都编译成Java字节码,但是由于在使用Kotlin时没有任何Java源文件,所以我认为javac -h无法工作。

Kotlin是否有javah替代品或解决方案?

EN

回答 5

Stack Overflow用户

发布于 2018-04-11 07:17:24

我推荐gjavap

将来,我还将实现一个更易于使用的命令行工具,它提供了与javap类似的功能。

票数 4
EN

Stack Overflow用户

发布于 2020-03-08 02:49:54

目前还没有内置的方法来做到这一点。这是关于Kotlin问题追踪器的公开问题是在2019年11月发布的,但到目前为止,它还没有被排序,也没有目标版本。

使用JDK 10+生成标头的唯一方法是使用javac -h,它只适用于javac -h源代码,而不是Kotlin。我在如何用Java 10 -丑陋的方式解决缺少的javah中测试了该方法,该方法由Oo.oO链接,目前作为一个解决方案。这些步骤是:

  1. 使用javap将字节码反编译回Java
  2. 编辑反编译的Java,使其适合生成头文件(将文件简化为native方法定义)。
  3. 通过javac -h运行反编译的Java代码以生成标头

我正在考虑编写一个gradle脚本来完成这个任务(或者希望其他人比我更好!)如果我能完成这件事,我会更新这篇文章。

票数 3
EN

Stack Overflow用户

发布于 2021-01-11 04:18:12

我编写了一个简单的gradle任务来生成JNI头,它的方法类似于@Oo.oO发布的方法,但与gradle有更好的集成,因此可以在Windows和基于Unix的操作系统上运行。

代码语言:javascript
复制
val generateJniHeaders by tasks.creating {
    group = "build"
    dependsOn(tasks.getByName("compileKotlinJvm"))

    // For caching
    inputs.dir("src/jvmMain/kotlin")
    outputs.dir("src/jvmMain/generated/jni")

    doLast {
        val javaHome = 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/jvm/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 = 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)

                project.exec {
                    commandLine(javac, "-h", jniHeaderDirectory.absolutePath, outputFile.absolutePath)
                }.assertNormalExitValue()
            }
    }
}
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48816188

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档