Gradle build - add module path

一笑奈何 提交于 2021-01-18 19:49:25

问题


My question: How do I set a module path for gradle build?

I've become comfortable working with Java modules from the command line. I do a frequent exercise in Powershell which results in these source files.

└───src
    ├───appMod
    │   │   module-info.java
    │   │
    │   └───appPack
    │           Entry.java
    │
    └───greetMod
        │   module-info.java
        │
        └───greetPack
                Hello.java

appMod/module-info

module appMod {
    requires greetMod;
}

appMod/appPack.Entry

package appPack;

import greetPack.Hello;

public class Entry {
    public static void main(String[] args) {
        System.out.println(new Hello().sayHello());
    }
}

greetMod/module-info

module greetMod {
    exports greetPack;
}

greetMod/greetPack.Hello

package greetPack;

public class Hello {
    public String sayHello() {
        return "Greetings from Hello class!";
    }
}

Since the appMod module requires greetMod, I compile and jar greetMod first.

javac -d out/greetMod src/greetMod/module-info.java src/greetMod/greetPack/Hello.java;
jar cf lib/greetJar.jar -C out/greetMod .;

Then I compile and jar appMod, but as I do so I specify the module path (-p) where the new greetMod jar (greetJar) can be found (in lib).

javac -d out/appMod -p lib src/appMod/module-info.java src/appMod/appPack/Entry.java;
jar cfe lib/appJar.jar appPack.Entry -C out/appMod .;

I can then run this or jlink it in part by adding a module path.

java -p lib -m appMod;
jlink -p lib --add-modules appMod --launcher launch=appMod --output dist;
dist/bin/launch

I now want to do this same exercise in Gradle, but I can't figure out how to do the equivalent of setting a module path such as -p lib. I've seen code for sourceSets, and countless variations of dependencies, but so far I haven't been able to put together something that works. I've also read conflicting statements that both say that Gradle doesn't fully support Java modules, and that Gradle does support them.


回答1:


I know it can be confusing, but it can definitely be done by gradle. You will need to use a multiproject build to have this work. In your top-most build.gradle, do this:

subprojects {
    apply plugin: 'java'

    sourceCompatibility = 1.9

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

In your settings.gradle:

rootProject.name = 'module-testing'

include 'src:greetMod'
include 'src:appMod'

Everything inside appMod should be moved into a folder called appModSrc. Do the same for greetMod so use greetModSrc.


greetMod

Directory structure:

├── build.gradle
└── greetModSrc
    ├── greetPack
    │   └── Hello.java
    └── module-info.java

build.gradle

sourceSets {
    main {
        java {
            srcDirs 'greetModSrc'
        }
    }
}

appMod

Directory structure:

├── appModSrc
│   ├── appPack
│   │   └── Entry.java
│   └── module-info.java
└── build.gradle

build.gradle

plugins {
    id 'application'
}

sourceSets {
    main {
        java {
            srcDirs 'appModSrc'
        }
    }
}

application {
    mainClassName 'appPack.Entry'
}

jar {
    doFirst {
        manifest {
            attributes('ModuleMainClass': mainClassName)
        }
    }
}

dependencies {
    implementation project(':src:greetMod')
}

With this setup, you can simply run ./gradlew :src:appMod:run:

> Task :src:appMod:run
Greetings from Hello class!

You can download the idea project here: https://github.com/smac89/multi-java9-gradle




回答2:


Since Gradle 6.4 you can used set the inferModulePath property on the project Java plugin to automatically set the module path:

subprojects {
    plugins.withType(JavaPlugin).configureEach {
        java {
            modularity.inferModulePath = true
            sourceCompatibility = JavaVersion.VERSION_11
            targetCompatibility = JavaVersion.VERSION_11
        }
    }
}



回答3:


First please note: I am on Gradle 6.6.1 with Java 15.

This is what I have observed:

  1. in order to make the compile work, every project needs:

    java {
        modularity.inferModulePath = true
    }
    
  2. this can be turned on at root build.gradle via

     subprojects {
         apply plugin: "java"
         java {
             modularity.inferModulePath = true
         }
     }
    
  3. in order to use modulepath with gradle run (ServiceLoader working WITHOUT META-INF, reflection restrictions ...) you have to use following application section:

    application {
         mainModule = 'org.gradle.sample.app' // name defined in module-info.java
         mainClass = 'org.gradle.sample.Main'
         // DO NOT USE   mainClassName = 'org.gradle.sample.Main'
    }
    

Took me quite some time to put all together from several Gradle pages --- but it is all here.

Note:

This will not but non-modular jars to the module-path.



来源:https://stackoverflow.com/questions/58708213/gradle-build-add-module-path

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!