Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] MinGW x64 port #574

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
39 changes: 31 additions & 8 deletions samples/SkiaMultiplatformSample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ buildscript {

dependencies {
// __KOTLIN_COMPOSE_VERSION__
classpath(kotlin("gradle-plugin", version = "1.6.10"))
classpath(kotlin("gradle-plugin", version = "1.7.10"))
}
}

plugins {
kotlin("multiplatform") version "1.6.10"
kotlin("multiplatform") version "1.7.10"
id("org.jetbrains.gradle.apple.applePlugin") version "222.849-0.15.1"
}

val coroutinesVersion = "1.5.2"
val coroutinesVersion = "1.6.4"

repositories {
mavenLocal()
Expand Down Expand Up @@ -61,18 +61,18 @@ val unzipTask = tasks.register("unzipWasm", Copy::class) {
}

kotlin {
val targets = mutableListOf<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>()
val macOSTargets = mutableListOf<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget>()

if (hostOs == "macos") {
val nativeHostTarget = when (host) {
"macos-x64" -> macosX64()
"macos-arm64" -> macosArm64()
else -> throw GradleException("Host OS is not supported yet")
}
targets.add(nativeHostTarget)
macOSTargets.add(nativeHostTarget)

targets.add(iosX64())
targets.add(iosArm64())
macOSTargets.add(iosX64())
macOSTargets.add(iosArm64())

ios {
binaries {
Expand All @@ -99,7 +99,7 @@ kotlin {
binaries.executable()
}

targets.forEach {
macOSTargets.forEach {
it.apply {
binaries {
executable {
Expand All @@ -114,6 +114,19 @@ kotlin {
}
}

if (hostOs == "windows") {
mingwX64 {
binaries {
executable {
entryPoint = "org.jetbrains.skiko.sample.main"
freeCompilerArgs += listOf(
"-linker-option", "-lopengl32"
)
}
}
}
}

sourceSets {
val commonMain by getting {
dependencies {
Expand Down Expand Up @@ -172,6 +185,16 @@ kotlin {
val iosArm64Main by getting {
dependsOn(iosMain)
}
} else if (hostOs == "windows") {
val mingwMain by creating {
dependsOn(nativeMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
}
}
val mingwX64Main by getting {
dependsOn(mingwMain)
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions samples/SkiaMultiplatformSample/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
kotlin.code.style=official
kotlin.mpp.enableGranularSourceSetsMetadata=true
kotlin.native.enableDependencyPropagation=false
kotlin.native.binary.memoryModel=experimental

org.gradle.jvmargs=-Xmx3G -XX:MaxMetaspaceSize=512m
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
package org.jetbrains.skiko.sample

import kotlinx.cinterop.*
import org.jetbrains.skiko.GenericSkikoView
import org.jetbrains.skiko.SkiaLayer
import platform.windows.*

fun makeApp(skiaLayer: SkiaLayer) = Clocks(skiaLayer)

lateinit var skiaLayer: SkiaLayer

fun wndProc(hwnd: HWND?, msg: UINT, wParam: WPARAM, lParam: LPARAM): LRESULT {
if(msg == WM_DESTROY.toUInt()) {
PostQuitMessage(0)
return 0
}
return skiaLayer.windowProc(hwnd, msg, wParam, lParam)
}

fun main() {

skiaLayer = SkiaLayer()

memScoped {
val lpszClassName = "SkiaMultiplatformSample"

val wc = alloc<WNDCLASSEX>()
wc.cbSize = sizeOf<WNDCLASSEX>().toUInt()
wc.lpfnWndProc = staticCFunction(::wndProc)
wc.style = (CS_HREDRAW or CS_VREDRAW or CS_OWNDC).toUInt()
wc.cbClsExtra = 0
wc.cbWndExtra = 0
wc.hInstance = null
wc.hIcon = null
wc.hCursor = (LoadCursor!!)(null, IDC_ARROW)
wc.lpszMenuName = null
wc.lpszClassName = lpszClassName.wcstr.ptr
wc.hIconSm = null

if (RegisterClassEx!!(wc.ptr) == 0u.toUShort()) {
println("could not register")
return
}

val hwnd = CreateWindowExA(
0, lpszClassName, "SkikoNative",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
640, 480,
null, null, null, null
)!!
skiaLayer.attachTo(hwnd)
ShowWindow(hwnd, SW_SHOW)
}

skiaLayer.skikoView = GenericSkikoView(skiaLayer, makeApp(skiaLayer))

memScoped {
val msg = alloc<MSG>()
msg.message = 0u
while (GetMessage!!(msg.ptr, null, 0u, 0u) > 0) {
if(msg.message == WM_QUIT.toUInt()) {
break
}
TranslateMessage(msg.ptr)
DispatchMessageA(msg.ptr)
}
}

skiaLayer.detach()
}
129 changes: 97 additions & 32 deletions skiko/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
import de.undercouch.gradle.tasks.download.Download
import org.gradle.crypto.checksum.Checksum
import org.gradle.api.tasks.testing.AbstractTestTask
import org.jetbrains.compose.internal.publishing.MavenCentralProperties
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTool
import org.gradle.api.tasks.testing.logging.TestExceptionFormat

plugins {
kotlin("multiplatform") version "1.6.10"
id("org.jetbrains.dokka") version "1.6.10"
kotlin("multiplatform") version "1.7.10"
id("org.jetbrains.dokka") version "1.7.10"
`maven-publish`
signing
id("org.gradle.crypto.checksum") version "1.1.0"
id("de.undercouch.download") version "4.1.2"
}

val coroutinesVersion = "1.5.2"
val coroutinesVersion = "1.6.4"

fun targetSuffix(os: OS, arch: Arch): String {
return "${os.id}_${arch.id}"
Expand Down Expand Up @@ -189,6 +189,17 @@ fun compileNativeBridgesTask(os: OS, arch: Arch, isArm64Simulator: Boolean): Tas
*skiaPreprocessorFlags(OS.Linux)
))
}
OS.MinGW -> {
flags.set(listOf(
*buildType.clangFlags,
"-fno-rtti",
"-fno-exceptions",
"-fvisibility=hidden",
"-fvisibility-inlines-hidden",
"-D_GLIBCXX_USE_CXX11_ABI=0",
*skiaPreprocessorFlags(OS.Linux)
))
}
else -> throw GradleException("$os not yet supported")
}

Expand Down Expand Up @@ -258,6 +269,7 @@ kotlin {
configureNativeTarget(OS.MacOS, Arch.X64, macosX64())
configureNativeTarget(OS.MacOS, Arch.Arm64, macosArm64())
configureNativeTarget(OS.Linux, Arch.X64, linuxX64())
configureNativeTarget(OS.MinGW, Arch.X64, mingwX64())
configureNativeTarget(OS.IOS, Arch.Arm64, iosArm64())
configureNativeTarget(OS.IOS, Arch.X64, iosX64())
configureNativeTarget(OS.IOS, Arch.Arm64, iosSimulatorArm64())
Expand Down Expand Up @@ -368,6 +380,21 @@ kotlin {
val linuxX64Test by getting {
dependsOn(linuxTest)
}
val mingwMain by creating {
dependsOn(nativeJsMain)
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutinesVersion")
}
}
val mingwTest by creating {
dependsOn(nativeTest)
}
val mingwX64Main by getting {
dependsOn(mingwMain)
}
val mingwX64Test by getting {
dependsOn(mingwTest)
}
val darwinMain by creating {
dependsOn(nativeMain)
}
Expand Down Expand Up @@ -434,7 +461,7 @@ fun configureNativeTarget(os: OS, arch: Arch, target: KotlinNativeTarget) {
val skiaDir = unpackedSkia.absolutePath

val bridgesLibrary = "$buildDir/nativeBridges/static/$targetString/skiko-native-bridges-$targetString.a"
val allLibraries = skiaStaticLibraries(skiaDir, targetString) + bridgesLibrary
val allLibraries = skiaStaticLibraries(os, skiaDir, targetString) + bridgesLibrary

target.compilations.all {
val skiaBinDir = "$skiaDir/out/${buildType.id}-$targetString"
Expand All @@ -459,6 +486,9 @@ fun configureNativeTarget(os: OS, arch: Arch, target: KotlinNativeTarget) {
"-linker-option", "$skiaBinDir/libskunicode.a",
"-linker-option", "$skiaBinDir/libskia.a"
)
OS.MinGW -> mutableListOf(
"-linker-option", "-lopengl32"
)
else -> mutableListOf()
}
if (skiko.includeTestHelpers) {
Expand Down Expand Up @@ -489,7 +519,7 @@ fun configureNativeTarget(os: OS, arch: Arch, target: KotlinNativeTarget) {
val staticLib = "$outDir/skiko-native-bridges-$targetString.a"
workingDir = File(outDir)
when (os) {
OS.Linux -> {
OS.Linux, OS.MinGW -> {
executable = "ar"
argumentProviders.add { listOf("-crs", staticLib) }
}
Expand All @@ -504,7 +534,9 @@ fun configureNativeTarget(os: OS, arch: Arch, target: KotlinNativeTarget) {
outputs.dir(outDir)
}
target.compilations.all {
compileKotlinTask.dependsOn(linkTask)
compileKotlinTaskProvider.configure {
dependsOn(linkTask)
}
}
}

Expand Down Expand Up @@ -586,30 +618,53 @@ fun skiaPreprocessorFlags(os: OS): Array<String> {
return (base + perOs).toTypedArray()
}

fun skiaStaticLibraries(skiaDir: String, targetString: String): List<String> {
fun skiaStaticLibraries(os: OS, skiaDir: String, targetString: String): List<String> {
val skiaBinSubdir = "$skiaDir/out/${buildType.id}-$targetString"
return listOf(
"libskresources.a",
"libparticles.a",
"libskparagraph.a",
"libskia.a",
"libicu.a",
"libskottie.a",
"libsvg.a",
"libpng.a",
"libfreetype2.a",
"libwebp_sse41.a",
"libsksg.a",
"libskunicode.a",
"libwebp.a",
"libdng_sdk.a",
"libpiex.a",
"libharfbuzz.a",
"libexpat.a",
"libzlib.a",
"libjpeg.a",
"libskshaper.a"
).map{
return when(os) {
OS.MinGW -> listOf(
"libexpat.a",
"libfreetype2.a",
"libharfbuzz.a",
"libicu.a",
"libjpeg.a",
"libparticles.a",
"libpng.a",
"libskcms.a",
"libskia.a",
"libskottie.a",
"libskparagraph.a",
"libskresources.a",
"libsksg.a",
"libskshaper.a",
"libskunicode.a",
"libsvg.a",
"libwebp.a",
"libwebp_sse41.a",
"libzlib.a",
)
else -> listOf(
"libskresources.a",
"libparticles.a",
"libskparagraph.a",
"libskia.a",
"libicu.a",
"libskottie.a",
"libsvg.a",
"libpng.a",
"libfreetype2.a",
"libwebp_sse41.a",
"libsksg.a",
"libskunicode.a",
"libwebp.a",
"libdng_sdk.a",
"libpiex.a",
"libharfbuzz.a",
"libexpat.a",
"libzlib.a",
"libjpeg.a",
"libskshaper.a"
)
}.map {
"$skiaBinSubdir/$it"
}
}
Expand Down Expand Up @@ -864,7 +919,7 @@ fun createCompileJvmBindingsTask(
"-fPIC"
)
}
OS.Wasm, OS.IOS -> error("Should not reach here")
OS.Wasm, OS.IOS, OS.MinGW -> error("Should not reach here")
}

flags.set(
Expand Down Expand Up @@ -967,6 +1022,16 @@ fun createLinkJvmBindings(
if (buildType == SkiaBuildType.DEBUG) add("dxgi.lib")
}.toTypedArray()
}
OS.MinGW -> {
osFlags = arrayOf(
"-shared",
"-static-libstdc++",
"-static-libgcc",
"-lGL",
"-lfontconfig",
"-lopengl32"
)
}
OS.Android -> {
osFlags = arrayOf(
"-shared",
Expand Down Expand Up @@ -1023,7 +1088,7 @@ fun KotlinTarget.generateVersion(
val compilation = compilations["main"] ?: error("Could not find 'main' compilation for target '$this'")
compilation.compileKotlinTaskProvider.configure {
dependsOn(generateVersionTask)
(this as AbstractCompile).source(generatedDir.get().asFile)
(this as KotlinCompileTool).source(generatedDir.get().asFile)
}
}

Expand Down
Loading