Kotlin编写JNI应用:如何通过Gradle生成Native头文件?
解决Kotlin JNI项目中无法生成.h头文件的问题
问题根源
你当前的Gradle配置只给compileJava任务设置了头文件输出,但Kotlin代码的编译是由compileKotlin任务负责的。javac的头文件生成逻辑只会处理Java编译的字节码,不会自动处理Kotlin编译后的字节码,所以才会出现无法生成.h文件的情况。
解决方案
修改Gradle配置,让Kotlin编译任务完成后,自动调用javac处理生成的字节码来生成JNI头文件,具体步骤如下:
1. 替换原有编译配置
删掉原来的compileJava代码块,添加针对Kotlin编译任务的配置:
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions.jvmTarget = "1.8" // 匹配你的项目JVM版本,可根据实际调整 doLast { // 定义头文件输出目录,确保和你原配置路径一致 def headerOutputDir = file('src/main/java/idk/bluecross/JMM/natives') headerOutputDir.mkdirs() // 自动创建目录,避免不存在导致报错 // 调用javac处理Kotlin生成的字节码,生成JNI头文件 exec { commandLine = [ "${System.getProperty('java.home')}/bin/javac", "-h", headerOutputDir.absolutePath, "-cp", sourceSets.main.runtimeClasspath.asPath, "${destinationDir}/idk/bluecross/**/*.class" // 替换为你的Kotlin类所在包路径 ] } } }
2. 验证配置效果
执行gradle compileKotlin任务,之后去src/main/java/idk/bluecross/JMM/natives目录下查看,应该能看到对应external fun hi()的.h头文件了。如果没生成,检查一下包路径是否和你的Kotlin类实际路径匹配。
3. 完整修改后的build.gradle
把原来的compileJava块替换成上面的代码后,完整配置如下:
plugins { id 'java' id 'org.jetbrains.kotlin.jvm' version '1.8.0-RC2' id 'application' id 'cpp' } group 'idk.bluecross' version '1.0-SNAPSHOT' application.mainClass = 'idk.bluecross.example.Main' application { applicationDefaultJvmArgs += ["-Djava.library.path=" + file("${buildDir}/libs/jMM/shared").absolutePath] } // 替换原来的compileJava配置,新增Kotlin编译后的头文件生成逻辑 tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach { kotlinOptions.jvmTarget = "1.8" doLast { def headerOutputDir = file('src/main/java/idk/bluecross/JMM/natives') headerOutputDir.mkdirs() exec { commandLine = [ "${System.getProperty('java.home')}/bin/javac", "-h", headerOutputDir.absolutePath, "-cp", sourceSets.main.runtimeClasspath.asPath, "${destinationDir}/idk/bluecross/**/*.class" ] } } } repositories { mavenCentral() } dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" } model { platforms { x64 { architecture "x86_64" } } components { JMM(NativeLibrarySpec) { sources { cpp { source { srcDir "src/main/java/idk/bluecross/JMM/natives" } } } targetPlatform "x64" binaries.all { def jvmHome = System.properties['java.home'] if (targetPlatform.operatingSystem.macOsX) { cppCompiler.args '-I', "${jvmHome}/include" cppCompiler.args '-I', "${jvmHome}/include/darwin" cppCompiler.args '-mmacosx-version-min=10.4' linker.args '-mmacosx-version-min=10.4' } else if (targetPlatform.operatingSystem.linux) { cppCompiler.args '-I', "${jvmHome}/include" cppCompiler.args '-I', "${jvmHome}/include/linux" cppCompiler.args '-D_FILE_OFFSET_BITS=64' } else if (targetPlatform.operatingSystem.windows) { cppCompiler.args "-I${jvmHome}/include" cppCompiler.args "-I${jvmHome}/include/win32" } else if (targetPlatform.operatingSystem.freeBSD) { cppCompiler.args '-I', "${jvmHome}/include" cppCompiler.args '-I', "${jvmHome}/include/freebsd" } } } } } classes.dependsOn 'JMMSharedLibrary'
额外提示
- Kotlin的
external fun编译后生成的字节码和Java的native方法结构完全一致,所以用javac处理完全可行 - 如果你调整了Kotlin类的包路径,记得同步修改
${destinationDir}/idk/bluecross/**/*.class中的路径 - 确保你的JDK环境变量正常,
${System.getProperty('java.home')}能正确指向JDK目录
内容的提问来源于stack exchange,提问作者Bluecross
相关产品推荐
相关产品推荐

