martmists
04/30/2022, 4:13 PMmartmists
04/30/2022, 4:14 PMimport org.jetbrains.kotlin.konan.target.KonanTarget
plugins {
kotlin("multiplatform")
`maven-publish`
id("com.github.gmazzo.buildconfig")
}
kotlin {
val targets = listOf(
// X64
linuxX64(),
mingwX64(),
macosX64(),
// Arm
linuxArm64(),
macosArm64(),
)
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val hostTarget = when {
hostOs == "Mac OS X" -> KonanTarget.MACOS_X64
hostOs == "Linux" -> KonanTarget.LINUX_X64
isMingwX64 -> KonanTarget.MINGW_X64
else -> error("Unsupported host OS: $hostOs")
}
sourceSets {
val nativeMain by creating {
}
val linuxX64Main by getting {
dependsOn(nativeMain)
}
val mingwX64Main by getting {
dependsOn(nativeMain)
}
val macosX64Main by getting {
dependsOn(nativeMain)
}
val linuxArm64Main by getting {
dependsOn(nativeMain)
}
val macosArm64Main by getting {
dependsOn(nativeMain)
}
}
targets.forEach {
it.apply {
val main by compilations.getting {
}
val python by main.cinterops.creating {
if (konanTarget != hostTarget && konanTarget == KonanTarget.MINGW_X64) {
defFile = project.file("src/nativeInterop/cinterop/python-github-MingwX64.def")
}
}
binaries {
staticLib {
binaryOptions["memoryModel"] = "experimental"
freeCompilerArgs += listOf("-Xgc=cms")
}
}
}
}
}
val pyVersion = findProperty("pythonVersion") as String? ?: "3.9"
version = "$version+$pyVersion"
buildConfig {
packageName.set("com.martmists.kpy.cfg")
buildConfigField("String", "VERSION", "\"${project.version}\"")
}
val generatePythonDef = tasks.create<Exec>("generatePythonDef") {
val minPyVersion = pyVersion
group = "interop"
description = "Generate Python.def file"
executable = "python3"
val cinteropDir = "${project.projectDir.absolutePath}/src/nativeInterop/cinterop"
val parts = minPyVersion.split(".").toMutableList()
while (parts.size < 4) {
parts.add("0")
}
val versionHex = parts.joinToString("") { it.toInt().toString(16) }
args(
"-c",
"""
import sysconfig
paths = sysconfig.get_paths()
template = '''
headers = Python.h
package = python
compilerOpts = -I"{INCLUDE_DIR}"
linkerOpts = -L"{LIB_DIR}" -l python3
---
struct KtPyObject {{
PyObject base;
void* ktObject;
}};
// Wrapper func for _PyUnicode_AsString macro
char* PyUnicode_AsString(PyObject* obj) {{
return _PyUnicode_AsString(obj);
}}
'''.strip()
with open('${cinteropDir.replace('\\', '/')}/python.def', 'w') as fp:
fp.write(template.format(
INCLUDE_DIR=paths['platinclude'],
LIB_DIR='/'.join(paths['platstdlib'].split('/')[:-1]),
MIN_VERSION_HEX='0x${versionHex}'
))
with open('${cinteropDir.replace('\\', '/')}/python-github-MingwX64.def', 'w') as fp:
fp.write(template.format(
INCLUDE_DIR="mingw64/include/python${pyVersion}",
LIB_DIR='/'.join(paths['platstdlib'].split('/')[:-1]),
MIN_VERSION_HEX='0x${versionHex}'
))
""".trim()
)
files(
"${cinteropDir.replace('\\', '/')}/python.def",
"${cinteropDir.replace('\\', '/')}/python-github-MingwX64.def",
)
}
for (target in listOf("LinuxX64", "MacosX64", "MingwX64", "LinuxArm64", "MacosArm64")) {
try {
tasks.getByName("cinteropPython${target}") {
dependsOn(generatePythonDef)
}
} catch (e: Exception) {
println("Skipping cinteropPython${target} as it's not available on this OS")
}
}
Project B (kpy-sample):
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
id("com.google.devtools.ksp")
kotlin("multiplatform")
}
repositories {
mavenCentral()
}
kotlin {
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val nativeTarget = when {
hostOs == "Mac OS X" -> macosX64()
hostOs == "Linux" -> linuxX64()
isMingwX64 -> mingwX64()
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
}
sourceSets {
val nativeMain by creating {
dependencies {
implementation(project(":kpy-library"))
}
kotlin.srcDir(buildDir.absolutePath + "/generated/ksp/native/nativeMain/kotlin")
}
targets.forEach {
if (it is KotlinNativeTarget) {
sourceSets.getByName("${it.name}Main") {
dependsOn(nativeMain)
}
}
}
}
nativeTarget.apply {
val main by compilations.getting {
}
binaries {
staticLib {
binaryOptions["memoryModel"] = "experimental"
freeCompilerArgs += listOf("-Xgc=cms")
}
}
}
}
val setupMetadata by tasks.creating {
actions.add {
println("""
|===METADATA START===
|project_name = "${project.name}"
|project_version = "${project.version}"
|build_dir = "${buildDir.absolutePath.replace('\\', '/')}"
|===METADATA END===
""".trimMargin())
}
}
ksp {
arg("projectName", project.name)
}
dependencies {
for (target in kotlin.targets) {
if (target is KotlinNativeTarget) {
add("ksp${target.name.capitalize()}", project(":kpy-processor"))
}
}
}
russhwolf
04/30/2022, 4:30 PMkotlin.mpp.enableCInteropCommonization=true
to your gradle.properties file. By default cinterop dependencies don't get commonized which means the IDE doesn't know how to read them from shared sources like nativeMain
.martmists
04/30/2022, 4:58 PMnapperley
05/01/2022, 2:01 AM