Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/martmists-gh/kpy-plugin
Gradle/KSP plugin to compile Kotlin/Native to Python C API
https://github.com/martmists-gh/kpy-plugin
gradle-plugin kotlin kotlin-multiplatform kotlin-multiplatform-library kotlin-native python-3 python-extension python3
Last synced: 2 months ago
JSON representation
Gradle/KSP plugin to compile Kotlin/Native to Python C API
- Host: GitHub
- URL: https://github.com/martmists-gh/kpy-plugin
- Owner: Martmists-GH
- License: bsd-4-clause
- Created: 2022-04-19T22:42:53.000Z (over 2 years ago)
- Default Branch: master
- Last Pushed: 2024-06-02T01:12:28.000Z (7 months ago)
- Last Synced: 2024-06-02T02:44:28.345Z (7 months ago)
- Topics: gradle-plugin, kotlin, kotlin-multiplatform, kotlin-multiplatform-library, kotlin-native, python-3, python-extension, python3
- Language: Kotlin
- Homepage:
- Size: 327 KB
- Stars: 27
- Watchers: 3
- Forks: 3
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# KPy Plugin
The KPy gradle plugin allows you to write Kotlin/Native code and use it from python.
> Note: Modules built with KPy still require XCode when building on macOS, this is a Kotlin/Native limitation.
A huge thank you to the [indygreg/python-build-standalone](https://github.com/indygreg/python-build-standalone/) project for providing prebuilt python binaries to build against. This project would be impossible to maintain without it.
## Features
### Implemented
- Export Kotlin/Native functions and classes without having to touch the Python API directly
- Convert between Kotlin and Python types with .toPython() and .toKotlin()
- Conversions handled mostly automatically
- Class inheritance mapped to python
- Generate Python stubs
- Catch Kotlin exceptions and raise them as Python exceptions## Setup
Change your gradle version to 7.5 (nightly builds only as of writing)
Enable the plugin in your build.gradle.kts file:```kotlin
plugins {
kotlin("multiplatform") version "2.0.0"
id("com.martmists.kpy.kpy-plugin") version "1.0.1"
}kotlin {
val hostOs = System.getProperty("os.name")
val isMingwX64 = hostOs.startsWith("Windows")
val isArm64 = System.getProperty("os.arch") == "aarch64"
// You can rename the target from `native` to something else,
// but make sure to also change setup.py to match this change!
val nativeTarget = when {
hostOs == "Mac OS X" && !isArm64 -> macosX64("native")
hostOs == "Linux" && !isArm64 -> linuxX64("native")
hostOs == "Mac OS X" && isArm64 -> macosArm64("native")
hostOs == "Linux" && isArm64 -> linuxArm64("native")
isMingwX64 -> mingwX64("native")
else -> throw GradleException("Host OS is not supported in Kotlin/Native.")
}
}
```Use the following setup.py template (note: may be outdated, see kpy-sample for an up-to-date example):
```python
from os.path import dirname, abspath
from platform import system
from setuptools import setup, Extension, find_packages
from subprocess import Popen, PIPEosname = system()
debug = False # Debug currently has some issues
dir_name = dirname(abspath(__file__))if osname == "Linux" or osname == "Darwin":
gradle_bin = "./gradlew"
else:
gradle_bin = ".\\gradlew.bat"# Build the project
proc = Popen([gradle_bin, "build"])
if proc.wait() != 0:
raise Exception("Build failed")# Fetch configuration from gradle task
proc = Popen([gradle_bin, "setupMetadata"], stdout=PIPE)
if proc.wait() != 0:
raise Exception("Failed to fetch metadata")
output = proc.stdout.read().decode()
real_output = output.split("===METADATA START===")[1].split("===METADATA END===")[0]exec(real_output, globals(), locals())
# Types of variables from gradle metadata
has_stubs: bool
project_name: str
module_name: str
project_version: str
build_dir: str
root_dir: str
target: strprint("name: " + project_name)
print("version: " + project_version)def snake_case(name):
return name.replace("-", "_").lower()def extensions():
folder = "debugStatic" if debug else "releaseStatic"
prefix = "_" if has_stubs else ""
native = Extension(prefix + module_name,
sources=[f'{build_dir}/generated/ksp/{target}/{target}Main/resources/entrypoint.cpp'],
include_dirs=[f"{build_dir}/bin/{target}/{folder}/"],
library_dirs=[f"{build_dir}/bin/{target}/{folder}/"],
libraries=[project_name])return [native]
with open("README.md", "r") as fh:
long_description = fh.read()attrs = {}
if has_stubs:
stub_root = f'{build_dir}/generated/ksp/{target}/{target}Main/resources'
attrs["packages"] = find_packages(where=stub_root)
attrs["package_dir"] = {"": stub_root}
else:
attrs["packages"] = []setup(
name=module_name,
version=project_version,
description=long_description,
ext_modules=extensions(),
**attrs
)```
## Configuration
To configure the plugin, you can use the `kpy` configuration.
```kotlin
kpy {
// Pass properties to setup.py, the exec() command will pass them to the context
// Note: the second parameter is an expression, and must be valid python.
metadata("my_key", "'my' + 'value'") // in setup.py you can now use my_key and it evaluates to 'myvalue'// Specify the python version to build against.
// Currently supported: [3.9, 3.10]
pyVersion.set(PythonVersion.Py310)// Generate python stubs for the native sources
// These are stored to `build/generated/ksp//Main/resources/`
// Note: these will be overwritten every time you build the project
generateStubs.set(true)
}
```