native: 优化 build script 及 actions,修复 ECDH 相关资源释放问题 (#2110)

* build: fix build on Windows

* test: fix ContentEqualsTest on native

* build: allow disabling targets with property

* fix: free ECDH-related resources properly on native
avoid memory leaking (usually on *nix) or crash (usually on Windows)

Signed-off-by: AdoptOSS <adoptoss@outlook.com>

* build(workflow): remove invalid options

* fix(styling): `mirai.target` property

* build(workflow): try to limit memory usage during mirai-console:tools:gradle-plugin:integTest

* enhance(test): use buildList

* build(workflow): retry

Co-authored-by: ArcticLampyrid <arcticlampyrid@outlook.com>
This commit is contained in:
AdoptOSS 2022-06-25 10:40:29 +08:00 committed by Him188
parent afedbdad7b
commit 7325c1f7e2
12 changed files with 201 additions and 166 deletions

View File

@ -13,7 +13,7 @@ jobs:
- windows-2022 - windows-2022
- macos-12 - macos-12
env: env:
gradleArgs: --scan "-Pkotlin.compiler.execution.strategy=in-process" "-Dorg.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 --illegal-access=permit -Dkotlin.daemon.jvm.options=--illegal-access=permit --add-opens java.base/java.util=ALL-UNNAMED" gradleArgs: --scan "-Dmirai.target=jvm;android;!other" "-Pkotlin.compiler.execution.strategy=in-process" "-Dorg.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8"
isMac: ${{ startsWith(matrix.os, 'macos') }} isMac: ${{ startsWith(matrix.os, 'macos') }}
isWindows: ${{ startsWith(matrix.os, 'windows') }} isWindows: ${{ startsWith(matrix.os, 'windows') }}
isUbuntu: ${{ startsWith(matrix.os, 'ubuntu') }} isUbuntu: ${{ startsWith(matrix.os, 'ubuntu') }}
@ -34,6 +34,13 @@ jobs:
- if: ${{ env.isUnix == 'true' }} - if: ${{ env.isUnix == 'true' }}
run: chmod -R 777 * run: chmod -R 777 *
- if: ${{ env.isWindows == 'true' }}
name: Setup Memory Environment on Windows
run: >
wmic pagefileset where name="D:\\pagefile.sys" set InitialSize=1024,MaximumSize=9216 &
net stop mongodb
shell: cmd
continue-on-error: true
- name: Clean and download dependencies - name: Clean and download dependencies
run: ./gradlew clean ${{ env.gradleArgs }} run: ./gradlew clean ${{ env.gradleArgs }}
@ -295,22 +302,24 @@ jobs:
- macos-11 - macos-11
include: include:
- os: windows-2022 - os: windows-2022
testTaskName: mingwX64Test targetName: mingwX64
- os: ubuntu-20.04 - os: ubuntu-20.04
testTaskName: linuxX64Test targetName: linuxX64
- os: ubuntu-18.04 - os: ubuntu-18.04
testTaskName: linuxX64Test targetName: linuxX64
- os: macos-12 - os: macos-12
testTaskName: macosX64Test targetName: macosX64
- os: macos-11 - os: macos-11
testTaskName: macosX64Test targetName: macosX64
env: env:
gradleArgs: --scan "-Pkotlin.compiler.execution.strategy=in-process" "-Dorg.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8 --illegal-access=permit -Dkotlin.daemon.jvm.options=--illegal-access=permit --add-opens java.base/java.util=ALL-UNNAMED" # FIXME there must be two or more targets, or we'll get error on `@OptionalExpectation`
# > Declaration annotated with '@OptionalExpectation' can only be used in common module sources
gradleArgs: --scan "-Dmirai.target=jvm;${{ matrix.targetName }};!other" "-Pkotlin.compiler.execution.strategy=in-process" "-Dorg.gradle.jvmargs=-Xmx4096m -Dfile.encoding=UTF-8"
isMac: ${{ startsWith(matrix.os, 'macos') }} isMac: ${{ startsWith(matrix.os, 'macos') }}
isWindows: ${{ startsWith(matrix.os, 'windows') }} isWindows: ${{ startsWith(matrix.os, 'windows') }}
isUbuntu: ${{ startsWith(matrix.os, 'ubuntu') }} isUbuntu: ${{ startsWith(matrix.os, 'ubuntu') }}
isUnix: ${{ startsWith(matrix.os, 'macos') || startsWith(matrix.os, 'ubuntu') }} isUnix: ${{ startsWith(matrix.os, 'macos') || startsWith(matrix.os, 'ubuntu') }}
VCPKG_DEFAULT_BINARY_CACHE: ${{ startsWith(matrix.os, 'windows') && 'C:\\vcpkg\\binary_cache' || '/usr/local/share/vcpkg/binary_cache' }} VCPKG_DEFAULT_BINARY_CACHE: ${{ startsWith(matrix.os, 'windows') && 'C:\vcpkg\binary_cache' || '/usr/local/share/vcpkg/binary_cache' }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
@ -373,12 +382,6 @@ jobs:
shell: cmd shell: cmd
continue-on-error: true continue-on-error: true
- if: ${{ env.isWindows == 'true' }}
name: Setup C++ Toolchain Environment on Windows
run: |
'echo "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\MSVC\14.32.31326\bin\Hostx64\x64" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append'
'echo "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Tools\Llvm\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append'
- if: ${{ env.isWindows == 'true' }} - if: ${{ env.isWindows == 'true' }}
name: Install OpenSSL & cURL on Windows name: Install OpenSSL & cURL on Windows
run: | run: |
@ -393,10 +396,10 @@ jobs:
run: ./gradlew clean ${{ env.gradleArgs }} run: ./gradlew clean ${{ env.gradleArgs }}
- name: "Test mirai-core-utils for ${{ matrix.os }}" - name: "Test mirai-core-utils for ${{ matrix.os }}"
run: ./gradlew :mirai-core-utils:${{ matrix.testTaskName }} ${{ env.gradleArgs }} run: ./gradlew :mirai-core-utils:${{ matrix.targetName }}Test ${{ env.gradleArgs }}
- name: "Test mirai-core-api for ${{ matrix.os }}" - name: "Test mirai-core-api for ${{ matrix.os }}"
run: ./gradlew :mirai-core-api:${{ matrix.testTaskName }} ${{ env.gradleArgs }} run: ./gradlew :mirai-core-api:${{ matrix.targetName }}Test ${{ env.gradleArgs }}
- name: "Test mirai-core for ${{ matrix.os }}" - name: "Test mirai-core for ${{ matrix.os }}"
run: ./gradlew :mirai-core:${{ matrix.testTaskName }} ${{ env.gradleArgs }} run: ./gradlew :mirai-core:${{ matrix.targetName }}Test ${{ env.gradleArgs }}

View File

@ -21,7 +21,7 @@ import java.io.File
*/ */
object BinaryCompatibilityConfigurator { object BinaryCompatibilityConfigurator {
fun Project.configureBinaryValidators(vararg targetNames: String) { fun Project.configureBinaryValidators(targetNames: Set<String>) {
targetNames.forEach { configureBinaryValidator(it) } targetNames.forEach { configureBinaryValidator(it) }
} }

View File

@ -30,10 +30,6 @@ private val miraiPlatform = Attribute.of(
) )
val IDEA_ACTIVE = System.getProperty("idea.active") == "true" && System.getProperty("publication.test") != "true" val IDEA_ACTIVE = System.getProperty("idea.active") == "true" && System.getProperty("publication.test") != "true"
val WINDOWS_TARGET_ENABLED = System.getProperty("mirai.windows.target") != "false"
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() val OS_NAME = System.getProperty("os.name").toLowerCase()
@ -50,7 +46,7 @@ sealed class HostKind(
val targetName: String val targetName: String
) { ) {
object LINUX : HostKind("linuxX64") object LINUX : HostKind("linuxX64")
object WINDOWS : HostKind("windowsX64") object WINDOWS : HostKind("mingwX64")
abstract class MACOS(targetName: String) : HostKind(targetName) abstract class MACOS(targetName: String) : HostKind(targetName)
@ -68,6 +64,7 @@ val HOST_KIND by lazy {
HostKind.MACOS_X64 HostKind.MACOS_X64
} }
} }
else -> HostKind.LINUX else -> HostKind.LINUX
} }
} }
@ -76,8 +73,31 @@ enum class HostArch {
X86, X64, ARM32, ARM64 X86, X64, ARM32, ARM64
} }
/// eg. "!a;!b" means to enable all targets but a or b
/// eg. "a;b;!other" means to disable all targets but a or b
val ENABLED_TARGETS by lazy {
System.getProperty(
"mirai.target",
if (IDEA_ACTIVE)
"jvm;android;${HOST_KIND.targetName};!other"
else
""
).split(';').toSet()
}
fun isTargetEnabled(name: String): Boolean {
return when {
name in ENABLED_TARGETS -> true
"!$name" in ENABLED_TARGETS -> false
else -> "!other" !in ENABLED_TARGETS
}
}
fun Set<String>.filterTargets() =
this.filter { isTargetEnabled(it) }.toSet()
val MAC_TARGETS: Set<String> by lazy { val MAC_TARGETS: Set<String> by lazy {
if (!IDEA_ACTIVE) setOf( setOf(
// "watchosX86", // "watchosX86",
"macosX64", "macosX64",
"macosArm64", "macosArm64",
@ -98,23 +118,22 @@ val MAC_TARGETS: Set<String> by lazy {
// "tvosX64", // "tvosX64",
// "tvosArm64", // "tvosArm64",
// "tvosSimulatorArm64", // "tvosSimulatorArm64",
) else setOf( ).filterTargets()
// IDEA active, reduce load
HOST_KIND.targetName
)
} }
val WIN_TARGETS = if (WINDOWS_TARGET_ENABLED) setOf("mingwX64") else emptySet() val WIN_TARGETS by lazy { setOf("mingwX64").filterTargets() }
val LINUX_TARGETS = setOf("linuxX64") val LINUX_TARGETS by lazy { setOf("linuxX64").filterTargets() }
val UNIX_LIKE_TARGETS by lazy { LINUX_TARGETS + MAC_TARGETS } val UNIX_LIKE_TARGETS by lazy { LINUX_TARGETS + MAC_TARGETS }
val NATIVE_TARGETS by lazy { UNIX_LIKE_TARGETS + WIN_TARGETS } val NATIVE_TARGETS by lazy { UNIX_LIKE_TARGETS + WIN_TARGETS }
fun Project.configureJvmTargetsHierarchical() { fun Project.configureJvmTargetsHierarchical() {
extensions.getByType(KotlinMultiplatformExtension::class.java).apply { extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
val commonMain by sourceSets.getting
val commonTest by sourceSets.getting
if (IDEA_ACTIVE) { if (IDEA_ACTIVE) {
jvm("jvmBase") { // dummy target for resolution, not published jvm("jvmBase") { // dummy target for resolution, not published
compilations.all { compilations.all {
@ -125,19 +144,42 @@ fun Project.configureJvmTargetsHierarchical() {
} }
} }
if (isAndroidSDKAvailable && ANDROID_ENABLED) { val jvmBaseMain by lazy {
jvm("android") { sourceSets.maybeCreate("jvmBaseMain").apply {
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.androidJvm) dependsOn(commonMain)
if (IDEA_ACTIVE) { }
attributes.attribute(miraiPlatform, "android") // avoid resolution }
} val jvmBaseTest by lazy {
sourceSets.maybeCreate("jvmBaseTest").apply {
dependsOn(commonTest)
} }
} else {
printAndroidNotInstalled()
} }
jvm("jvm") { if (isTargetEnabled("android")) {
if (isAndroidSDKAvailable) {
jvm("android") {
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.androidJvm)
if (IDEA_ACTIVE) {
attributes.attribute(miraiPlatform, "android") // avoid resolution
}
}
val androidMain by sourceSets.getting
val androidTest by sourceSets.getting
androidMain.dependsOn(jvmBaseMain)
androidTest.dependsOn(jvmBaseTest)
} else {
printAndroidNotInstalled()
}
}
if (isTargetEnabled("jvm")) {
jvm("jvm") {
}
val jvmMain by sourceSets.getting
val jvmTest by sourceSets.getting
jvmMain.dependsOn(jvmBaseMain)
jvmTest.dependsOn(jvmBaseTest)
} }
} }
} }
@ -188,21 +230,39 @@ fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical(
val commonMain by sourceSets.getting val commonMain by sourceSets.getting
val commonTest 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 nativeMain by lazy {
val nativeTest = this.sourceSets.maybeCreate("nativeTest") this.sourceSets.maybeCreate("nativeMain").apply {
dependsOn(commonMain)
}
}
val nativeTest by lazy {
this.sourceSets.maybeCreate("nativeTest").apply {
dependsOn(commonTest)
}
}
val unixMain = this.sourceSets.maybeCreate("unixMain") val unixMain by lazy {
val unixTest = this.sourceSets.maybeCreate("unixTest") this.sourceSets.maybeCreate("unixMain").apply {
dependsOn(nativeMain)
}
}
val unixTest by lazy {
this.sourceSets.maybeCreate("unixTest").apply {
dependsOn(nativeTest)
}
}
val darwinMain = this.sourceSets.maybeCreate("darwinMain") val darwinMain by lazy {
val darwinTest = this.sourceSets.maybeCreate("darwinTest") this.sourceSets.maybeCreate("darwinMain").apply {
dependsOn(unixMain)
}
}
val darwinTest by lazy {
this.sourceSets.maybeCreate("darwinTest").apply {
dependsOn(unixTest)
}
}
presets.filter { it.name in MAC_TARGETS }.forEach { preset -> presets.filter { it.name in MAC_TARGETS }.forEach { preset ->
addNativeTarget(preset).run { addNativeTarget(preset).run {
@ -293,24 +353,6 @@ fun KotlinMultiplatformExtension.configureNativeTargetsHierarchical(
} }
} }
} }
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)
} }
private fun KotlinNativeTarget.findOrCreateTest(buildType: NativeBuildType, configure: TestExecutable.() -> Unit) = private fun KotlinNativeTarget.findOrCreateTest(buildType: NativeBuildType, configure: TestExecutable.() -> Unit) =

View File

@ -29,14 +29,21 @@ abstract class AbstractTest {
lateinit var propertiesFile: File lateinit var propertiesFile: File
fun gradleRunner(): GradleRunner { @OptIn(ExperimentalStdlibApi::class)
println(PluginUnderTestMetadataReading.readImplementationClasspath()) fun runGradle(vararg arguments: String) {
return GradleRunner.create() System.gc()
GradleRunner.create()
.withProjectDir(tempDir) .withProjectDir(tempDir)
.withPluginClasspath() .withPluginClasspath()
.withGradleVersion("7.2") .withGradleVersion("7.2")
.forwardOutput() .forwardOutput()
.withEnvironment(System.getenv()) .withEnvironment(System.getenv())
.withArguments(buildList {
addAll(arguments)
add("-Pkotlin.compiler.execution.strategy=in-process")
add("-Dorg.gradle.jvmargs=-Xmx256m -Dfile.encoding=UTF-8")
})
.build()
} }
@BeforeEach @BeforeEach

View File

@ -88,9 +88,7 @@ class TestBuildPlugin : AbstractTest() {
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle(":buildPlugin", "--stacktrace", "--info")
.withArguments(":buildPlugin", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -174,9 +172,7 @@ class TestBuildPlugin : AbstractTest() {
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle(":buildPlugin", "--stacktrace", "--info")
.withArguments(":buildPlugin", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -242,9 +238,7 @@ class TestBuildPlugin : AbstractTest() {
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle(":buildPlugin", "--stacktrace", "--info")
.withArguments(":buildPlugin", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -311,9 +305,7 @@ class TestBuildPlugin : AbstractTest() {
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle(":buildPlugin", "dependencies", "--stacktrace", "--info")
.withArguments(":buildPlugin", "dependencies", "--stacktrace", "--info")
.build()
checkOutput() checkOutput()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -334,9 +326,7 @@ class TestBuildPlugin : AbstractTest() {
} }
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle("buildPlugin", "dependencies", "--stacktrace", "--info")
.withArguments("buildPlugin", "dependencies", "--stacktrace", "--info")
.build()
checkOutput() checkOutput()
} }
@ -349,9 +339,7 @@ class TestBuildPlugin : AbstractTest() {
} }
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle("buildPlugin", "dependencies", "--stacktrace", "--info")
.withArguments("buildPlugin", "dependencies", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -372,9 +360,7 @@ class TestBuildPlugin : AbstractTest() {
} }
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle("buildPlugin", "dependencies", "--stacktrace", "--info")
.withArguments("buildPlugin", "dependencies", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -397,9 +383,7 @@ class TestBuildPlugin : AbstractTest() {
} }
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle("buildPlugin", "dependencies", "--stacktrace", "--info")
.withArguments("buildPlugin", "dependencies", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
@ -423,9 +407,7 @@ class TestBuildPlugin : AbstractTest() {
} }
""".trimIndent() """.trimIndent()
) )
gradleRunner() runGradle("buildPlugin", "dependencies", "--stacktrace", "--info")
.withArguments("buildPlugin", "dependencies", "--stacktrace", "--info")
.build()
ZipFile(findJar()).use { zipFile -> ZipFile(findJar()).use { zipFile ->
assertNotNull(zipFile.getEntry("cn/hutool/core/annotation/Alias.class")) assertNotNull(zipFile.getEntry("cn/hutool/core/annotation/Alias.class"))

View File

@ -15,8 +15,6 @@ class TestPluginApply : AbstractTest() {
@Test @Test
fun `can apply plugin`() { fun `can apply plugin`() {
gradleRunner() runGradle("clean", "--stacktrace")
.withArguments("clean", "--stacktrace")
.build()
} }
} }

View File

@ -55,7 +55,7 @@ kotlin {
} }
} }
val jvmBaseMain by getting { findByName("jvmBaseMain")?.apply {
dependencies { dependencies {
api(`kotlinx-coroutines-jdk8`) // use -jvm modules for this magic target 'jvmBase' api(`kotlinx-coroutines-jdk8`) // use -jvm modules for this magic target 'jvmBase'
implementation(`jetbrains-annotations`) implementation(`jetbrains-annotations`)
@ -64,34 +64,32 @@ kotlin {
} }
} }
if (isAndroidSDKAvailable) { findByName("androidMain")?.apply {
val androidMain by getting { dependsOn(commonMain)
dependsOn(commonMain) dependencies {
dependencies { compileOnly(`android-runtime`)
compileOnly(`android-runtime`)
// api(`ktor-client-android`) // api(`ktor-client-android`)
}
} }
} }
val jvmMain by getting { findByName("jvmMain")?.apply {
} }
val jvmTest by getting { findByName("jvmTest")?.apply {
dependencies { dependencies {
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
} }
} }
val nativeMain by getting { findByName("nativeMain")?.apply {
dependencies { dependencies {
} }
} }
} }
} }
if (isAndroidSDKAvailable) { if (tasks.findByName("androidMainClasses") != null) {
tasks.register("checkAndroidApiLevel") { tasks.register("checkAndroidApiLevel") {
doFirst { doFirst {
analyzes.AndroidApiLevelCheck.check( analyzes.AndroidApiLevelCheck.check(
@ -107,4 +105,4 @@ if (isAndroidSDKAvailable) {
} }
configureMppPublishing() configureMppPublishing()
configureBinaryValidators("jvm", "android") configureBinaryValidators(setOf("jvm", "android").filterTargets())

View File

@ -12,7 +12,6 @@ package net.mamoe.mirai.message.data
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
import net.mamoe.mirai.Mirai import net.mamoe.mirai.Mirai
import net.mamoe.mirai.contact.FileSupported import net.mamoe.mirai.contact.FileSupported
import net.mamoe.mirai.contact.file.AbsoluteFile import net.mamoe.mirai.contact.file.AbsoluteFile
@ -42,7 +41,6 @@ import net.mamoe.mirai.utils.safeCast
@Serializable(FileMessage.Serializer::class) @Serializable(FileMessage.Serializer::class)
@SerialName(FileMessage.SERIAL_NAME) @SerialName(FileMessage.SERIAL_NAME)
@NotStableForInheritance @NotStableForInheritance
@JvmBlockingBridge
public actual interface FileMessage : MessageContent, ConstrainSingle, CodableMessage { public actual interface FileMessage : MessageContent, ConstrainSingle, CodableMessage {
/** /**
* 服务器需要的某种 ID. * 服务器需要的某种 ID.

View File

@ -47,31 +47,31 @@ kotlin {
} }
} }
val jvmBaseMain by getting { findByName("jvmBaseMain")?.apply {
dependencies { dependencies {
implementation(`jetbrains-annotations`) implementation(`jetbrains-annotations`)
} }
} }
if (isAndroidSDKAvailable) { findByName("androidMain")?.apply {
val androidMain by getting { //
// dependencies {
dependencies { compileOnly(`android-runtime`)
compileOnly(`android-runtime`)
// api1(`ktor-client-android`) // api1(`ktor-client-android`)
}
} }
} }
val jvmMain by getting findByName("jvmMain")?.apply {
val jvmTest by getting { }
findByName("jvmTest")?.apply {
dependencies { dependencies {
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
} }
} }
val nativeMain by getting { findByName("nativeMain")?.apply {
dependencies { dependencies {
// implementation("com.soywiz.korlibs.krypto:krypto:2.4.12") // ':mirai-core-utils:compileNativeMainKotlinMetadata' fails because compiler cannot find reference // implementation("com.soywiz.korlibs.krypto:krypto:2.4.12") // ':mirai-core-utils:compileNativeMainKotlinMetadata' fails because compiler cannot find reference
} }
@ -79,7 +79,7 @@ kotlin {
} }
} }
if (isAndroidSDKAvailable) { if (tasks.findByName("androidMainClasses") != null) {
tasks.register("checkAndroidApiLevel") { tasks.register("checkAndroidApiLevel") {
doFirst { doFirst {
analyzes.AndroidApiLevelCheck.check( analyzes.AndroidApiLevelCheck.check(

View File

@ -55,7 +55,7 @@ kotlin {
} }
} }
val jvmBaseMain by getting { findByName("jvmBaseMain")?.apply {
dependencies { dependencies {
implementation(bouncycastle) implementation(bouncycastle)
implementation(`log4j-api`) implementation(`log4j-api`)
@ -65,45 +65,43 @@ kotlin {
} }
} }
val jvmBaseTest by getting { findByName("jvmBaseTest")?.apply {
dependencies { dependencies {
implementation(`kotlinx-coroutines-debug`) implementation(`kotlinx-coroutines-debug`)
} }
} }
if (isAndroidSDKAvailable) { findByName("androidMain")?.apply {
val androidMain by getting { dependsOn(commonMain)
dependsOn(commonMain) dependencies {
dependencies { compileOnly(`android-runtime`)
compileOnly(`android-runtime`)
}
} }
val androidTest by getting { }
dependencies { findByName("androidTest")?.apply {
implementation(kotlin("test", Versions.kotlinCompiler)) dependencies {
implementation(kotlin("test-junit5", Versions.kotlinCompiler)) implementation(kotlin("test", Versions.kotlinCompiler))
implementation(kotlin("test-annotations-common")) implementation(kotlin("test-junit5", Versions.kotlinCompiler))
implementation(kotlin("test-common")) implementation(kotlin("test-annotations-common"))
//implementation("org.bouncycastle:bcprov-jdk15on:1.64") implementation(kotlin("test-common"))
} //implementation("org.bouncycastle:bcprov-jdk15on:1.64")
} }
} }
val jvmMain by getting { findByName("jvmMain")?.apply {
dependencies { dependencies {
//implementation("org.bouncycastle:bcprov-jdk15on:1.64") //implementation("org.bouncycastle:bcprov-jdk15on:1.64")
// api(kotlinx("coroutines-debug", Versions.coroutines)) // api(kotlinx("coroutines-debug", Versions.coroutines))
} }
} }
val jvmTest by getting { findByName("jvmTest")?.apply {
dependencies { dependencies {
api(`kotlinx-coroutines-debug`) api(`kotlinx-coroutines-debug`)
// implementation("net.mamoe:mirai-login-solver-selenium:1.0-dev-14") // implementation("net.mamoe:mirai-login-solver-selenium:1.0-dev-14")
} }
} }
val nativeMain by getting { findByName("nativeMain")?.apply {
dependencies { dependencies {
} }
} }
@ -151,7 +149,7 @@ kotlin {
} }
} }
val darwinMain by getting { findByName("darwinMain")?.apply {
dependencies { dependencies {
implementation(`ktor-client-darwin`) implementation(`ktor-client-darwin`)
} }
@ -188,7 +186,7 @@ afterEvaluate {
} }
} }
if (isAndroidSDKAvailable) { if (tasks.findByName("androidMainClasses") != null) {
tasks.register("checkAndroidApiLevel") { tasks.register("checkAndroidApiLevel") {
doFirst { doFirst {
analyzes.AndroidApiLevelCheck.check( analyzes.AndroidApiLevelCheck.check(
@ -204,4 +202,4 @@ if (isAndroidSDKAvailable) {
} }
configureMppPublishing() configureMppPublishing()
configureBinaryValidators("jvm", "android") configureBinaryValidators(setOf("jvm", "android").filterTargets())

View File

@ -9,6 +9,7 @@
package net.mamoe.mirai.internal.message.data package net.mamoe.mirai.internal.message.data
import net.mamoe.mirai.internal.test.AbstractTest
import net.mamoe.mirai.message.data.* import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.safeCast import net.mamoe.mirai.utils.safeCast
import kotlin.test.Test import kotlin.test.Test
@ -26,7 +27,7 @@ internal class TestConstrainSingleMessage : ConstrainSingle, Any() {
get() = Key get() = Key
} }
internal class ContentEqualsTest { internal class ContentEqualsTest: AbstractTest() {
@Test @Test
fun testContentEquals() { fun testContentEquals() {

View File

@ -15,7 +15,6 @@ import net.mamoe.mirai.utils.md5
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
import openssl.* import openssl.*
import platform.posix.errno import platform.posix.errno
import platform.posix.free
private const val curveId = NID_X9_62_prime256v1 private const val curveId = NID_X9_62_prime256v1
@ -27,13 +26,26 @@ private val convForm by lazy { EC_GROUP_get_point_conversion_form(group) }
// shared, not freed! // shared, not freed!
private val bnCtx by lazy { BN_CTX_new() } private val bnCtx by lazy { BN_CTX_new() }
// ====ATTENTION====
// Do not use [platform.posix.free] easily
// For anything allocated by OpenSSL, <type>_free or CRYPTO_free
// (the underlying of OPENSSL_free macro) should be called.
// It's more than dangerous to assume OpenSSL uses the same memory manager as general posix functions,
// easily causing memory leaking (usually on *nix) or crash (usually on Windows)
internal actual interface ECDHPublicKey : OpenSSLKey { internal actual interface ECDHPublicKey : OpenSSLKey {
val encoded: ByteArray val encoded: ByteArray
/**
* @return It is the caller's responsibility to free this memory with a subsequent call to [EC_POINT_free]
*/
fun toPoint(): CPointer<EC_POINT> fun toPoint(): CPointer<EC_POINT>
} }
internal actual interface ECDHPrivateKey : OpenSSLKey { internal actual interface ECDHPrivateKey : OpenSSLKey {
/**
* @return It is the caller's responsibility to free this memory with a subsequent call to [BN_free]
*/
fun toBignum(): CPointer<BIGNUM> fun toBignum(): CPointer<BIGNUM>
} }
@ -52,16 +64,14 @@ internal class OpenSslPrivateKey(
companion object { companion object {
fun fromKey(key: CPointer<EC_KEY>): OpenSslPrivateKey { fun fromKey(key: CPointer<EC_KEY>): OpenSslPrivateKey {
// Note that the private key (bignum) is associated with the key
// We can't free it, or it'll crash when EC_KEY_free
val bn = EC_KEY_get0_private_key(key) ?: error("Failed EC_KEY_get0_private_key") val bn = EC_KEY_get0_private_key(key) ?: error("Failed EC_KEY_get0_private_key")
val ptr = BN_bn2hex(bn) ?: error("Failed EC_POINT_bn2point")
val hex = try { val hex = try {
val ptr = BN_bn2hex(bn) ?: error("Failed EC_POINT_bn2point") ptr.toKString()
try {
ptr.toKString()
} finally {
free(ptr)
}
} finally { } finally {
BN_free(bn) CRYPTO_free(ptr, "OpenSslPrivateKey.Companion.fromKey(key: CPointer<EC_KEY>)", -1)
} }
return OpenSslPrivateKey(hex) return OpenSslPrivateKey(hex)
} }
@ -115,7 +125,7 @@ private fun CPointer<EC_POINT>.toKtHex(): String {
return try { return try {
ptr.toKString() ptr.toKString()
} finally { } finally {
free(ptr) CRYPTO_free(ptr, "CPointer<EC_POINT>.toKtHex()", -1)
} }
} }
@ -159,15 +169,13 @@ internal actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) {
actual fun generateKeyPair(initialPublicKey: ECDHPublicKey): ECDHKeyPair { actual fun generateKeyPair(initialPublicKey: ECDHPublicKey): ECDHKeyPair {
val key: CPointer<EC_KEY> = EC_KEY_new_by_curve_name(curveId) val key: CPointer<EC_KEY> = EC_KEY_new_by_curve_name(curveId)
?: throw IllegalStateException("Failed to create key curve, $errno") ?: throw IllegalStateException("Failed to create key curve, $errno")
if (1 != EC_KEY_generate_key(key)) {
throw IllegalStateException("Failed to generate key, $errno")
}
try { try {
if (1 != EC_KEY_generate_key(key)) {
throw IllegalStateException("Failed to generate key, $errno")
}
return ECDHKeyPairImpl.fromKey(key, initialPublicKey) return ECDHKeyPairImpl.fromKey(key, initialPublicKey)
} finally { } finally {
free(key) // TODO: THIS MAY CAUSE MEMORY LEAK. But EC_KEY_free() will terminate the process for unknown reason. EC_KEY_free(key)
} }
} }