Compare commits

..

7 Commits

14 changed files with 410 additions and 24 deletions

151
README.md Normal file
View File

@ -0,0 +1,151 @@
[//]: # ([![Kotlin](https://img.shields.io/badge/Kotlin-2.0.20-blue.svg?logo=kotlin)](https://kotlinlang.org))
# Gradle buildscript utilities for Kotlin/Multiplatform
## Getting
### As library
```kotlin
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.*
buildscript {
repositories {
mavenCentral()
maven("https://maven.landgrafhomyak.ru/")
}
dependencies {
classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build-helper:v0.2k2.0.20")
}
}
plugins {
kotlin("multiplatform") version "2.0.20" // version of kotlin must be the same as in this library
}
repositories {
mavenCentral()
}
kotlin {
optInContracts()
// ...
defineAllMultiplatformTargets()
sourceSets {
// ...
}
}
```
### As plugin (custom repository)
```kotlin
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.*
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.xomrk
buildscript {
repositories {
mavenCentral()
maven("https://maven.landgrafhomyak.ru/")
}
dependencies {
classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build:v0.2k2.0.20")
}
}
plugins {
// kotlin/multiplatorm and other plugins will be lazily enabled by dsl
}
repositories {
mavenCentral()
}
xomrk {
// lazily enables kotlin if not yet
kotlin {
// same as with original kotlin plugin
}
// lazily enables `maven-publish` if not yet
publishing {
// same as with original kotlin plugin
}
}
```
### As plugin (gradle portal)
This library officially isn't published, so this way wouldn't work
```kotlin
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.*
plugins {
id("ru.landgrafhomyak.kotlin.original-multiplatform-ext") version "v0.2k2.0.20"
}
repositories {
mavenCentral()
}
xomrk {
// lazily enables kotlin if not yet
kotlin {
// same as with original kotlin plugin
}
// lazily enables `maven-publish` if not yet
publishing {
// same as with original kotlin plugin
}
}
```
## Functionality
```kotlin
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.*
// ...
kotlin {
// Configures compilations of all targets
configureAllCompilations { }
// Configures compiler for all targets
configureAllCompilersOptions { }
// Removes warning "expect/actual mechanism is experimental"
noWarnExpectActual()
warningsAsErrors()
// Opt-ins specified annotation to all targets
optIn("org.example.OptIn")
// optIn("kotlin.contracts.ExperimentalContracts")
optInContracts()
// sets kotlin compatibility (both api and language) for all targets
setCompatibilityWithKotlin(org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_2_0)
// defines all possible targets, useful for 'algorithm' libraries that are not depends on platform
defineAllMultiplatformTargets()
}
publishing {
// useful for single-platform (e.g. JVM-only) libraries
forceSetAllMavenArtifactsId(project.name)
// safe replacing for libraries with many targets
replaceAllMavenArtifactsIdPrefixes(project.name, "custom-name")
// replacing of platform id (but better to do it in kotlin {...} block)
replaceAllMavenArtifactsIdSuffixes("js", "frontend")
}
```

61
embed/build.gradle.kts Normal file
View File

@ -0,0 +1,61 @@
import java.util.Properties
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineXomrkGiteaMavenRepo
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.forceSetAllMavenArtifactsId
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.optInContracts
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.setCompatibilityWithKotlin
buildscript {
val versions = java.util.Properties()
versions.load(rootDir.resolve("../versions.properties").inputStream())
dependencies {
classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build-helper:v${versions.getProperty("this")}k${versions.getProperty("kotlin")}")
}
}
plugins {
kotlin("multiplatform") version "2.0.20"
`maven-publish`
}
val versions = Properties()
versions.load(rootDir.resolve("../versions.properties").inputStream())
val targetKotlinVersion = versions.getProperty("kotlin")
group = "ru.landgrafhomyak.kotlin"
version = "v${versions.getProperty("this")}k${targetKotlinVersion}"
repositories {
mavenCentral()
}
kotlin {
optInContracts()
jvmToolchain(8)
jvm()
setCompatibilityWithKotlin(KotlinVersion.KOTLIN_1_8)
sourceSets {
jvmMain {
dependencies {
compileOnly("dev.gradleplugins:gradle-api:${versions.getProperty("gradle")}")
api("${group}:kotlin-mpp-gradle-build-helper:${version}")
api("org.jetbrains.kotlin:kotlin-gradle-plugin:${targetKotlinVersion}")
}
}
}
}
publishing {
repositories {
defineXomrkGiteaMavenRepo()
}
forceSetAllMavenArtifactsId(project.name)
}

View File

@ -0,0 +1,2 @@
rootProject.name = "kotlin-mpp-gradle-build"

View File

@ -0,0 +1,22 @@
package ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin
import org.gradle.api.Plugin
import org.gradle.api.Project
class SetupBuildScript : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.add("xomrk", XomrkDsl(project))
}
internal object PluginIDs {
@JvmStatic
val THIS = "ru.landgrafhomyak.kotlin.original-multiplatform-ext"
@JvmStatic
val KOTLIN_MULTIPLATFORM = "org.jetbrains.kotlin.multiplatform"
@JvmStatic
val MAVEN_PUBLISHING = "org.gradle.maven-publish"
}
}

View File

@ -0,0 +1,43 @@
package ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.reflect.KClass
import org.gradle.api.Project
import org.gradle.api.publish.PublishingExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.SetupBuildScript.PluginIDs
class XomrkDsl internal constructor(private val project: Project) {
@Suppress("FunctionName")
private fun <T : Any> _wrapExtension(
@Suppress("SameParameterValue") pluginId: String,
extensionClass: KClass<T>,
config: T.() -> Unit
) {
contract {
callsInPlace(config, InvocationKind.EXACTLY_ONCE)
}
if (null == this.project.plugins.findPlugin(pluginId)) {
this.project.plugins.apply(pluginId)
}
val dsl = this.project.extensions.findByType(extensionClass.java) ?: throw RuntimeException("Can't get extension")
config(dsl)
}
fun kotlin(config: KotlinMultiplatformExtension.() -> Unit) {
contract {
callsInPlace(config, InvocationKind.EXACTLY_ONCE)
}
this._wrapExtension(PluginIDs.KOTLIN_MULTIPLATFORM, KotlinMultiplatformExtension::class, config)
}
fun publishing(config: PublishingExtension.() -> Unit) {
this._wrapExtension(PluginIDs.MAVEN_PUBLISHING, PublishingExtension::class, config)
}
}

View File

@ -0,0 +1,20 @@
package ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin
import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import org.gradle.api.Project
@Suppress("unused")
fun Project.xomrk(config: XomrkDsl.() -> Unit) {
contract {
callsInPlace(config, InvocationKind.EXACTLY_ONCE)
}
if (null == this.plugins.findPlugin(SetupBuildScript::class.java)) {
this.plugins.apply(SetupBuildScript::class.java)
}
val dsl = this.extensions.findByType(XomrkDsl::class.java) ?: throw RuntimeException("Can't install helper plugin")
config(dsl)
}

View File

@ -0,0 +1 @@
implementation-class=ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.SetupBuildScript

View File

@ -3,41 +3,68 @@
package ru.landgrafhomyak.kotlin.kmp_gradle_build_helper
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
public fun KotlinMultiplatformExtension.configureAllCompilations(action: KotlinCompilation<KotlinCommonOptions>.() -> Unit) {
public fun KotlinMultiplatformExtension.configureAllCompilationsOnAllTargets(action: KotlinCompilation<*>.() -> Unit) {
this.targets.configureEach { t ->
t.compilations.configureEach(action)
}
}
public fun KotlinMultiplatformExtension.configureAllCompilersOptions(action: KotlinCommonCompilerOptions.() -> Unit) {
@Deprecated(
message = "New name avoids confusions when function called on wrong scope",
replaceWith = ReplaceWith(
"this.configureAllCompilationsOnAllTargets",
"ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.configureAllCompilationsOnAllTargets"
)
)
public fun KotlinMultiplatformExtension.configureAllCompilations(action: KotlinCompilation<*>.() -> Unit): Unit =
this.configureAllCompilationsOnAllTargets(action)
public fun KotlinMultiplatformExtension.configureAllCompilersOptionsOnAllTargets(action: KotlinCommonCompilerOptions.() -> Unit) {
this.targets.configureEach { t ->
t.compilations.configureEach { c ->
c.compileTaskProvider.configure { t ->
t.compilerOptions(action)
}
t.configureAllCompilersOptionsOnAllCompilations(action)
}
}
@Deprecated(
message = "New name avoids confusions when function called on wrong scope",
replaceWith = ReplaceWith(
"this.configureAllCompilersOptionsOnAllTargets",
"ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.configureAllCompilersOptionsOnAllTargets"
)
)
public fun KotlinMultiplatformExtension.configureAllCompilersOptions(action: KotlinCommonCompilerOptions.() -> Unit): Unit =
this.configureAllCompilersOptionsOnAllTargets(action)
public fun KotlinTarget.configureAllCompilersOptionsOnAllCompilations(action: KotlinCommonCompilerOptions.() -> Unit) {
this.compilations.configureEach { c ->
c.compileTaskProvider.configure { t ->
t.compilerOptions(action)
}
}
}
public fun KotlinMultiplatformExtension.noWarnExpectActual(): Unit =
this.configureAllCompilersOptions { this@configureAllCompilersOptions.freeCompilerArgs.add("-Xexpect-actual-classes") }
this.configureAllCompilersOptionsOnAllTargets { this@configureAllCompilersOptionsOnAllTargets.freeCompilerArgs.add("-Xexpect-actual-classes") }
public fun KotlinMultiplatformExtension.warningsAsErrors(): Unit =
this.configureAllCompilersOptions { this@configureAllCompilersOptions.allWarningsAsErrors.set(true) }
this.configureAllCompilersOptionsOnAllTargets { this@configureAllCompilersOptionsOnAllTargets.allWarningsAsErrors.set(true) }
public fun KotlinMultiplatformExtension.optIn(classQualname: String): Unit =
this.configureAllCompilersOptions { this@configureAllCompilersOptions.optIn.add(classQualname) }
this.configureAllCompilersOptionsOnAllTargets { this@configureAllCompilersOptionsOnAllTargets.optIn.add(classQualname) }
public fun KotlinMultiplatformExtension.optInContracts(): Unit =
this.optIn("kotlin.contracts.ExperimentalContracts")
public fun KotlinMultiplatformExtension.optInUnsignedArrayTypes(): Unit =
this.optIn("kotlin.ExperimentalUnsignedTypes")
public fun KotlinMultiplatformExtension.setCompatibilityWithKotlin(version: KotlinVersion): Unit =
this.configureAllCompilersOptions {
this@configureAllCompilersOptions.apiVersion.set(version)
this@configureAllCompilersOptions.languageVersion.set(version)
this.configureAllCompilersOptionsOnAllTargets {
this@configureAllCompilersOptionsOnAllTargets.apiVersion.set(version)
this@configureAllCompilersOptionsOnAllTargets.languageVersion.set(version)
}

View File

@ -0,0 +1,22 @@
package ru.landgrafhomyak.kotlin.kmp_gradle_build_helper
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
public enum class Improvements {
JAVA_INTERFACES_DEFAULT_METHODS {
// since kotlin 1.4
override fun fix(target: KotlinMultiplatformExtension) {
target.configureAllCompilersOptions { freeCompilerArgs.add("-Xjvm-default=all") }
}
};
internal abstract fun fix(target: KotlinMultiplatformExtension)
}
public fun KotlinMultiplatformExtension.fixAllStrangeBehavioursExcept(vararg except: Improvements) {
(Improvements.values().toSet() - except.toSet()).forEach { f -> f.fix(this) }
}
public fun KotlinMultiplatformExtension.fixAllStrangeBehaviours(): Unit = this.fixAllStrangeBehavioursExcept()

View File

@ -0,0 +1,30 @@
package ru.landgrafhomyak.kotlin.kmp_gradle_build_helper
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication
public fun PublishingExtension.forceSetAllMavenArtifactsId(newName: String) {
this.publications { c ->
c.withType(MavenPublication::class.java) { p ->
p.artifactId = newName
}
}
}
public fun PublishingExtension.replaceAllMavenArtifactsIdPrefixes(oldPrefix: String, newPrefix: String) {
val pattern = Regex("^${Regex.escape(oldPrefix)}")
this.publications { c ->
c.withType(MavenPublication::class.java) { p ->
p.artifactId = p.artifactId.replace(pattern, newPrefix)
}
}
}
public fun PublishingExtension.replaceAllMavenArtifactsIdSuffixes(oldSuffix: String, newSuffix: String) {
val pattern = Regex("${Regex.escape(oldSuffix)}$")
this.publications { c ->
c.withType(MavenPublication::class.java) { p ->
p.artifactId = p.artifactId.replace(pattern, newSuffix)
}
}
}

View File

@ -1,2 +1,3 @@
includeBuild("impl")
includeBuild("embed")
includeBuild("test")

View File

@ -1,6 +1,9 @@
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.configureAllCompilations
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineAllMultiplatformTargets
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.defineXomrkGiteaMavenRepo
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.forceSetAllMavenArtifactsId
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.optInContracts
import ru.landgrafhomyak.kotlin.kmp_gradle_build_helper.plugin.xomrk
buildscript {
val versions = java.util.Properties()
@ -12,22 +15,24 @@ buildscript {
}
dependencies {
classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build-helper:v${versions.getProperty("this")}k${versions.getProperty("kotlin")}")
classpath("ru.landgrafhomyak.kotlin:kotlin-mpp-gradle-build:v${versions.getProperty("this")}k${versions.getProperty("kotlin")}")
}
}
plugins {
kotlin("multiplatform") version "2.0.20"
}
repositories {
mavenCentral()
defineXomrkGiteaMavenRepo()
}
xomrk {
kotlin {
jvmToolchain(8)
defineAllMultiplatformTargets()
optInContracts()
configureAllCompilations { this.compileTaskProvider }
}
kotlin {
jvmToolchain(8)
defineAllMultiplatformTargets()
optInContracts()
}
publishing {
forceSetAllMavenArtifactsId(project.name)
}
}

1
test/gradle.properties Normal file
View File

@ -0,0 +1 @@
kotlin.native.ignoreDisabledTargets=true

View File

@ -1,3 +1,3 @@
this=0.1
this=0.3
kotlin=2.0.20
gradle=7.5.1