繁体   English   中英

在Gradle编译一个JDK 8项目+一个JDK 9“module-info.java”

[英]Compile a JDK 8 project + a JDK 9 "module-info.java" in Gradle

我正在开发一个以 JDK 8 为目标的 Java 库,我正在使用 OpenJDK 11 在 Gradle 5 中构建它。为了以 JDK 8 为目标,我使用了 javac 的--release选项。

但是,我也希望我的库与 JPMS 兼容。 换句话说:

  • 我想提供一个用--release 9编译的module-info.classStephen Colebourne 规模中的选项 3),
  • 而所有 rest 都是用--release 8编译的。

MCVE

build.gradle :

plugins {
    id 'java'
    id 'org.javamodularity.moduleplugin' version '1.4.1' // *
}

repositories {
    mavenCentral()
}

dependencies {
    compileOnly 'org.projectlombok:lombok:1.18.6'
}

compileJava.options.compilerArgs.addAll(['--release', '9']) // **

*org.javamodularity.moduleplugincompileJava设置--module-path

** --release还没有 Gradle DSL: #2510

src/main/java/module-info.java

module pl.tlinkowski.sample {
  requires lombok;
  exports pl.tlinkowski.sample;
}

src/main/java/pl/tlinkowski/sample/Sample.java

package pl.tlinkowski.sample;

@lombok.Value
public class Sample {
  int sample;
}

此 MCVE 编译,但所有类(而不是仅module-info.class )都是 JDK 9 class 格式( v.53 )。

其他构建工具

我想做的事肯定有可能:

  1. Maven
    • 例如ThreeTen-Extra (他们的方法归结为:首先使用--release 9编译所有内容,然后使用--release 8编译除module-info.java之外的所有内容)。
  2. Ant
    • 例如Lombok (他们的方法归结为:将module-info.java放在单独的“源代码集”中 - 主要源代码集使用--release 8编译,“模块信息”源代码集使用--release 9编译)。

我试过的

我喜欢Lombok的做法,所以我操作build.gradle中的源集如下:

sourceSets {
    main { // all but module-info
        java {
            exclude 'module-info.java'
        }
    }
    mainModuleInfo { // module-info only
        java {
            srcDirs = ['src/main/java']
            outputDir = file("$buildDir/classes/java/main")
            include 'module-info.java'
        }
    }
}

然后,我配置了一个任务依赖项并为两个编译任务添加了正确的--release选项:

classes.dependsOn mainModuleInfoClasses

compileJava.options.compilerArgs.addAll(['--release', '8'])
compileMainModuleInfoJava.options.compilerArgs.addAll(['--release', '9'])

如果我现在编译,我会得到:

错误:package 龙目岛不存在

所以我仍然不知道如何指示org.javamodularity.moduleplugin来:

  • 不要对main使用--module-path
  • mainModuleInfo设置正确的--module-path

编辑:1.5.0版开始, Gradle Modules Plugin现在支持此功能。

这是一个有效的build.gradle片段:

plugins {
    id 'java'
    id 'org.javamodularity.moduleplugin' version '1.5.0'
}

repositories {
    mavenCentral()
}

dependencies {
    compileOnly 'org.projectlombok:lombok:1.18.6'
}

modularity.mixedJavaRelease 8

好的,我设法通过以下方式使其工作:

  1. 禁用org.javamodularity.moduleplugin
  2. 删除自定义源集(没有必要)
  3. 添加自定义compileModuleInfoJava任务并将其--module-path设置为compileJava任务的类路径(受此Gradle 手册启发)

这是build.gradle的完整源代码:

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    compileOnly 'org.projectlombok:lombok:1.18.6'
}

compileJava {
    exclude 'module-info.java'

    options.compilerArgs = ['--release', '8']
}

task compileModuleInfoJava(type: JavaCompile) {
    classpath = files() // empty
    source = 'src/main/java/module-info.java'
    destinationDir = compileJava.destinationDir // same dir to see classes compiled by compileJava

    doFirst {
        options.compilerArgs = [
                '--release', '9',
                '--module-path', compileJava.classpath.asPath,
        ]
    }
}

compileModuleInfoJava.dependsOn compileJava
classes.dependsOn compileModuleInfoJava

笔记:

  • 它编译👍
  • 我验证了module-info.class是 JDK 9 格式(第 8 个字节是0x35v.53 ),而其他类是 JDK 8 格式(第 8 个字节是0x34v.52 )👍
  • 然而,禁用org.javamodularity.moduleplugin并不令人满意,因为这意味着测试将不再在模块路径上运行,等等。👎

我为此开发了一个 Gradle 插件: https://github.com/Glavo/module-info-compiler

试过Gradle Modules Plugin,但是还是有些麻烦的问题,所以开发了这个插件,专门用来编译module-info.java的编译器。

它不是通过调用javac实现的。 是一个可以运行在Java上面的完整编译器 8.识别module-info.java的语法,并根据它生成对应的module-info.class文件。

它只检查语法,并不实际检查那些包、类或模块,因此它可以在不配置任何模块路径的情况下工作。

这个 Gradle 插件已经为你处理好了一切。 对于包含module-info.java的 Java 8 项目,你只需要这样做:

plugins {
    id("java")
    id("org.glavo.compile-module-info-plugin") version "2.0"
}

tasks.compileJava {
    options.release.set(8)
}

暂无
暂无

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

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