Create multiple BuildCreateTasks
This is to support the following scenarios:
- Cross-compilation for mobile platforms (Android, iOS)
- Separate debug & release build results
Android
We can retrieve LibraryExtension
or BaseAppModuleExtension
from the Android Gradle Plugin and pass the path of the output directory.
val debugBuildCrateTask = tasks.create<BuildCrateTask> {
profile = "debug"
useAndroidJniLayout = true // Copies the .so to <NDK abi name>/lib<library name>.so
}
val releaseBuildCrateTask = tasks.create<BuildCrateTask> {
profile = "release"
useAndroidJniLayout = true
}
plugins.withId("com.android.library") {
with(extensions.getByType<LibraryExtension>()) {
sourceSets {
getByName("debug") {
jniLibs {
srcDir(debugBuildCrateTask.libraryOutputDirectory)
}
}
getByName("release") {
jniLibs {
srcDir(releaseBuildCrateTask.libraryOutputDirectory)
}
}
}
packagingOptions.jniLibs.excludes += "**/*.a"
}
}
Android NDK supports four ABIs: x86
, x86-64
, armv7a
, and aarch64
. We can also make BuildCreateTask
for each ABI, resulting in 8 BuildCreateTask
s in total.
For this, we need to:
-
Add properties (e.g. useAndroidJniLayout
) for NDK toBuildCreateTask
-
Add properties specifying the path and the version of NDK -
Allow users to specify ABIs in UniFfiExtension
-
Set useful environment variables or allow users to do that in BuildCreateTask
There are occasions when the user needs to set some environment variables when using Rust for Android.
For example, When building OpenSSL for Android, the build script of OpenSSL requires users to set the API level via compiler macros. To do this, you have to set variables like
CFLAGS_aarch64-linux-android
to something like-D__ANDROID_MIN_SDK_VERSION__=29
.Using crates like
cc
also requires the user to pass the path of executables in the toolchain (CC
toclang
,CXX
toclang++
,AR
tollvm-ar
, andRANLIB
tollvm-ranlib
).
iOS
As in Android, we need to generate tasks for each profile and each sysroot for iOS. For iOS KMP projects that use Cocoapods, we can detect the profile by checking the kotlin.native.cocoapods.configuration
property. (I don't know the name of the property used in projects without Cocoapods)
val release = rootProject.properties["kotlin.native.cocoapods.configuration"]?.toString()
?.lowercase() == "release"
To retrieve sysroots created by the user, we can allow users to provide that info, or we may be able to detect that by checking all KotlinNativeTarget
s.
For iOS, users may prefer static linking to shared libraries because all shared libraries must be signed, but I thought someone would need static linking on other platforms, so I filed a separate issue(#34 (closed)) for that. Currently we are using static linking for native targets; this is derived from my misunderstanding.
For this, we need to:
-
Detect profile via root project properties -
Detect sysroots configured by the user
Other platforms
I haven't found a reliable way to separate debug/release output directories for Desktop JVM platforms.