[sdks/android] DO NOT LAND - Build libmentat_ffi.so as part of Gradle build.
This uses a very rudimentary Gradle plugin, `rust-android-gradle`, with custom fixes and extensions. It works pretty well for what it is!
This commit is contained in:
parent
bf7f0ef6a4
commit
6898bac83d
11 changed files with 317 additions and 4 deletions
|
@ -17,6 +17,7 @@ buildscript {
|
|||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
|
|
64
sdks/android/Mentat/buildSrc/build.gradle
Normal file
64
sdks/android/Mentat/buildSrc/build.gradle
Normal file
|
@ -0,0 +1,64 @@
|
|||
buildscript {
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
ext.kotlin_version = '1.2.41'
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
google()
|
||||
}
|
||||
|
||||
apply plugin: "java-gradle-plugin"
|
||||
// apply plugin: "maven-publish"
|
||||
apply plugin: "kotlin"
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
simplePlugin {
|
||||
id = "com.nishtahir.rust-android"
|
||||
implementationClass = "com.nishtahir.RustAndroidPlugin"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// group 'com.nishtahir'
|
||||
// version '0.0.2'
|
||||
|
||||
// publishing {
|
||||
// repositories {
|
||||
// maven {
|
||||
// url "../samples/maven-repo"
|
||||
// }
|
||||
// }
|
||||
// publications {
|
||||
// maven(MavenPublication) {
|
||||
// groupId 'com.nishtahir'
|
||||
// artifactId 'rust-android'
|
||||
// version '0.0.2'
|
||||
|
||||
// from components.java
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
dependencies {
|
||||
compileOnly gradleApi()
|
||||
implementation "com.android.tools.build:gradle:3.1.2"
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version"
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
||||
compileTestKotlin {
|
||||
kotlinOptions.jvmTarget = "1.8"
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package com.nishtahir;
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import java.io.File
|
||||
|
||||
open class CargoBuildTask : DefaultTask() {
|
||||
|
||||
@Suppress("unused")
|
||||
@TaskAction
|
||||
fun build() = with(project) {
|
||||
extensions[CargoExtension::class].apply {
|
||||
targets.forEach { target ->
|
||||
val toolchain = toolchains.find { (arch) -> arch == target }
|
||||
if (toolchain != null) {
|
||||
buildProjectForTarget(project, toolchain, this)
|
||||
|
||||
val targetDirectory = targetDirectory ?: "${module}/target"
|
||||
|
||||
copy { spec ->
|
||||
spec.into(File(buildDir, "rustJniLibs/${toolchain.folder}"))
|
||||
spec.from(File(project.projectDir, "${targetDirectory}/${toolchain.target}/${profile}"))
|
||||
spec.include(targetInclude)
|
||||
}
|
||||
} else {
|
||||
println("No such target $target")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildProjectForTarget(project: Project, toolchain: Toolchain, cargoExtension: CargoExtension) {
|
||||
project.exec { spec ->
|
||||
val cc = "${project.getToolchainDirectory()}/${toolchain.cc()}"
|
||||
val ar = "${project.getToolchainDirectory()}/${toolchain.ar()}"
|
||||
println("using CC: $cc")
|
||||
println("using AR: $ar")
|
||||
with(spec) {
|
||||
standardOutput = System.out
|
||||
workingDir = File(project.project.projectDir, cargoExtension.module)
|
||||
environment("CC", cc)
|
||||
environment("AR", ar)
|
||||
environment("RUSTFLAGS", "-C linker=$cc")
|
||||
commandLine = listOf("cargo", "build", "--target=${toolchain.target}")
|
||||
if (cargoExtension.profile != "debug") {
|
||||
// Cargo is rigid: it accepts "--release" for release (and
|
||||
// nothing for dev). This is a cheap way of allowing only
|
||||
// two values.
|
||||
commandLine.add("--${cargoExtension.profile}")
|
||||
}
|
||||
}
|
||||
}.assertNormalExitValue()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.nishtahir
|
||||
|
||||
open class CargoExtension {
|
||||
var module: String = ""
|
||||
var targets: List<String> = emptyList()
|
||||
|
||||
/**
|
||||
* The Cargo [release profile](https://doc.rust-lang.org/book/second-edition/ch14-01-release-profiles.html#customizing-builds-with-release-profiles) to build.
|
||||
*
|
||||
* Defaults to `"debug"`.
|
||||
*/
|
||||
var profile: String = "debug"
|
||||
|
||||
/**
|
||||
* The target directory into Cargo which writes built outputs.
|
||||
*
|
||||
* Defaults to `${module}/target`.
|
||||
*/
|
||||
var targetDirectory: String? = null
|
||||
|
||||
/**
|
||||
* Which Cargo built outputs to consider JNI libraries.
|
||||
*
|
||||
* Defaults to `"*.so"`.
|
||||
*/
|
||||
var targetInclude: String = "*.so"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.nishtahir
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.plugins.ExtensionContainer
|
||||
import java.io.File
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
const val TOOLS_FOLDER = ".cargo/toolchain"
|
||||
|
||||
operator fun <T : Any> ExtensionContainer.get(type: KClass<T>): T = getByType(type.java)
|
||||
|
||||
|
||||
|
||||
fun Project.getToolchainDirectory(): File = File(projectDir, TOOLS_FOLDER)
|
|
@ -0,0 +1,45 @@
|
|||
package com.nishtahir
|
||||
|
||||
import com.android.build.gradle.*
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
|
||||
open class GenerateToolchainsTask : DefaultTask() {
|
||||
|
||||
@TaskAction
|
||||
@Suppress("unused")
|
||||
fun generateToolchainTask() {
|
||||
project.plugins.all {
|
||||
when (it) {
|
||||
is AppPlugin -> congfigureTask<AppExtension>(project)
|
||||
is LibraryPlugin -> congfigureTask<LibraryExtension>(project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline fun <reified T : BaseExtension> congfigureTask(project: Project) {
|
||||
val app = project.extensions[T::class]
|
||||
val minApi = app.defaultConfig.minSdkVersion.apiLevel
|
||||
val ndkPath = app.ndkDirectory
|
||||
|
||||
if (project.getToolchainDirectory().exists()) {
|
||||
println("Existing toolchain found.")
|
||||
return
|
||||
}
|
||||
|
||||
toolchains
|
||||
.filterNot { (arch) -> minApi < 21 && arch.endsWith("64") }
|
||||
.forEach { (arch) ->
|
||||
project.exec { spec ->
|
||||
spec.standardOutput = System.out
|
||||
spec.errorOutput = System.out
|
||||
spec.commandLine("$ndkPath/build/tools/make_standalone_toolchain.py")
|
||||
spec.args("--arch=$arch", "--api=$minApi",
|
||||
"--install-dir=${project.getToolchainDirectory()}/$arch",
|
||||
"--force")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.nishtahir
|
||||
|
||||
import com.android.build.gradle.*
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.plugins.ide.idea.IdeaPlugin
|
||||
import org.gradle.plugins.ide.idea.model.IdeaModel
|
||||
import java.io.File
|
||||
|
||||
const val RUST_TASK_GROUP = "rust"
|
||||
|
||||
val toolchains = listOf(
|
||||
Toolchain("arm",
|
||||
"arm-linux-androideabi",
|
||||
"bin/arm-linux-androideabi-clang",
|
||||
"bin/arm-linux-androideabi-ar",
|
||||
"armeabi"),
|
||||
Toolchain("arm64",
|
||||
"aarch64-linux-android",
|
||||
"bin/aarch64-linux-android-clang",
|
||||
"bin/aarch64-linux-android-ar",
|
||||
"aarch64"),
|
||||
Toolchain("mips",
|
||||
"mipsel-linux-android",
|
||||
"bin/mipsel-linux-android-clang",
|
||||
"bin/mipsel-linux-android-ar",
|
||||
"mips"),
|
||||
Toolchain("x86",
|
||||
"i686-linux-android",
|
||||
"bin/i686-linux-android-clang",
|
||||
"bin/i686-linux-android-ar",
|
||||
"x86"),
|
||||
Toolchain("x86_64",
|
||||
"x86_64-linux-android",
|
||||
"bin/x86_64-linux-android-clang",
|
||||
"bin/x86_64-linux-android-ar",
|
||||
"x86_64")
|
||||
)
|
||||
|
||||
data class Toolchain(val platform: String,
|
||||
val target: String,
|
||||
val cc: String,
|
||||
val ar: String,
|
||||
val folder: String) {
|
||||
fun cc(): String = "$platform/$cc"
|
||||
fun ar(): String = "$platform/$ar"
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
open class RustAndroidPlugin : Plugin<Project> {
|
||||
|
||||
override fun apply(project: Project) {
|
||||
with(project) {
|
||||
|
||||
extensions.add("cargo", CargoExtension::class.java)
|
||||
|
||||
afterEvaluate {
|
||||
plugins.all {
|
||||
when (it) {
|
||||
is AppPlugin -> configurePlugin<AppExtension>(this)
|
||||
is LibraryPlugin -> configurePlugin<LibraryExtension>(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified T : BaseExtension> configurePlugin(project: Project) = with(project) {
|
||||
extensions[T::class].apply {
|
||||
sourceSets.getByName("main").jniLibs.srcDir(File("$buildDir/rustJniLibs/"))
|
||||
}
|
||||
|
||||
val generateToolchain = tasks.maybeCreate("generateToolchains",
|
||||
GenerateToolchainsTask::class.java).apply {
|
||||
group = RUST_TASK_GROUP
|
||||
description = "Generate standard toolchain for given architectures"
|
||||
}
|
||||
|
||||
val buildTask = tasks.maybeCreate("cargoBuild",
|
||||
CargoBuildTask::class.java).apply {
|
||||
group = RUST_TASK_GROUP
|
||||
description = "Build library"
|
||||
}
|
||||
|
||||
buildTask.dependsOn(generateToolchain)
|
||||
}
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'com.nishtahir.rust-android'
|
||||
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'com.jfrog.bintray'
|
||||
// Simply applying this plugin gets bintray to publish a pom file.
|
||||
|
@ -33,6 +35,14 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
cargo {
|
||||
module = '../../../../ffi'
|
||||
targetDirectory = '../../../../target'
|
||||
targetInclude = 'libmentat_ffi.so'
|
||||
|
||||
targets = ['x86']
|
||||
}
|
||||
|
||||
dependencies {
|
||||
androidTestImplementation 'com.android.support:support-annotations:27.1.1'
|
||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||
|
@ -41,10 +51,23 @@ dependencies {
|
|||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||
implementation 'net.java.dev.jna:jna:4.5.1'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
afterEvaluate {
|
||||
// The `cargoBuild` tasks isn't available until after evaluation.
|
||||
android.libraryVariants.all { variant ->
|
||||
def productFlavor = ""
|
||||
variant.productFlavors.each {
|
||||
productFlavor += "${it.name.capitalize()}"
|
||||
}
|
||||
def buildType = "${variant.buildType.name.capitalize()}"
|
||||
tasks["generate${productFlavor}${buildType}Assets"].dependsOn(tasks["cargoBuild"])
|
||||
}
|
||||
}
|
||||
|
||||
// Publishing to jcenter/bintray.
|
||||
def libGroupId = properties.libGroupId
|
||||
def libRepoName = properties.libRepositoryName
|
||||
|
@ -71,7 +94,6 @@ artifacts {
|
|||
archives sourcesJar
|
||||
}
|
||||
|
||||
|
||||
group = libGroupId
|
||||
archivesBaseName = libProjectName
|
||||
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
../../../../../../../../target/aarch64-linux-android/release/libmentat_ffi.so
|
|
@ -1 +0,0 @@
|
|||
../../../../../../../../target/armv7-linux-androideabi/release/libmentat_ffi.so
|
|
@ -1 +0,0 @@
|
|||
../../../../../../../../target/i686-linux-android/release/libmentat_ffi.so
|
Loading…
Reference in a new issue