简体   繁体   English

用 Gradle 构建一个 Kotlin + Java 9 项目

[英]Building a Kotlin + Java 9 project with Gradle

I'm fairly new to Gradle (and Java 9, to be honest), and I'm trying to use Gradle to build a simple library project that is a mix of Java 9 and Kotlin. More in detail, there is an interface in Java and an implementation in Kotlin;我对 Gradle(和 Java 9,老实说)还很陌生,我正在尝试使用 Gradle 构建一个简单的库项目,该项目混合了 Java 9 和 Kotlin。更详细地说,有一个接口Java 和 Kotlin 中的实现; I'd do everything in Kotlin, but the modules-info.java is java anyway, so I decided to do things this way.我会在 Kotlin 中做所有事情,但是modules-info.java无论如何都是 java,所以我决定这样做。

I'm building on IntelliJ Idea, with the 1.2.0 kotlin plugin and gradle 4.3.1 defined externally.我在 IntelliJ Idea 上构建,使用外部定义的 1.2.0 kotlin 插件和 gradle 4.3.1。

Filesystem schema is:文件系统架构是:

+ src
  + main
    + java
      + some.package
        - Roundabout.java [an interface]
      - module-info.java
    + kotlin
      + some.package.impl
        - RoundaboutImpl.kt [implementing the interface]

module-info.java is: module-info.java是:

module some.package {
  requires kotlin.stdlib;
  exports some.package;
}

and build.gradle is: build.gradle是:

buildscript {
    ext.kotlin_version = '1.2.0'

    repositories {
        mavenCentral()
    }
    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

group 'some.package'
version '1.0-PRE_ALPHA'

apply plugin: 'java-library'
apply plugin: 'kotlin'

tasks.withType(JavaCompile) {
    options.encoding = 'UTF-8'
}

sourceCompatibility = 9

compileJava {
    dependsOn(':compileKotlin')
    doFirst {
        options.compilerArgs = [
                '--module-path', classpath.asPath,
        ]
        classpath = files()
    }
}

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.jetbrains.kotlin', name: 'kotlin-stdlib', version: "$kotlin_version"
    testCompile group: 'junit', name: 'junit', version: '4.12'
}

compileKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

compileTestKotlin {
    kotlinOptions.jvmTarget = "1.8"
}

Notice that I had to specify a module path on the java compile task, or the compilation fails with:请注意,我必须在 java 编译任务上指定模块路径,否则编译会失败:

error: module not found: kotlin.stdlib requires kotlin.stdlib;错误:找不到模块:kotlin.stdlib 需要 kotlin.stdlib;

Anyway, now this build fails with this error, and I can't figure out how to solve it:无论如何,现在这个构建失败并出现这个错误,我不知道如何解决它:

error: package some.package.impl does not exist错误:package some.package.impl 不存在

import some.package.impl.RoundaboutImpl;导入 some.package.impl.RoundaboutImpl;

error: cannot find symbol错误:找不到符号

return new RoundaboutImpl<>(queueSize, parallelism, worker, threadPool); return new RoundaboutImpl<>(queueSize, parallelism, worker, threadPool);

I think that the Kotlin part of the compilation is going ok, then the java part fails because it doesn't "see" the kotlin side, so to speak.认为编译的 Kotlin 部分正常,然后 java 部分失败,因为它没有“看到”kotlin 的一面,可以这么说。

I think I should tell it somehow to to load the already compiled kotlin classes in the classpath;我想我应该以某种方式告诉它在类路径中加载已经编译的 kotlin 类; but (first) how do I do this in gradle?但是(首先)我如何在 gradle 中执行此操作? and (second) is it even possible ?和(第二)甚至可能吗? I think you can't mix module path and class path in Java 9.我认为你不能在 Java 9 中混合模块路径和 class 路径。

How can I solve this?我该如何解决这个问题? I think it is a pretty common situation, as every java9-style module will be a mixed-language module (because of module-info.java ), so I think I'm missing something really basic here.我认为这是一种很常见的情况,因为每个 java9 风格的模块都是混合语言模块(因为module-info.java ),所以我想我在这里遗漏了一些非常基本的东西。

Thanks in advance!提前致谢!

Solved! 解决了! It was sufficient to set the kotlin compilation dir to the same dir as Java: 将kotlin编译目录设置为与Java相同的目录就足够了:

compileKotlin.destinationDir = compileJava.destinationDir

It works now, both with the sources in the same tree or in different trees; 现在它可以使用同一棵树或不同树木中的来源; but with a quirk: the jar task produces a jar with all the entries duplicated. 但有一个怪癖: jar任务产生一个包含所有条目重复的jar。 I'll work on fix this, next. 接下来,我会努力解决这个问题。

Thanks to everyone! 谢谢大家!

I am using the following gradle script where I put the module-info.java under src/module. 我使用以下gradle脚本,我将module-info.java放在src / module下。 It gets automatically included in the jar (without duplicates): 它自动包含在jar中(没有重复):

if (JavaVersion.current() >= JavaVersion.VERSION_1_9) {
    subprojects {
        def srcModule = "src/module"
        def moduleInfo = file("${project.projectDir}/$srcModule/module-info.java")
        if (moduleInfo.exists()) {

            sourceSets {
                module {
                    java {
                        srcDirs = [srcModule]
                        compileClasspath = main.compileClasspath
                        sourceCompatibility = '9'
                        targetCompatibility = '9'
                    }
                }
                main {
                    kotlin { srcDirs += [srcModule] }
                }
            }

            compileModuleJava.configure {
                dependsOn compileKotlin
                destinationDir = compileKotlin.destinationDir
                doFirst {
                    options.compilerArgs = ['--module-path', classpath.asPath,]
                    classpath = files()
                }
            }
            jar.dependsOn compileModuleJava
        }
    }
}

I won't update it any longer, have a look at https://github.com/robstoll/atrium/blob/master/build.gradle to see the current version in use. 我不会再更新它,看一下https://github.com/robstoll/atrium/blob/master/build.gradle来查看当前使用的版本。

The accepted answer did not work for me (atleast not the way it was presented), but this is what worked:接受的答案对我不起作用(至少不是它的呈现方式),但这是有效的:

plugins {
    id "org.jetbrains.kotlin.jvm" version "1.3.50"
}

compileKotlin {
    doFirst {
        destinationDir = compileJava.destinationDir
    }
}

jar {
    duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}

Doing it the way the accepted answer suggests led to me getting this error:按照接受的答案建议的方式进行操作导致我收到此错误:

Directory '/path/to/project/build/classes/kotlin/main' specified for property 'compileKotlinOutputClasses' does not exist.为属性“compileKotlinOutputClasses”指定的目录“/path/to/project/build/classes/kotlin/main”不存在。


Gradle version : 5.6摇篮版本:5.6

I ran into the same problem and the existing answers fixed only part of the issue for me, so I searched over all internet and ended up with a working solution.我遇到了同样的问题,现有的答案只为我解决了部分问题,所以我搜索了所有互联网并最终找到了一个可行的解决方案。 I don't know exactly why this works, but I decided to share my build.gradle.kts file here to help other people to find they way.我不知道为什么会这样,但我决定在这里分享我的build.gradle.kts文件来帮助其他人找到他们的方式。 This file is a combination of many pieces that I found on the internet.这个文件是我在互联网上找到的许多片段的组合。

I'm using Java 16, Kotlin 1.5.31 and Gradle 7.1.我使用的是 Java 16、Kotlin 1.5.31 和 Gradle 7.1。

The file tree is:文件树是:

+ project
  - build.gradle.kts
  + src
    + main
      + java
        - module-info.java
        + my
          + package
            - SomeClasses.java
      + kotlin
        + my
          + package
            - MoreClasses.kt

module-info.java模块信息.java

module name.of.your.javamodule {
    requires kotlin.stdlib;
    requires kotlinx.coroutines.core.jvm;
    requires org.jetbrains.annotations;

    exports my.pacakge;
}

build.gradle.kts build.gradle.kts

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    application
    kotlin("jvm") version "1.5.31"
    id("org.jetbrains.kotlin.plugin.serialization") version "1.5.31"
}
val kotlinVersion = "1.5.31"

group = "your.group.id"
version = "0.0.1-SNAPSHOT"
application {
    mainClass.set("full.name.of.your.MainClass")
    mainModule.set("name.of.your.javamodule") // Same defined in module-info.java
    executableDir = "run"
}

repositories {
    mavenCentral()
}

dependencies {
    implementation(kotlin("stdlib-jdk8", kotlinVersion))
    implementation("com.michael-bull.kotlin-inline-logger:kotlin-inline-logger:1.0.3")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.2-native-mt")
    implementation("org.jetbrains:annotations:22.0.0")
    testImplementation(kotlin("test", kotlinVersion))
}

java {
    sourceCompatibility = JavaVersion.VERSION_16
    targetCompatibility = JavaVersion.VERSION_16
}

tasks {
    run.configure {
        dependsOn(jar)
        doFirst {
            jvmArgs = listOf(
                "--module-path", classpath.asPath
            )
            classpath = files()
        }
    }

    compileJava {
        dependsOn(compileKotlin)
        doFirst {
            options.compilerArgs = listOf(
                "--module-path", classpath.asPath
            )
        }
    }

    compileKotlin {
        destinationDirectory.set(compileJava.get().destinationDirectory)
    }

    jar {
        duplicatesStrategy = DuplicatesStrategy.EXCLUDE
    }
}

tasks.withType<KotlinCompile>().configureEach {
    kotlinOptions {
        jvmTarget = "16"
    }
}

On gradle 7.4 with kotlin DSL, I need to:在 gradle 7.4 和 kotlin DSL 上,我需要:

  • move the module-info.java to src/main/java将 module-info.java 移动到 src/main/java
  • create any java file inside each package to export under src/main/java, at least empty package-info.java在每个 package 中创建任何 java 文件以在 src/main/java 下导出,至少为空 package-info.java

In build.gradle.kts:在 build.gradle.kts 中:

val compileKotlin: KotlinCompile by tasks
val compileJava: JavaCompile by tasks
compileKotlin.destinationDirectory.set(compileJava.destinationDirectory)

Also discussed here: https://github.com/gradle/gradle/issues/17271也在这里讨论: https://github.com/gradle/gradle/issues/17271

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM