Gradle compileKotlin includeRuntime not adding runtime to jar - gradle

I have a Kotlin Gradle project, and I would like to include Kotlin's runtime and stdlib in the jar file. I'm currently using this, but it's not including the runtime or stdlib when I build the project using the build.gradle configuration.
compileKotlin {
kotlinOptions {
includeRuntime = true
noStdlib = false
}
}
This is the Gradle code I'm using to include the runtime/stdlib in the jar, but it isn't working like I expect it to. Here's the full build.gradle file for some context:
https://github.com/BenWoodworth/CrossPlatformGreeter/blob/bd1da79f36e70e3d88ed871bc35502ecc3a852fb/build.gradle#L35-L43
Kotlin's Gradle documentation seems to indicate that setting kotlinOptions.includeRuntime to true should include the Kotlin runtime in the resulting .jar.
https://kotlinlang.org/docs/reference/using-gradle.html#attributes-specific-for-kotlin
Edit:
This might be related. When I run compileKotlin, I'm getting a couple of warnings related to the runtime:
:compileKotlin
w: Classpath entry points to a non-existent location: <no_path>\lib\kotlin-runtime.jar
BUILD SUCCESSFUL

Here's an alternative I came up with. It'll add the Kotlin runtime and stdlib to the jar using the jar task.
jar {
from {
String[] include = [
"kotlin-runtime-${version_kotlin}.jar",
"kotlin-stdlib-${version_kotlin}.jar"
]
configurations.compile
.findAll { include.contains(it.name) }
.collect { it.isDirectory() ? it : zipTree(it) }
}
}

Gradle Kotlin DSL:
tasks.withType<Jar> {
val include = setOf("kotlin-stdlib-1.4.0.jar")
configurations.runtimeClasspath.get()
.filter { it.name in include }
.map { zipTree(it) }
.also { from(it) }
}

Try this:
Build script
Unpack jar
Add kotlin runtime and rapack it
type gradle packJar to create jar with kotlin runtime in it
or
type gradle runJar to create and run the jar file
build Script

Related

Fat Jar expands dependencies with Gradle Kotlin DSL

I am trying to build a fat jar using the following in my Kotlin based gradle file.
val fatJar = task("fatJar", type = Jar::class) {
baseName = "safescape-lib-${project.name}"
// manifest Main-Class attribute is optional.
// (Used only to provide default main class for executable jar)
from(configurations.runtimeClasspath.map({ if (it.isDirectory) it else zipTree(it) }))
with(tasks["jar"] as CopySpec)
}
tasks {
"build" {
dependsOn(fatJar)
}
}
However, the fat jar has all the dependencies expanded out. I would like to have the jars included as is in a /lib directory but I cannot work out how to achieve this.
Can anyone give any pointers as to how I can achieve this?
Thanks
Well you are using zipTree in that map part of the spec, and it behaves according to the documentation: it unzips the files that are not a directory.
If you want the jars in /lib, replace your from with:
from(configurations.runtimeClasspath) {
into("lib")
}
In case anyone is using kotlin-multiplatform plugin, the configuration is a bit different. Here's a fatJar task configuration assuming JVM application with embedded JS frontend from JS module:
afterEvaluate {
tasks {
create("jar", Jar::class).apply {
dependsOn("jvmMainClasses", "jsJar")
group = "jar"
manifest {
attributes(
mapOf(
"Implementation-Title" to rootProject.name,
"Implementation-Version" to rootProject.version,
"Timestamp" to System.currentTimeMillis(),
"Main-Class" to mainClassName
)
)
}
val dependencies = configurations["jvmRuntimeClasspath"].filter { it.name.endsWith(".jar") } +
project.tasks["jvmJar"].outputs.files +
project.tasks["jsJar"].outputs.files
dependencies.forEach { from(zipTree(it)) }
into("/lib")
}
}
}

Kotlin always tells me KotlinReflectionNotSupportedError

I've just started converting to Kotlin from Java. I have a question: when I'm reflecting something like:
XXClass::class.java
or anything else. They don't work in JAR, but work fine from IDE.
I'm using gradle :module:build or gradle :module:jar to generate the JAR file. After generating, it always tells me KotlinReflectionNotSupportedError: Kotlin reflection implementation is not found at runtime. Make sure you have kotlin-reflect.jar in the classpath. But I've already added them into dependencies, and they work fine in IDE.
These are parts of my gradle files (Please notice that this is a kotlin application module, not an Android module):
// (Module level)
apply plugin: 'kotlin'
sourceCompatibility = 1.8
dependencies {
// Others...
// I've already added reflect and stdlib
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
jar {
manifest {
// ...
}
// To include dependencies to build a fat jar
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
}
// Include reflect and stdlib
compileKotlin {
kotlinOptions {
jvmTarget = "1.8"
javaParameters = true
noReflect = false
noStdlib = false
}
}
// (Project level)
buildscript {
ext.kotlin_version = '1.3.11'
repositories {
// ...
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Could anyone give me a hand? Thanks a lot.
The issue is in this block of script
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
You've included the dependencies ( kotlin-reflect ) using implementation configuration, but collecting the dependencies from compile configuration. If you changed your config from implementation to compile, this block will work. Since compile is deprecated, you can try something like this to collect your dependencies to your jar
compileJava.classpath.collect {
it.isDirectory() ? it : zipTree(it)
}
see this answer

Using testCompile output from other subproject (Gradle Kotlin DSL)

I have some utility files in the test sources in one of my gradle subproject and would like to use them in an other subproject.
My "source" subproject is called core, while the one uses it is called tem.
I try to migrate and integrate the following example:
In your Server project:
configurations {
testArtifacts.extendsFrom testCompile
}
task testJar(type: Jar) {
classifier "test"
from sourceSets.test.output
}
artifacts {
testArtifacts testJar
}
In your ServerWeb project:
testCompile project(path: ":Server", configuration: 'testArtifacts')
As far as I get is making the conversation. I added the following to my core.gradle.kts:
val testConfig = configurations.create("testArtifacts") {
extendsFrom(configurations["testCompile"])
}
tasks.register("testJar", Jar::class.java) {
classifier += "test"
from(sourceSets["test"].output)
}
artifacts {
add("testArtifacts", tasks.named<Jar>("testJar") )
}
And tried to refer to it in tem.gradle.kts:
testImplementation(project(":core", "testArtifacts"))
It compiles, but I still can't access the classes from core.
Where did I miss something?
Most of your code should be OK
But you must define classesDirs for jar
tasks.register<Jar>("testJar") {
dependsOn("testClasses")
archiveBaseName.set("${project.name}-test")
from(sourceSets["test"].output.classesDirs)
}
I also added depends on testClasses to be sure that classes are compiled.
You can test that jar is OK by executing testJar task. Then verify that generated jar contains your classes. If you make mistake with from method call then you get empty jar.
The following configuration worked for me to include both the test classes and test resources:
core build.gradle.kts
val testConfig = configurations.create("testArtifacts") {
extendsFrom(configurations["testCompile"])
}
tasks.register("testJar", Jar::class.java) {
dependsOn("testClasses")
classifier += "test"
from(sourceSets["test"].output)
}
artifacts {
add("testArtifacts", tasks.named<Jar>("testJar") )
}
tem build.gradle.kts
testImplementation(project(":core", "testArtifacts"))

How to create a custom task in gradle to pack java and kotlin code to a jar?

We have a multi modular setup and we are sharing some tests classes between the modules (mainly Fakes implementations). Our current solution (that you can find below) works just for classes written in Java, but we are looking at supporting also shared kotlin classes.
if (isAndroidLibrary()) {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileDebugUnitTestJavaWithJavac.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = compileDebugUnitTestSources
} else {
task compileTestCommonJar(type: JavaCompile) {
classpath = compileTestJava.classpath
source sourceSets.testShared.java.srcDirs
destinationDir = file('build/testCommon')
}
taskToDependOn = testClasses
}
task testJar(type: Jar, dependsOn: taskToDependOn) {
classifier = 'tests'
from compileTestCommonJar.outputs
}
How can I modify the compileTestCommonJar so it supports kotlin?
Here is what we do:
In the module with shared test classes, pack the test source set output into a jar
configurations { tests }
...
task testJar(type: Jar, dependsOn: testClasses) {
baseName = "test-${project.archivesBaseName}"
from sourceSets.test.output
}
artifacts { tests testJar }
In a module that depends on the shared classes
dependencies {
testCompile project(path: ":my-project-with-shared-test-classes", configuration: "tests")
}
PS: Honestly, I would prefer to have a separate Gradle module with common test classes as it's more explicit solution.
The task compileTestCommonJar(type: JavaCompile) compiles .java files only because its the task of JavaCompile type.
There's KotlinCompile task aswell, so you would need to merge it, it basically works similary to JavaCompile but compiles .kt files only.
Said that i wouldn't use task system to share the dependencies across, i would use separate module and work with default compileTestKotlin and compileTestJava task's outputs

Unable to resolve library using Gradle. Resolved using Grape

I'm fairly new to Groovy and I'm trying to wrap my head around Gradle. If I import the org.jvnet.hudson.plugins through Grapes it works perfectly and the dependency is resolved. But if I try to retrieve the dependency using Gradle the dependency is not resolved.
The package org.eclipse.hudson:hudson-core:3.2.1 works with both Gradle and Grape.
A dependency that is not resolved using Gradle
compile 'org.jvnet.hudson.plugins:checkstyle:3.42'
A dependency which is resolved using Grape
#Grab('org.jvnet.hudson.plugins:checkstyle:3.42')
A dependency which is resolved using Gradle
compile 'org.eclipse.hudson:hudson-core:3.2.1'
Error during Gradle build
line 3, column 1.
import hudson.plugins.checkstyle.CheckStyleResultAction;
^
The build.gradle
apply plugin: 'groovy'
repositories {
mavenCentral()
maven {
url "http://repo.jenkins-ci.org/releases/"
}
}
configurations {
ivy
}
sourceSets {
main {
groovy {
srcDirs = ['src/']
}
}
test {
groovy {
srcDirs = ['test/']
}
}
}
dependencies {
compile 'org.codehaus.groovy:groovy-all:2.4.11'
compile "org.apache.ivy:ivy:2.4.0"
ivy "org.apache.ivy:ivy:2.3.0"
// Works
compile 'org.eclipse.hudson:hudson-core:3.2.1'
// Does not work
compile 'org.jvnet.hudson.plugins:checkstyle:3.42'
}
tasks.withType(GroovyCompile) {
groovyClasspath += configurations.ivy
}
You're probably not actually downloading the jar you think you are. Looks like the default artifact that comes back from the org.jvnet.hudson.plugins:checkstyle:3.42 dependency is actually a file named checkstyle-3.42.hpi.
To get the jar which contains the classes instead, use:
compile group: 'org.jvnet.hudson.plugins', name: 'checkstyle', version:'3.42', ext: 'jar'
Then that class will be found on your classpath (and you'll be on to locating the next missing dependency).

Resources