shammancer
shammancer

Reputation: 397

Splitting all output directories in Gradle

Gradle 4.0 came out yesterday and I updated my project for it.

Now I am getting the following warning:

Gradle now uses separate output directories for each JVM language, but this build assumes a single directory for all classes from a source set. This behaviour has been deprecated and is scheduled to be removed in Gradle 5.0

I would like to use separate output directories for each language. What do I need to change to make that happen?


Things I tried:


Related GitHub issue


Gradle Plugins:

Upvotes: 32

Views: 12820

Answers (4)

Tono Wiedermann
Tono Wiedermann

Reputation: 608

My case was a bit specific because output classes directories were used to construct classpath entry for command-line execution. But perhaps this will help someone.

I decided to concatenate all output directories. The change I made was form

sourceSets.integrationTest.output.classesDir

to

ext {
    classpathSeparator = System.properties['os.name'].toLowerCase().contains('windows')?";":":"
}
...
sourceSets.integrationTest.output.classesDirs.join(classpathSeparator)

Upvotes: 0

gavenkoa
gavenkoa

Reputation: 48753

Gradle 4.0 introduces multiple sourceSets per JVM language in order to enable remote build caching. With the java plugin your build/classes/main should become build/classes/java/main and build/classes/test should become build/classes/java/test, etc.

The warning you're seeing is defined in DefaultSourceSets.java

Therefore, if any plugin within your project or your build.gradle calls DefaultSourceSetOutput.getClassesDir() (or access classesDir) you get this warning.

Solution 1

Use

sourceSets.main.output.classesDir = new File(buildDir, "classes/main")

which corresponds to:

@Override
public boolean isLegacyLayout() {
    return classesDir!=null;
}

@Override
public void setClassesDir(File classesDir) {
    setClassesDir((Object)classesDir);
}

@Override
public void setClassesDir(Object classesDir) {
    this.classesDir = classesDir;
    this.classesDirs.setFrom(classesDir);
}

Note that SourceSetOutput.java marks getClassesDir() as deprecated.

So until all plugins in your project get support for Gradle 4.0 you should stick to the workaround and ignore the deprecation warnings.

Another issue is test files. If you don't want to have the new layout (build/classes/main and build/classes/java/test) you should adjust test path too:

sourceSets.main.output.classesDir = new File(buildDir, "classes/main")
sourceSets.test.output.classesDir = new File(buildDir, "classes/test")

UPDATE Users of IDEA may notice that IDE starts using separate out directories for build if Gradle 4.x is detected. That makes impossible hot app reloading if you run app outside of IDEA. To fix that add and reimport:

subprojects {
    apply plugin: 'idea'
    // Due to Gradle 4.x changes (separate output directories per JVM language)
    // Idea developers refuse to reuse Gradle classpath and use own 'out/' directory.
    // Revert to old behavior to allow Spring Devtool to work with using fast Idea compiler.
    // https://youtrack.jetbrains.com/issue/IDEA-175172
    // Alternatively use native Gradle builds or bootRun.addResources = true
    // To use this feature push Ctrl+Shift+F9 to recompile!
    // Be aware that Idea put resources into classes/ directory!!
    idea.module.inheritOutputDirs = false
    idea.module.outputDir = sourceSets.main.output.classesDir
    idea.module.testOutputDir = sourceSets.test.output.classesDir
}

Please note that IDEA puts resources into the same directory as .class files so your Gradle classpath could be corrupted. Just do gradle clean for modules on which you use IDEA built-in build commands (Ctrl+Shift+F10, etc).

Upvotes: 15

Dordoka Maisu
Dordoka Maisu

Reputation: 101

This is due to the change introduced in Gradle 4.0: it now uses separate output directories if there are multiple language sources.

To return to the old behaviour and get rid of the warning, insert this into your build.gradle:

// Change the output directory for the main source set back to the old path sourceSets.main.output.classesDir = new File(buildDir, "classes/main")

Reference: https://docs.gradle.org/4.0/release-notes.html#multiple-class-directories-for-a-single-source-set

Upvotes: 5

Andrii Abramov
Andrii Abramov

Reputation: 10751

For example, if you mix Java, Kotlin and Groovy project structure should be like the following:

root/
    src/
       main/
            java/
            kotlin/
            groovy/
       test/
            java/
            kotlin/
            groovy/

In you build.gradle you have to specify plugins that are required for specific language.

apply plugin: 'java'
apply plugin: 'groovy'
apply plugin: 'kotlin'

Upvotes: -1

Related Questions