首页 > 解决方案 > 将 gradle shadow 与 Kotlin 多平台一起使用

问题描述

有没有办法用 Kotlin 多平台项目设置 Gradle Shadow ?我正在使用多平台项目的“新”版本,其中我所有的源集定义/依赖项都在一个文件中。这是我的构建文件:

buildscript {
    ext.ktor_version = "1.0.0-beta-3"

    repositories {
       maven { url "https://plugins.gradle.org/m2/"}
    }

    dependencies {
        classpath "com.github.jengelman.gradle.plugins:shadow:4.0.2"
    }
}


plugins {
    id 'kotlin-multiplatform' version '1.3.0'
    id 'com.github.johnrengelman.shadow' version '4.0.2'
    id 'application'
}

version = '1.0'
group = '[redacted]'
mainClassName = '[redacted]'

repositories {
    maven { url "https://dl.bintray.com/kotlin/exposed" }
    maven { url "https://dl.bintray.com/kotlin/ktor" }
    mavenCentral()
    jcenter()
}
kotlin {
    targets {
        fromPreset(presets.jvm, 'jvm')
        fromPreset(presets.js, 'js')
    }
    sourceSets {
        commonMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
            }
        }
        commonTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test-common'
                implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
            }
        }
        jvmMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
                implementation 'org.jetbrains.exposed:exposed:0.11.2'
                implementation "org.mindrot:jbcrypt:0.4"
                implementation "org.slf4j:slf4j-simple:1.8.0-beta2"
                implementation "io.ktor:ktor-server-netty:$ktor_version"
                implementation "io.ktor:ktor-jackson:$ktor_version"
                implementation "mysql:mysql-connector-java:8.0.13"
            }
        }
        jvmTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test'
                implementation 'org.jetbrains.kotlin:kotlin-test-junit'
            }
        }
        jsMain {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-stdlib-js'
            }
        }
        jsTest {
            dependencies {
                implementation 'org.jetbrains.kotlin:kotlin-test-js'
            }
        }
    }
}

shadowJar {
    baseName = '[redacted]'
    version = 1.0
}

尝试使用它时,我得到了一个 JAR 文件的可悲结果,只有 META-INF(304 字节)。老实说,我不确定从哪里开始,这让我思考和困惑了好几个小时。任何人的帮助将不胜感激。

我的项目的骨架:

├── build.gradle
├── gradle.properties
├── settings.gradle
└── src
    ├── commonMain
    │   └── kotlin
    │       ├── PasswordValidator.kt
    │       └── Responses.kt
    └── jvmMain
        └── kotlin
            └── XXX
                └── XXXXXX
                    └── ticketing
                        ├── Auth.kt
                        ├── Registration.kt
                        ├── Server.kt
                        ├── requests
                        │   ├── Auth.kt
                        │   ├── Register.kt
                        │   └── account
                        │       ├── Close.kt
                        │       ├── List.kt
                        │       ├── ModifyPassword.kt
                        │       ├── New.kt
                        │       └── SetAdmin.kt
                        └── services
                            ├── AsyncHandler.kt
                            ├── Exception.kt
                            ├── RateLimiter.kt
                            └── Token.kt

标签: gradlegroovykotlinbuild-script

解决方案


我确实有一个适用于kotlin-multiplatform插件版本1.3.31和通过 IntelliJNew Project/Kotlin/JS Client and JVM Server | Gradle选项生成的项目的解决方案。

buildscript {
  repositories {
    jcenter()
  }
}

plugins {
  id 'com.github.johnrengelman.shadow' version '5.0.0'
  id 'kotlin-multiplatform' version '1.3.31'
}

import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar

repositories {
  jcenter()
  maven { url "https://dl.bintray.com/kotlin/ktor" }
  mavenCentral()
}
def ktor_version = '1.2.1'
def logback_version = '1.2.3'

kotlin {
  jvm()
  js() {
    compilations.all {
      kotlinOptions {
        languageVersion = "1.3"
        moduleKind = "umd"
        sourceMap = true
        metaInfo = true
      }
    }
  }
  sourceSets {
    commonMain {
      dependencies {
        implementation kotlin('stdlib-common')
      }
    }
    commonTest {
      dependencies {
        implementation kotlin('test-common')
        implementation kotlin('test-annotations-common')
      }
    }
    jvmMain {
      dependencies {
        implementation kotlin('stdlib-jdk8')
        implementation "io.ktor:ktor-server-netty:$ktor_version"
        implementation "io.ktor:ktor-html-builder:$ktor_version"
        implementation "io.ktor:ktor-jackson:$ktor_version"
        implementation "ch.qos.logback:logback-classic:$logback_version"
      }
    }
    jvmTest {
      dependencies {
        implementation kotlin('test')
        implementation kotlin('test-junit')
        implementation "io.ktor:ktor-server-test-host:$ktor_version"
      }
    }
    jsMain {
      dependencies {
        implementation kotlin('stdlib-js')
      }
    }
    jsTest {
      dependencies {
        implementation kotlin('test-js')
      }
    }
  }
}

def webFolder = new File(project.buildDir, "web")
def jsCompilations = kotlin.targets.js.compilations

task populateWebFolder(dependsOn: [jsMainClasses]) {
  doLast {
    copy {
      from jsCompilations.main.output
      from kotlin.sourceSets.jsMain.resources.srcDirs
      jsCompilations.test.runtimeDependencyFiles.each {
        if (it.exists() && !it.isDirectory()) {
          from zipTree(it.absolutePath).matching { include '*.js' }
        }
      }
      into webFolder
    }
  }
}

jsJar.dependsOn(populateWebFolder)

def mainServerClassName = "org.pongasoft.jamba.quickstart.server.be.ServerKt"

task run(type: JavaExec, dependsOn: [jvmMainClasses, jsJar]) {
  main = mainServerClassName
  ignoreExitValue = true
  classpath {
    [
        kotlin.targets.jvm.compilations.main.output.allOutputs.files,
        configurations.jvmRuntimeClasspath,
    ]
  }
  args = ["-P:org.pongasoft.jamba.quickstart.server.staticWebDir=${webFolder.canonicalPath}"]
}

task shadowJar(type: ShadowJar, dependsOn: [jvmJar]) {
  from jvmJar.archiveFile
  configurations = [project.configurations.jvmRuntimeClasspath]
  manifest {
      attributes 'Main-Class': mainServerClassName
  }
}

根据文档,我认为为什么它不起作用的主要问题是:

来自:Shadow 文档,Shadow 是一个反应式插件。这意味着单独应用 Shadow 不会对您的项目执行任何配置。相反,Shadow 做出反应这意味着,对于大多数用户而言,必须显式应用 java 或 groovy 插件才能获得所需的效果。

因此,它不能与具有非传统设置的 kotlin 多平台插件一起使用。所以诀窍是定义一个ShadowJar任务,该任务依赖jvmJar并使用工件作为它的from( jvmJar.archiveFile) 和project.configurations.jvmRuntimeClasspath包含所有运行时依赖项的配置。这也是定义Main-Class清单条目的地方。

请注意,此版本不捆绑为编译的 javascript 部分生成的静态资源。


推荐阅读