diff --git a/build.gradle.kts b/build.gradle.kts index 8f6f26386..635595be6 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -37,6 +37,7 @@ buildscript { plugins { kotlin("jvm") // version Versions.kotlinCompiler kotlin("plugin.serialization") version Versions.kotlinCompiler + id("com.google.osdetector") id("org.jetbrains.dokka") version Versions.dokka id("me.him188.kotlin-jvm-blocking-bridge") version Versions.blockingBridge id("me.him188.kotlin-dynamic-delegation") version Versions.dynamicDelegation @@ -44,6 +45,8 @@ plugins { id("org.jetbrains.kotlinx.binary-compatibility-validator") version Versions.binaryValidator apply false } +osDetector = osdetector + GpgSigner.setup(project) analyzes.CompiledCodeVerify.run { registerAllVerifyTasks() } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8445d4d16..6fbc735dc 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -58,5 +58,7 @@ dependencies { api(asm("util")) api(asm("commons")) + api("gradle.plugin.com.google.gradle:osdetector-gradle-plugin:1.7.0") + api(gradleApi()) } \ No newline at end of file diff --git a/buildSrc/src/main/kotlin/HmppConfigure.kt b/buildSrc/src/main/kotlin/HmppConfigure.kt index 5e851695f..f45e3b903 100644 --- a/buildSrc/src/main/kotlin/HmppConfigure.kt +++ b/buildSrc/src/main/kotlin/HmppConfigure.kt @@ -7,25 +7,84 @@ * https://github.com/mamoe/mirai/blob/dev/LICENSE */ +import com.google.gradle.osdetector.OsDetector import org.apache.tools.ant.taskdefs.condition.Os import org.gradle.api.Project import org.gradle.api.attributes.Attribute import org.gradle.kotlin.dsl.get +import org.gradle.kotlin.dsl.getting import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import java.io.File private val miraiPlatform = Attribute.of( - "net.mamoe.mirai.platform", - String::class.java + "net.mamoe.mirai.platform", String::class.java ) +val IDEA_ACTIVE = System.getProperty("idea.active") == "true" && System.getProperty("publication.test") != "true" + +val NATIVE_ENABLED = System.getProperty("mirai.enable.native", "true").toBoolean() +val ANDROID_ENABLED = System.getProperty("mirai.enable.android", "true").toBoolean() + +val OS_NAME = System.getProperty("os.name").toLowerCase() + +enum class HostKind { + LINUX, WINDOWS, MACOS, +} + +val HOST_KIND = when { + OS_NAME.contains("windows", true) -> HostKind.WINDOWS + OS_NAME.contains("mac", true) -> HostKind.MACOS + else -> HostKind.LINUX +} + +enum class HostArch { + X86, X64, ARM32, ARM64 +} + +lateinit var osDetector: OsDetector + +val MAC_TARGETS: Set by lazy { + if (!IDEA_ACTIVE) setOf( +// "watchosX86", + "macosX64", + "macosArm64", + + // Failed to generate cinterop for :mirai-core:cinteropOpenSSLIosX64: Process 'command '/Library/Java/JavaVirtualMachines/temurin-17.jdk/Contents/Home/bin/java'' finished with non-zero exit value 1 + // Exception in thread "main" java.lang.Error: /var/folders/kw/ndw272ns06s7cys2mcwwlb5c0000gn/T/1181140105365175708.c:1:10: fatal error: 'openssl/ec.h' file not found + // + // Note: the openssl/ec.h is actually there, seems Kotlin doesn't support that + +// "iosX64", +// "iosArm64", +// "iosArm32", +// "iosSimulatorArm64", +// "watchosX64", +// "watchosArm32", +// "watchosArm64", +// "watchosSimulatorArm64", +// "tvosX64", +// "tvosArm64", +// "tvosSimulatorArm64", + ) else setOf( + // IDEA active, reduce load + if (osDetector.arch.contains("aarch")) "macosArm64" else "macosX64" + ) +} + +val WIN_TARGETS = setOf("mingwX64") + +val LINUX_TARGETS = setOf("linuxX64") + +val UNIX_LIKE_TARGETS by lazy { LINUX_TARGETS + MAC_TARGETS } + fun Project.configureHMPPJvm() { extensions.getByType(KotlinMultiplatformExtension::class.java).apply { @@ -37,7 +96,7 @@ fun Project.configureHMPPJvm() { // attributes.attribute(miraiPlatform, "jvmBase") } - if (isAndroidSDKAvailable) { + if (isAndroidSDKAvailable && ANDROID_ENABLED) { jvm("android") { attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.androidJvm) // publishAllLibraryVariants() @@ -49,85 +108,215 @@ fun Project.configureHMPPJvm() { jvm("jvm") { } - - - val ideaActive = System.getProperty("idea.active") == "true" && System.getProperty("publication.test") != "true" - - val nativeMainSets = mutableListOf() - val nativeTestSets = mutableListOf() - val nativeTargets = mutableListOf() - - if (ideaActive) { - val target = when { - Os.isFamily(Os.FAMILY_MAC) -> if (Os.isArch("aarch64")) macosArm64("native") else macosX64("native") - Os.isFamily(Os.FAMILY_WINDOWS) -> mingwX64("native") - else -> linuxX64("native") - } - nativeTargets.add(target) - } else { - // 1.6.0 - val nativeTargetNames: List = arrayOf( - // serialization doesn't support those commented targets -// "androidNativeArm32, androidNativeArm64, androidNativeX86, androidNativeX64", - "iosArm32, iosArm64, iosX64, iosSimulatorArm64", - "watchosArm32, watchosArm64, watchosX86, watchosX64, watchosSimulatorArm64", - "tvosArm64, tvosX64, tvosSimulatorArm64", - "macosX64, macosArm64", - "linuxMips32, linuxMipsel32, linuxX64", - "mingwX64", -// "wasm32" // linuxArm32Hfp, mingwX86 - ).flatMap { it.split(",") }.map { it.trim() } - presets.filter { it.name in nativeTargetNames } - .forEach { preset -> - val target = targetFromPreset(preset, preset.name) as KotlinNativeTarget - nativeMainSets.add(target.compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.first()) - nativeTestSets.add(target.compilations[TEST_COMPILATION_NAME].kotlinSourceSets.first()) - nativeTargets.add(target) - } - - if (!ideaActive) { - configure(nativeMainSets) { - dependsOn(sourceSets.maybeCreate("nativeMain")) - } - - configure(nativeTestSets) { - dependsOn(sourceSets.maybeCreate("nativeTest")) - } - } - } - - configureNativeInterop("main", projectDir.resolve("src/nativeMainInterop"), nativeTargets) - configureNativeInterop("test", projectDir.resolve("src/nativeTestInterop"), nativeTargets) - - - val sourceSets = kotlinSourceSets.orEmpty() - val commonMain = sourceSets.single { it.name == "commonMain" } - val commonTest = sourceSets.single { it.name == "commonTest" } - val jvmBaseMain = this.sourceSets.maybeCreate("jvmBaseMain") - val jvmBaseTest = this.sourceSets.maybeCreate("jvmBaseTest") - val jvmMain = sourceSets.single { it.name == "jvmMain" } - val jvmTest = sourceSets.single { it.name == "jvmTest" } - val androidMain = sourceSets.single { it.name == "androidMain" } - val androidTest = sourceSets.single { it.name == "androidTest" } - - val nativeMain = sourceSets.single { it.name == "nativeMain" } - val nativeTest = sourceSets.single { it.name == "nativeTest" } - - - jvmBaseMain.dependsOn(commonMain) - jvmBaseTest.dependsOn(commonTest) - - jvmMain.dependsOn(jvmBaseMain) - androidMain.dependsOn(jvmBaseMain) - - jvmTest.dependsOn(jvmBaseTest) - androidTest.dependsOn(jvmBaseTest) - - nativeMain.dependsOn(commonMain) - nativeTest.dependsOn(commonTest) } } +///** +// * [IDEA_ACTIVE] 时配置单一 'native' target, 基于 host 平台; 否则配置所有 native targets 依赖 'native' 作为中间平台. +// */ +//@Deprecated("") +//fun KotlinMultiplatformExtension.configureNativeTargets( +// project: Project +//) { +// val nativeMainSets = mutableListOf() +// val nativeTestSets = mutableListOf() +// val nativeTargets = mutableListOf() +// +// if (IDEA_ACTIVE) { +// val target = when { +// Os.isFamily(Os.FAMILY_MAC) -> if (Os.isArch("aarch64")) macosArm64("native") else macosX64( +// "native" +// ) +// Os.isFamily(Os.FAMILY_WINDOWS) -> mingwX64("native") +// else -> linuxX64("native") +// } +// nativeTargets.add(target) +// } else { +// // 1.6.0 +// val nativeTargetNames: List = arrayOf( +// // serialization doesn't support those commented targets +//// "androidNativeArm32, androidNativeArm64, androidNativeX86, androidNativeX64", +// "iosArm32, iosArm64, iosX64, iosSimulatorArm64", +// "watchosArm32, watchosArm64, watchosX86, watchosX64, watchosSimulatorArm64", +// "tvosArm64, tvosX64, tvosSimulatorArm64", +// "macosX64, macosArm64", +//// "linuxMips32, linuxMipsel32, linuxX64", +// "linuxX64", +// "mingwX64", +//// "wasm32" // linuxArm32Hfp, mingwX86 +// ).flatMap { it.split(",") }.map { it.trim() } +// presets.filter { it.name in nativeTargetNames }.forEach { preset -> +// val target = targetFromPreset(preset, preset.name) as KotlinNativeTarget +// nativeMainSets.add(target.compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.first()) +// nativeTestSets.add(target.compilations[TEST_COMPILATION_NAME].kotlinSourceSets.first()) +// nativeTargets.add(target) +// } +// +// if (!IDEA_ACTIVE) { +// project.configure(nativeMainSets) { +// dependsOn(sourceSets.maybeCreate("nativeMain")) +// } +// +// project.configure(nativeTestSets) { +// dependsOn(sourceSets.maybeCreate("nativeTest")) +// } +// } +// } +// +// project.configureNativeInterop("main", project.projectDir.resolve("src/nativeMainInterop"), nativeTargets) +// project.configureNativeInterop("test", project.projectDir.resolve("src/nativeTestInterop"), nativeTargets) +// project.configureNativeLinkOptions(nativeTargets) +// +// val sourceSets = project.kotlinSourceSets.orEmpty() +// val commonMain = sourceSets.single { it.name == "commonMain" } +// val commonTest = sourceSets.single { it.name == "commonTest" } +// val jvmBaseMain = this.sourceSets.maybeCreate("jvmBaseMain") +// val jvmBaseTest = this.sourceSets.maybeCreate("jvmBaseTest") +// val jvmMain = sourceSets.single { it.name == "jvmMain" } +// val jvmTest = sourceSets.single { it.name == "jvmTest" } +// val androidMain = sourceSets.single { it.name == "androidMain" } +// val androidTest = sourceSets.single { it.name == "androidTest" } +// +// val nativeMain = sourceSets.single { it.name == "nativeMain" } +// val nativeTest = sourceSets.single { it.name == "nativeTest" } +// +// +// jvmBaseMain.dependsOn(commonMain) +// jvmBaseTest.dependsOn(commonTest) +// +// jvmMain.dependsOn(jvmBaseMain) +// androidMain.dependsOn(jvmBaseMain) +// +// jvmTest.dependsOn(jvmBaseTest) +// androidTest.dependsOn(jvmBaseTest) +// +// nativeMain.dependsOn(commonMain) +// nativeTest.dependsOn(commonTest) +//} + +/** + * ``` + * common + * | + * /---------------+---------------\ + * jvmBase native + * / \ / \ + * jvm android unix \ + * / \ mingwX64 + * / \ + * darwin linuxX64 + * | + * * + * + * ``` + * + * ``: macosX64, macosArm64, tvosX64, iosArm64, iosArm32... + */ +fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical( + project: Project +) { + val nativeMainSets = mutableListOf() + val nativeTestSets = mutableListOf() + val nativeTargets = mutableListOf() + + + fun KotlinMultiplatformExtension.addNativeTarget( + preset: KotlinTargetPreset<*>, + ): KotlinNativeTarget { + val target = targetFromPreset(preset, preset.name) as KotlinNativeTarget + nativeMainSets.add(target.compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.first()) + nativeTestSets.add(target.compilations[TEST_COMPILATION_NAME].kotlinSourceSets.first()) + nativeTargets.add(target) + return target + } + + + // project.configureNativeInterop("main", project.projectDir.resolve("src/nativeMainInterop"), nativeTargets) + // project.configureNativeInterop("test", project.projectDir.resolve("src/nativeTestInterop"), nativeTargets) + + + val sourceSets = project.objects.domainObjectContainer(KotlinSourceSet::class.java) + .apply { addAll(project.kotlinSourceSets.orEmpty()) } + + val commonMain by sourceSets.getting + val commonTest by sourceSets.getting + val jvmBaseMain = this.sourceSets.maybeCreate("jvmBaseMain") + val jvmBaseTest = this.sourceSets.maybeCreate("jvmBaseTest") + val jvmMain by sourceSets.getting + val jvmTest by sourceSets.getting + val androidMain by sourceSets.getting + val androidTest by sourceSets.getting + + val nativeMain = this.sourceSets.maybeCreate("nativeMain") + val nativeTest = this.sourceSets.maybeCreate("nativeTest") + + val unixMain = this.sourceSets.maybeCreate("unixMain") + val unixTest = this.sourceSets.maybeCreate("unixTest") + + val darwinMain = this.sourceSets.maybeCreate("darwinMain") + val darwinTest = this.sourceSets.maybeCreate("darwinTest") + + presets.filter { it.name in MAC_TARGETS }.forEach { preset -> + addNativeTarget(preset).run { + compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(darwinMain) } + compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(darwinTest) } + } + } + + presets.filter { it.name in LINUX_TARGETS }.forEach { preset -> + addNativeTarget(preset).run { + compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(unixMain) } + compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(unixTest) } + } + } + + presets.filter { it.name in WIN_TARGETS }.forEach { preset -> + addNativeTarget(preset).run { + compilations[MAIN_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(nativeMain) } + compilations[TEST_COMPILATION_NAME].kotlinSourceSets.forEach { it.dependsOn(nativeTest) } + } + } + + jvmBaseMain.dependsOn(commonMain) + jvmBaseTest.dependsOn(commonTest) + + nativeMain.dependsOn(commonMain) + nativeTest.dependsOn(commonTest) + + unixMain.dependsOn(nativeMain) + unixTest.dependsOn(nativeTest) + + darwinMain.dependsOn(unixMain) + darwinTest.dependsOn(unixTest) + + jvmMain.dependsOn(jvmBaseMain) + jvmTest.dependsOn(jvmBaseTest) + + androidMain.dependsOn(jvmBaseMain) + androidTest.dependsOn(jvmBaseTest) +} + + +// e.g. Linker will try to link curl for mingwX64 but this can't be done on macOS. +fun Project.disableCrossCompile() { + project.afterEvaluate { + if (HOST_KIND != HostKind.MACOS) { + MAC_TARGETS.forEach { target -> disableTargetLink(this, target) } + } + if (HOST_KIND != HostKind.WINDOWS) { + WIN_TARGETS.forEach { target -> disableTargetLink(this, target) } + } + if (HOST_KIND != HostKind.LINUX) { + LINUX_TARGETS.forEach { target -> disableTargetLink(this, target) } + } + } +} + +private fun disableTargetLink(project: Project, target: String) { + project.tasks.getByName("linkDebugTest${target.titlecase()}").enabled = false + project.tasks.getByName("${target}Test").enabled = false +} + private fun Project.linkerDirs(): List { return listOf( ":mirai-core", @@ -149,23 +338,10 @@ private fun Project.includeDirs(): List { } private fun Project.configureNativeInterop( - compilationName: String, - nativeInteropDir: File, - nativeTargets: MutableList + compilationName: String, nativeInteropDir: File, nativeTargets: MutableList ) { val crateName = project.name.replace("-", "_") + "_i" - configure(nativeTargets) { - binaries { - for (buildType in NativeBuildType.values()) { - findTest(buildType)?.apply { - linkerOpts("-v") - linkerOpts(*linkerDirs().map { "-L$it" }.toTypedArray()) - linkerOpts("-undefined", "dynamic_lookup") // resolve symbol in runtime - } - } - } - } if (nativeInteropDir.exists() && nativeInteropDir.isDirectory && nativeInteropDir.resolve("build.rs").exists()) { val kotlinDylibName = project.name.replace("-", "_") + "_i" val kotlinDylibName = project.name.replace("-", "_") @@ -202,19 +378,14 @@ private fun Project.configureNativeInterop( val cbindgen = tasks.register("cbindgen${compilationName.titlecase()}") { group = "mirai" description = "Generate C Headers from Rust" - inputs.files( - project.objects.fileTree().from(nativeInteropDir.resolve("src")) - .filterNot { it.name == "bindings.rs" } - ) + inputs.files(project.objects.fileTree().from(nativeInteropDir.resolve("src")) + .filterNot { it.name == "bindings.rs" }) outputs.file(nativeInteropDir.resolve(headerName)) doLast { exec { workingDir(nativeInteropDir) commandLine( - "cbindgen", - "--config", "cbindgen.toml", - "--crate", crateName, - "--output", headerName + "cbindgen", "--config", "cbindgen.toml", "--crate", crateName, "--output", headerName ) } } @@ -267,30 +438,45 @@ private fun Project.configureNativeInterop( // targetCompilation!!.compileKotlinTask.dependsOn(cbindgen) // tasks.getByName("cinteropNative$name").dependsOn(cbindgen) } - targetCompilation!! - val compileRust = tasks.register("compileRust${compilationName.titlecase()}") { - group = "mirai" - inputs.files(nativeInteropDir.resolve("src")) - outputs.file(rustLibDir.resolve("lib$crateName.dylib")) + if (targetCompilation != null) { + val compileRust = tasks.register("compileRust${compilationName.titlecase()}") { + group = "mirai" + inputs.files(nativeInteropDir.resolve("src")) + outputs.file(rustLibDir.resolve("lib$crateName.dylib")) // dependsOn(targetCompilation!!.compileKotlinTask) - dependsOn(bindgen) - dependsOn(tasks.findByName("linkDebugSharedNative")) // dylib to link - doLast { - exec { - workingDir(nativeInteropDir) - commandLine( - "cargo", - "build", - "--color", "always", - "--all", + dependsOn(bindgen) + dependsOn(tasks.findByName("linkDebugSharedNative")) // dylib to link + doLast { + exec { + workingDir(nativeInteropDir) + commandLine( + "cargo", + "build", + "--color", "always", + "--all", // "--", "--color", "always", "2>&1" - ) + ) + } + } + } + + tasks.getByName("assemble").dependsOn(compileRust) + } + } +} + +private fun Project.configureNativeLinkOptions(nativeTargets: MutableList) { + configure(nativeTargets) { + binaries { + for (buildType in NativeBuildType.values()) { + findTest(buildType)?.apply { + linkerOpts("-v") + linkerOpts(*linkerDirs().map { "-L$it" }.toTypedArray()) + linkerOpts("-undefined", "dynamic_lookup") // resolve symbol in runtime } } } - - tasks.getByName("assemble").dependsOn(compileRust) } } diff --git a/buildSrc/src/main/kotlin/MppPublishing.kt b/buildSrc/src/main/kotlin/MppPublishing.kt index d2b3116cf..21ca3aa8c 100644 --- a/buildSrc/src/main/kotlin/MppPublishing.kt +++ b/buildSrc/src/main/kotlin/MppPublishing.kt @@ -24,11 +24,11 @@ fun Project.configureMppPublishing() { // mirai does some magic on MPP targets afterEvaluate { - tasks.findByName("compileKotlinCommon")?.enabled = false - tasks.findByName("compileTestKotlinCommon")?.enabled = false +// tasks.findByName("compileKotlinCommon")?.enabled = false +// tasks.findByName("compileTestKotlinCommon")?.enabled = false - tasks.findByName("compileCommonMainKotlinMetadata")?.enabled = false - tasks.findByName("compileKotlinMetadata")?.enabled = false +// tasks.findByName("compileCommonMainKotlinMetadata")?.enabled = false +// tasks.findByName("compileKotlinMetadata")?.enabled = false // TODO: 2021/1/30 如果添加 JVM 到 root module, 这个 task 会失败因 root module artifacts 有变化 // tasks.findByName("generateMetadataFileForKotlinMultiplatformPublication")?.enabled = false // FIXME: 2021/1/21 diff --git a/buildSrc/src/main/kotlin/Versions.kt b/buildSrc/src/main/kotlin/Versions.kt index 4e564e2ed..a994a7b70 100644 --- a/buildSrc/src/main/kotlin/Versions.kt +++ b/buildSrc/src/main/kotlin/Versions.kt @@ -28,7 +28,7 @@ object Versions { const val kotlinCompilerForIdeaPlugin = "1.7.0-RC" - const val coroutines = "1.6.1" + const val coroutines = "1.6.2" const val atomicFU = "0.17.2" const val serialization = "1.3.2" const val ktor = "1.6.7" @@ -108,6 +108,9 @@ val `ktor-serialization` = ktor("serialization", Versions.ktor) val `ktor-client-core` = ktor("client-core", Versions.ktor) val `ktor-client-cio` = ktor("client-cio", Versions.ktor) +val `ktor-client-mock` = ktor("client-mock", Versions.ktor) +val `ktor-client-curl` = ktor("client-curl", Versions.ktor) +val `ktor-client-ios` = ktor("client-ios", Versions.ktor) val `ktor-client-okhttp` = ktor("client-okhttp", Versions.ktor) val `ktor-client-android` = ktor("client-android", Versions.ktor) val `ktor-client-logging` = ktor("client-logging", Versions.ktor) diff --git a/mirai-console/tools/compiler-annotations/build.gradle.kts b/mirai-console/tools/compiler-annotations/build.gradle.kts index 059a1ec0f..c31327585 100644 --- a/mirai-console/tools/compiler-annotations/build.gradle.kts +++ b/mirai-console/tools/compiler-annotations/build.gradle.kts @@ -21,6 +21,7 @@ kotlin { explicitApi() configureHMPP() + configureNativeTargetsHierarchical(project) } configureMppPublishing() \ No newline at end of file diff --git a/mirai-core-api/build.gradle.kts b/mirai-core-api/build.gradle.kts index 342e886aa..6c7aa3964 100644 --- a/mirai-core-api/build.gradle.kts +++ b/mirai-core-api/build.gradle.kts @@ -28,6 +28,8 @@ kotlin { explicitApi() configureHMPP() + configureNativeTargetsHierarchical(project) + sourceSets { val commonMain by getting { diff --git a/mirai-core-utils/build.gradle.kts b/mirai-core-utils/build.gradle.kts index ea012015d..43079ebfc 100644 --- a/mirai-core-utils/build.gradle.kts +++ b/mirai-core-utils/build.gradle.kts @@ -24,6 +24,7 @@ kotlin { explicitApi() configureHMPP() + configureNativeTargetsHierarchical(project) sourceSets { val commonMain by getting { diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts index 08cfc5a49..b08e71316 100644 --- a/mirai-core/build.gradle.kts +++ b/mirai-core/build.gradle.kts @@ -26,6 +26,7 @@ kotlin { explicitApi() configureHMPP() + configureNativeTargetsHierarchical(project) sourceSets.apply {