我有一个使用Kotlin Gradle插件的Gradle项目。我想构建一个Java 9模块,所以我的目录结构如下所示:
src/main/java/
- module-info.java
src/main/kotlin/
- Foo.kt
- Bar.kt
build.gradle
...
我的build.gradle
声明了以下依赖项:
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.10"
compile "org.jetbrains.kotlin:kotlin-reflect:1.2.10"
compile "org.junit.jupiter:junit-jupiter-api:5.0.2"
}
我在我的Kotlin源代码中使用了所有这些依赖项(Foo.kt
,Bar.kt
,...)。
如果我这样写module-info.java
,那么一切都很有效:
module my.module {
requires kotlin.stdlib;
exports my.module.pkg;
}
如果我使用this technique在javac
任务期间将所有编译时依赖项提供给compileJava
。
然而如果我在-Xlint:all
任务期间打开compileJava
Java编译器(编译module-info.java
),我会收到以下警告:
/path/to/my.module/src/main/java/module-info.java:26: warning: requires directive for an automatic module
requires kotlin.stdlib;
^
所以这里我们有Java编译器,javac
抱怨kotlin.stdlib
是一个自动模块,因此我不应该有requires
子句。
但是,如果我删除requires
子句以使javac
满意,那么kotlinc
会比javac
更加愤怒(我收到的错误不是警告):< / p>
e: /path/to/my.module/src/main/java/module-info.java: The Kotlin standard library is not found in the module graph. Please ensure you have the 'requires kotlin.stdlib' clause in your module definition
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':my.module:compileKotlin'.
现在我也可以通过编辑我的compileKotlin
任务来解决这个问题:
compileKotlin {
doFirst {
kotlinOptions.freeCompilerArgs = ['-Xallow-kotlin-package']
}
}
但这只会在compileKotlin
任务期间导致更多错误,所有这些都看起来像这样:
e: /path/to/my.module/src/main/kotlin/Foo.kt: (27, 30): Symbol is declared in module 'org.junit.jupiter.api' which current module does not depend on
然后,如果我尝试通过将compileKotlin
添加到"-Xmodule-path=${classpath.asPath}"
并将freeCompilerArgs
设置为空来强制classpath
获取模块路径而不是类路径,那么Kotlin编译器根本找不到任何东西,我最终得到了数以万计的未解决的参考错误!
为什么Kotlin编译器告诉我,当Java编译器说相反时,我必须拥有requires kotlin.stdlib;
?如何让Kotlin和Java一起工作来生成Java 9模块?
答案 0 :(得分:2)
如果您在Kotlin中编写Java 9模块,则必须在requires kotlin.stdlib
中声明module-info.java
以满足已编译的Kotlin代码的运行时依赖性以及显式依赖性标准库API。
javac
警告您在启用lint时需要自动模块,因为与普通模块相比,自动模块有一些潜在的drawbacks。在将标准库编译为普通模块之前,您必须处理此警告。
-Xallow-kotlin-package
编译器标志允许您省略require kotlin.stdlib
,因为它仅在编译标准库本身时使用。显然,如果你指定这个标志并省略了那个要求,你将无法使用标准库中的任何API,所以这对你来说不是一个真正的选择。
答案 1 :(得分:1)
我发现简单地禁止使用自动模块的警告是最容易的。 (就我而言,无论是否需要,我都必须使用一些自动模块,因此这些警告只是分散噪音。)我在build.gradle.kts中包含以下内容:
val compilerArgs = listOf(
"-Xlint:all", // Enable all warnings except...
"-Xlint:-requires-automatic", // Suppress "requires directive for an automatic module" warnings from module-info.java
"-Xlint:-requires-transitive-automatic" // Suppress "requires transitive directive for an automatic module" warnings from module-info.java
)
// This task will compile all Java code in the target module except for test code.
tasks.compileJava {
doFirst {
options.compilerArgs.addAll(compilerArgs)
}
}
// This task will compile all Java test code in the target module.
tasks.compileTestJava {
doFirst {
options.compilerArgs.addAll(compilerArgs)
}
}