Kotlin 1.2.10和Java 9对自动模块有相反的规则吗?

时间:2017-12-24 06:49:58

标签: java gradle kotlin jigsaw java-module

我有一个使用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.ktBar.kt,...)。

如果我这样写module-info.java,那么一切都很有效:

module my.module {
    requires kotlin.stdlib;
    exports my.module.pkg;
}

如果我使用this techniquejavac任务期间将所有编译时依赖项提供给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模块?

2 个答案:

答案 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)
    }
}