How do I define a compile-time *only* classpath in Gradle?

CompilationClasspathGradle

Compilation Problem Overview


Can someone please give me a simple build.gradle example of how I can specify compile-time-only classes that are not included in the runtime deployment (war).

Gradle seems to have gotten this the wrong way around since 'runtime' inherits from 'compile'. I can't imagine a situation where I would want classes at runtime that I wouldn't want at compile time. However, there are many circumstances where I need classes to generate code at compile time that I do not wish to deploy at runtime!

I've ploughed through the bloated gradle documentation but cannot find any clear instructions or examples. I suspect this might be achieved by defining a 'configuration' and setting it as the classpath of the CompileJava plugin - but the documentation falls short on explaining how to achieve this.

Compilation Solutions


Solution 1 - Compilation

There has been a lot of discussion regarding this topic, mainly here, but not clear conclusion.

You are on the right track: currently the best solution is to declare your own provided configuration, that will included compile-only dependencies and add to to your compile classpath:

configurations{
  provided
}

dependencies{
  //Add libraries like lombok, findbugs etc
  provided '...'
}

//Include provided for compilation
sourceSets.main.compileClasspath += [configurations.provided]

// optional: if using 'idea' plugin
idea {
  module{
    scopes.PROVIDED.plus += [configurations.provided]
  }
}

// optional: if using 'eclipse' plugin
eclipse {
  classpath {
    plusConfigurations += [configurations.provided]
  }
}

Typically this works well.

Solution 2 - Compilation

If you use the war plugin, providedCompile should do the trick. However if you need to exclude dependencies from being included in a jar, you'll have to extend the jar task. Below is an example for building a "fat jar" or "uber jar" (a single jar that includes all classes of its dependencies) excluding depndencies marked provided:

configurations {
    provided
    compile.extendsFrom provided
}
 
dependencies {
    provided "group.artifact:version"
    compile "group.artifact:version"
}
 
jar {
    dependsOn configurations.runtime
    from {
        (configurations.runtime - configurations.provided).collect {
            it.isDirectory() ? it : zipTree(it)
        }
    } 
}

Credit: http://kennethjorgensen.com/blog/2014/fat-jars-with-excluded-dependencies-in-gradle/

Update:

As of Gradle 2.12 the issue of defining compile only dependencies is finally solved in a simple and natural manner by the new "copmpileOnly" configuration:

dependencies {
    compileOnly 'javax.servlet:servlet-api:2.5'
}

Solution 3 - Compilation

I figured it out for my project setup. I use Android Studio running with the gradle plugin 0.9.+ with gradle 1.11 The main project uses amazon ads and amazon inapp purchases. It depends on a library project using amazon device messaging(ADM).

My main issue was with the the ADM where I got the "RuntimeException: Stub!" error.

1.) Library Project: The "provided configuration" proposed by Lukas does not work, as stated by him, so I used Richards approach, which however did not work as well out of the box. I had to change it a little since I could not find the lib in the ext_libs folder of the aar file. Gradle seems to pack all libraries in the libs folder in the in the final aar-file.

android.libraryVariants.all { variant ->
variant.packageLibrary.exclude( 'libs/amazon-device-messaging-1.0.1.jar' )
}

2.) Application Project : Here, the approach with the "provided configuration" worked.

configurations{
    provided
} 
dependencies {
    compile 'fr.avianey:facebook-android-api:+@aar'
    compile files('ext_libs/amazon-ads-5.3.22.jar')
    compile files('ext_libs/in-app-purchasing-1.0.3.jar' )
    provided files('ext_libs/amazon-device-messaging-1.0.1.jar')
}

android.applicationVariants.all {
    variant -> variant.javaCompile.classpath += configurations.provided
}

Solution 4 - Compilation

It's quite common to have runtime dependencies that aren't compile time dependencies. The other way around is a fairly special case and as such requires a few lines of configuration in Gradle. I suggest to search the Gradle forum for provided.

It sounds like what you are really after is declaring dependencies for your build, not for the compile class path. How this is done depends on how the desired functionality gets invoked (Ant task, Gradle task/plugin, ad-hoc use from build script). If you provide more detailed information on what you are trying to do, I can provide a more specific answer.

Here are some links to relevant information in the Gradle user guide:

Solution 5 - Compilation

If you use the WAR plugin, you can use providedCompile as in this example

dependencies {
    compile module(":compile:1.0") {
        dependency ":compile-transitive-1.0@jar"
        dependency ":providedCompile-transitive:1.0@jar"
    }
    providedCompile "javax.servlet:servlet-api:2.5"
    providedCompile module(":providedCompile:1.0") {
        dependency ":providedCompile-transitive:1.0@jar"
    }
    runtime ":runtime:1.0"
    providedRuntime ":providedRuntime:1.0@jar"
    testCompile "junit:junit:4.11"
    moreLibs ":otherLib:1.0"
}

Solution 6 - Compilation

In Gradle 2.12 a compileOnly configuration has been introduced. A blog post introducing this features can be found here:

Gradle latest feature: Compile only dependencies

Please be aware of one important side effect:

> As a result of the addition of the “compileOnly” configuration, the “compile” configuration no longer represents a complete picture of all compile time dependencies. When needing reference a compile classpath in build scripts or custom plugins, the appropriate source set’s compileClasspath property should be used instead.

Solution 7 - Compilation

It turns out that they have added a "provided" configuration in the gradle android plugin 0.8.0 but it doesn't quite work. It does add the provided libraries to the compile path automatically, but it also includes them in the final aar/apk.

What worked for me was the solution provided by @lukas-hanaceck but by changing the name from "provided" to any other custom name. In my case this is a library project which is a dependency for my final android application project. Heres a gist of what worked for me.

configurations {
   providedlibs
}

dependencies {
   providedlibs files('provided/library.jar')
}

libraryVariants.all {
    variant -> variant.javaCompile.classpath += configurations.providedlibs
}

It compiles perfectly and the provided/library.jar is not included in the final apk. The only issue I am having is notifying Android studio of the existence of library.jar. The idea plugin doesn't seem to work for Android studio. Im guessing that they have another custom plugin for syncing gradle with studio.

Solution 8 - Compilation

I didnt find a solution for Android Studio, but this what I tried:

In android studio I had to update to version 0.5.+

in gradle/gradle-wrapper.properties replace

distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-rc-3-bin.zip

by

distributionUrl=http\://services.gradle.org/distributions/gradle-1.11-all.zip

in all my build.gradle replace

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.7.+'
    }
}

by

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:0.9.+'
    }
}

and in the library I wanted to use provided

configurations {
    provided
}

//put applicationVariants in case it is apply plugin: 'android' and not apply plugin: 'android-library'
android.libraryVariants.all {
    variant -> variant.javaCompile.classpath += configurations.provided
}

dependencies {
    provided files('ext_libs/amazon-device-messaging-1.0.1.jar')
}

and at the end it doesnt work, it seems that it works for jar but not for aar or apk as stated here https://groups.google.com/forum/#!topic/adt-dev/WIjtHjgoGwA

Solution 9 - Compilation

In Android Studio 1.0 do this:

android.libraryVariants.all { variant ->
    variant.outputs.each { output ->
        output.packageLibrary.exclude('libs/someLib.jar')
    }
}

Solution 10 - Compilation

We don't need "provided", try to add this:

android.libraryVariants.all { variant ->
    variant.packageLibrary.exclude( 'ext_libs/amazon-device-messaging-1.0.1.jar' )
}

Enjoy!

Solution 11 - Compilation

The OP apparently didn't look for an Android answer, but some answers are specific to Android. So I suggest you look at this page : http://tools.android.com/tech-docs/new-build-system

Version 0.9.0 introduced a provided scope. So, just use

dependencies {
    provided "groupId:artifcatId:version"
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlex WordenView Question on Stackoverflow
Solution 1 - CompilationrodionView Answer on Stackoverflow
Solution 2 - CompilationDoron GoldView Answer on Stackoverflow
Solution 3 - CompilationMike TView Answer on Stackoverflow
Solution 4 - CompilationPeter NiederwieserView Answer on Stackoverflow
Solution 5 - CompilationAdrian H.View Answer on Stackoverflow
Solution 6 - CompilationxsvedaView Answer on Stackoverflow
Solution 7 - CompilationaarkayView Answer on Stackoverflow
Solution 8 - CompilationLukas HanacekView Answer on Stackoverflow
Solution 9 - CompilationThomas HofmannView Answer on Stackoverflow
Solution 10 - CompilationRichard LiView Answer on Stackoverflow
Solution 11 - CompilationSnicolasView Answer on Stackoverflow