mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-19 11:32:18 +02:00
Add Rust build support
This commit is contained in:
parent
c198e8b376
commit
c5d1d3b31e
10
.gitignore
vendored
10
.gitignore
vendored
@ -47,3 +47,13 @@ crowdin.properties
|
|||||||
# Nix stuff
|
# Nix stuff
|
||||||
.direnv/
|
.direnv/
|
||||||
result
|
result
|
||||||
|
|
||||||
|
# VSCode
|
||||||
|
.vscode/
|
||||||
|
|
||||||
|
# Rust
|
||||||
|
debug/
|
||||||
|
target/
|
||||||
|
Cargo.lock
|
||||||
|
**/*.rs.bk
|
||||||
|
*.pdb
|
||||||
|
@ -101,12 +101,6 @@ android {
|
|||||||
kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get()
|
kotlinCompilerExtensionVersion = libs.versions.androidx.compose.compiler.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
//externalNativeBuild {
|
|
||||||
// cmake {
|
|
||||||
// path("src/main/cpp/CMakeLists.txt")
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
buildTypes {
|
buildTypes {
|
||||||
named("debug") {
|
named("debug") {
|
||||||
applicationIdSuffix = ".debug"
|
applicationIdSuffix = ".debug"
|
||||||
@ -152,11 +146,6 @@ android {
|
|||||||
initWith(getByName("release"))
|
initWith(getByName("release"))
|
||||||
signingConfig = signingConfigs.getByName("debug")
|
signingConfig = signingConfigs.getByName("debug")
|
||||||
matchingFallbacks += listOf("release")
|
matchingFallbacks += listOf("release")
|
||||||
|
|
||||||
ndk {
|
|
||||||
// For running FlorisBoard on the emulator
|
|
||||||
abiFilters += listOf("x86", "x86_64")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +203,8 @@ dependencies {
|
|||||||
implementation(libs.patrickgold.jetpref.datastore.ui)
|
implementation(libs.patrickgold.jetpref.datastore.ui)
|
||||||
implementation(libs.patrickgold.jetpref.material.ui)
|
implementation(libs.patrickgold.jetpref.material.ui)
|
||||||
|
|
||||||
|
|
||||||
implementation(project(":lib:kotlin"))
|
implementation(project(":lib:kotlin"))
|
||||||
|
implementation(project(":lib:native"))
|
||||||
|
|
||||||
testImplementation(libs.equalsverifier)
|
testImplementation(libs.equalsverifier)
|
||||||
testImplementation(libs.kotest.assertions.core)
|
testImplementation(libs.kotest.assertions.core)
|
||||||
|
@ -34,20 +34,17 @@ import dev.patrickgold.florisboard.ime.media.emoji.FlorisEmojiCompat
|
|||||||
import dev.patrickgold.florisboard.ime.nlp.NlpManager
|
import dev.patrickgold.florisboard.ime.nlp.NlpManager
|
||||||
import dev.patrickgold.florisboard.ime.text.gestures.GlideTypingManager
|
import dev.patrickgold.florisboard.ime.text.gestures.GlideTypingManager
|
||||||
import dev.patrickgold.florisboard.ime.theme.ThemeManager
|
import dev.patrickgold.florisboard.ime.theme.ThemeManager
|
||||||
import dev.patrickgold.florisboard.lib.NativeStr
|
|
||||||
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
import dev.patrickgold.florisboard.lib.cache.CacheManager
|
||||||
import dev.patrickgold.florisboard.lib.crashutility.CrashUtility
|
import dev.patrickgold.florisboard.lib.crashutility.CrashUtility
|
||||||
import dev.patrickgold.florisboard.lib.devtools.Flog
|
import dev.patrickgold.florisboard.lib.devtools.Flog
|
||||||
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
import dev.patrickgold.florisboard.lib.devtools.LogTopic
|
||||||
import dev.patrickgold.florisboard.lib.devtools.flogError
|
import dev.patrickgold.florisboard.lib.devtools.flogError
|
||||||
import dev.patrickgold.florisboard.lib.devtools.flogInfo
|
|
||||||
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
import dev.patrickgold.florisboard.lib.ext.ExtensionManager
|
||||||
import dev.patrickgold.florisboard.lib.io.AssetManager
|
import dev.patrickgold.florisboard.lib.io.AssetManager
|
||||||
import dev.patrickgold.florisboard.lib.io.deleteContentsRecursively
|
import dev.patrickgold.florisboard.lib.io.deleteContentsRecursively
|
||||||
import dev.patrickgold.florisboard.lib.io.subFile
|
|
||||||
import dev.patrickgold.florisboard.lib.toNativeStr
|
|
||||||
import dev.patrickgold.jetpref.datastore.JetPref
|
import dev.patrickgold.jetpref.datastore.JetPref
|
||||||
import org.florisboard.lib.kotlin.tryOrNull
|
import org.florisboard.lib.kotlin.tryOrNull
|
||||||
|
import org.florisboard.libnative.dummyAdd
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -59,13 +56,9 @@ private var FlorisApplicationReference = WeakReference<FlorisApplication?>(null)
|
|||||||
@Suppress("unused")
|
@Suppress("unused")
|
||||||
class FlorisApplication : Application() {
|
class FlorisApplication : Application() {
|
||||||
companion object {
|
companion object {
|
||||||
private const val ICU_DATA_ASSET_PATH = "icu4c/icudt73l.dat"
|
|
||||||
|
|
||||||
private external fun nativeInitICUData(path: NativeStr): Int
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
try {
|
try {
|
||||||
System.loadLibrary("florisboard-native")
|
System.loadLibrary("fl_native")
|
||||||
} catch (_: Exception) {
|
} catch (_: Exception) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,6 +92,7 @@ class FlorisApplication : Application() {
|
|||||||
)
|
)
|
||||||
CrashUtility.install(this)
|
CrashUtility.install(this)
|
||||||
FlorisEmojiCompat.init(this)
|
FlorisEmojiCompat.init(this)
|
||||||
|
flogError { "dummy result: ${dummyAdd(3,4)}" }
|
||||||
|
|
||||||
if (!UserManagerCompat.isUserUnlocked(this)) {
|
if (!UserManagerCompat.isUserUnlocked(this)) {
|
||||||
cacheDir?.deleteContentsRecursively()
|
cacheDir?.deleteContentsRecursively()
|
||||||
@ -115,7 +109,6 @@ class FlorisApplication : Application() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun init() {
|
fun init() {
|
||||||
initICU(this)
|
|
||||||
cacheDir?.deleteContentsRecursively()
|
cacheDir?.deleteContentsRecursively()
|
||||||
prefs.initializeBlocking(this)
|
prefs.initializeBlocking(this)
|
||||||
extensionManager.value.init()
|
extensionManager.value.init()
|
||||||
@ -123,28 +116,6 @@ class FlorisApplication : Application() {
|
|||||||
DictionaryManager.init(this)
|
DictionaryManager.init(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initICU(context: Context): Boolean {
|
|
||||||
try {
|
|
||||||
val androidAssetManager = context.assets ?: return false
|
|
||||||
val icuTmpDataFile = context.cacheDir.subFile("icudt.dat")
|
|
||||||
icuTmpDataFile.outputStream().use { os ->
|
|
||||||
androidAssetManager.open(ICU_DATA_ASSET_PATH).use { it.copyTo(os) }
|
|
||||||
}
|
|
||||||
val status = nativeInitICUData(icuTmpDataFile.absolutePath.toNativeStr())
|
|
||||||
icuTmpDataFile.delete()
|
|
||||||
return if (status != 0) {
|
|
||||||
flogError { "Native ICU data initializing failed with error code $status!" }
|
|
||||||
false
|
|
||||||
} else {
|
|
||||||
flogInfo { "Successfully loaded ICU data!" }
|
|
||||||
true
|
|
||||||
}
|
|
||||||
} catch (e: Exception) {
|
|
||||||
flogError { e.toString() }
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private inner class BootComplete : BroadcastReceiver() {
|
private inner class BootComplete : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context?, intent: Intent?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
if (intent == null) return
|
if (intent == null) return
|
||||||
|
71
lib/native/build.gradle.kts
Normal file
71
lib/native/build.gradle.kts
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
plugins {
|
||||||
|
alias(libs.plugins.agp.library)
|
||||||
|
alias(libs.plugins.kotlin.android)
|
||||||
|
}
|
||||||
|
|
||||||
|
val projectMinSdk: String by project
|
||||||
|
val projectCompileSdk: String by project
|
||||||
|
val projectNdkVersion: String by project
|
||||||
|
|
||||||
|
android {
|
||||||
|
namespace = "org.florisboard.libnative"
|
||||||
|
compileSdk = projectCompileSdk.toInt()
|
||||||
|
ndkVersion = projectNdkVersion
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
minSdk = projectMinSdk.toInt()
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
targets("fl_native")
|
||||||
|
arguments(
|
||||||
|
"-DCMAKE_ANDROID_API=" + minSdk.toString(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ndk {
|
||||||
|
//abiFilters += listOf("armeabi-v7a", "arm64-v8a")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
isMinifyEnabled = false
|
||||||
|
proguardFiles(
|
||||||
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility = JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "1.8"
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
maybeCreate("main").apply {
|
||||||
|
java {
|
||||||
|
srcDirs("src/main/kotlin")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
externalNativeBuild {
|
||||||
|
cmake {
|
||||||
|
path("src/main/rust/CMakeLists.txt")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.named("clean") {
|
||||||
|
doLast {
|
||||||
|
delete("src/main/rust/target", "src/main/rust/Cargo.lock")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
// none
|
||||||
|
}
|
4
lib/native/src/main/AndroidManifest.xml
Normal file
4
lib/native/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
</manifest>
|
@ -0,0 +1,3 @@
|
|||||||
|
package org.florisboard.libnative
|
||||||
|
|
||||||
|
external fun dummyAdd(a: Int, b: Int): Int
|
53
lib/native/src/main/rust/CMakeLists.txt
Normal file
53
lib/native/src/main/rust/CMakeLists.txt
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
project(florisboard)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set(USER_HOME_DIRECTORY "$ENV{USERPROFILE}")
|
||||||
|
else()
|
||||||
|
set(USER_HOME_DIRECTORY "$ENV{HOME}")
|
||||||
|
endif()
|
||||||
|
set(RUST_TOOLCHAIN "${USER_HOME_DIRECTORY}/.cargo/bin")
|
||||||
|
|
||||||
|
### FlorisBoard ###
|
||||||
|
|
||||||
|
add_library(fl_native SHARED src/lib.c)
|
||||||
|
|
||||||
|
if(CMAKE_ANDROID_ARCH_ABI STREQUAL "armeabi-v7a")
|
||||||
|
set(ANDROID_TARGET "armv7a-linux-androideabi")
|
||||||
|
set(RUST_TARGET "armv7-linux-androideabi")
|
||||||
|
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "arm64-v8a")
|
||||||
|
set(ANDROID_TARGET "aarch64-linux-android")
|
||||||
|
set(RUST_TARGET "aarch64-linux-android")
|
||||||
|
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86")
|
||||||
|
set(ANDROID_TARGET "i686-linux-android")
|
||||||
|
set(RUST_TARGET "i686-linux-android")
|
||||||
|
elseif(CMAKE_ANDROID_ARCH_ABI STREQUAL "x86_64")
|
||||||
|
set(ANDROID_TARGET "x86_64-linux-android")
|
||||||
|
set(RUST_TARGET "x86_64-linux-android")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unsupported ABI: ${CMAKE_ANDROID_ARCH_ABI}")
|
||||||
|
endif()
|
||||||
|
get_filename_component(LLVM_TOOLCHAIN ${CMAKE_C_COMPILER} DIRECTORY)
|
||||||
|
|
||||||
|
set(FL_NATIVE_RUST_PATH "${CMAKE_CURRENT_SOURCE_DIR}/target/${RUST_TARGET}/release/libfl_native_rust.a")
|
||||||
|
|
||||||
|
add_custom_target(
|
||||||
|
setup_rust_target ALL
|
||||||
|
COMMAND ${RUST_TOOLCHAIN}/rustup target add ${RUST_TARGET}
|
||||||
|
)
|
||||||
|
add_custom_target(
|
||||||
|
fl_native_rust_build ALL
|
||||||
|
COMMAND ${RUST_TOOLCHAIN}/cargo rustc --release --target ${RUST_TARGET} --
|
||||||
|
-C linker="${LLVM_TOOLCHAIN}/${ANDROID_TARGET}${CMAKE_ANDROID_API}-clang"
|
||||||
|
DEPENDS setup_rust_target
|
||||||
|
BYPRODUCTS ${FL_NATIVE_RUST_PATH}
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_dependencies(fl_native fl_native_rust_build)
|
||||||
|
|
||||||
|
# TODO: check if there's a better way than allowing multiple symbol definitions
|
||||||
|
target_link_libraries(fl_native
|
||||||
|
android log -Wl,--whole-archive -Wl,--allow-multiple-definition ${FL_NATIVE_RUST_PATH}
|
||||||
|
)
|
12
lib/native/src/main/rust/Cargo.toml
Normal file
12
lib/native/src/main/rust/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[package]
|
||||||
|
name = "fl_native_rust"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "fl_native_rust"
|
||||||
|
crate-type = ["staticlib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
dummy = { path = "../../../../../libnative/dummy" }
|
||||||
|
jni = "0.21.1"
|
1
lib/native/src/main/rust/src/lib.c
Normal file
1
lib/native/src/main/rust/src/lib.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
// DO NOT DELETE ELSE CMAKE FAILS
|
15
lib/native/src/main/rust/src/lib.rs
Normal file
15
lib/native/src/main/rust/src/lib.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
use dummy;
|
||||||
|
|
||||||
|
use jni::objects::JClass;
|
||||||
|
use jni::sys::jint;
|
||||||
|
use jni::JNIEnv;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "system" fn Java_org_florisboard_libnative_TestKt_dummyAdd(
|
||||||
|
_env: JNIEnv,
|
||||||
|
_class: JClass,
|
||||||
|
a: jint,
|
||||||
|
b: jint,
|
||||||
|
) -> jint {
|
||||||
|
dummy::addnumbers(a, b)
|
||||||
|
}
|
6
libnative/dummy/Cargo.toml
Normal file
6
libnative/dummy/Cargo.toml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[package]
|
||||||
|
name = "dummy"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
3
libnative/dummy/src/lib.rs
Normal file
3
libnative/dummy/src/lib.rs
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
pub fn addnumbers(left: i32, right: i32) -> i32 {
|
||||||
|
left + right
|
||||||
|
}
|
@ -36,3 +36,4 @@ dependencyResolutionManagement {
|
|||||||
include(":app")
|
include(":app")
|
||||||
include(":benchmark")
|
include(":benchmark")
|
||||||
include(":lib:kotlin")
|
include(":lib:kotlin")
|
||||||
|
include(":lib:native")
|
||||||
|
Loading…
Reference in New Issue
Block a user