[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()
|
jcenter()
|
||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.1.2'
|
classpath 'com.android.tools.build:gradle:3.1.2'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
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.android.library'
|
||||||
|
apply plugin: 'com.nishtahir.rust-android'
|
||||||
|
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'com.jfrog.bintray'
|
apply plugin: 'com.jfrog.bintray'
|
||||||
// Simply applying this plugin gets bintray to publish a pom file.
|
// 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 {
|
dependencies {
|
||||||
androidTestImplementation 'com.android.support:support-annotations:27.1.1'
|
androidTestImplementation 'com.android.support:support-annotations:27.1.1'
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
|
@ -41,10 +51,23 @@ dependencies {
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
||||||
implementation 'net.java.dev.jna:jna:4.5.1'
|
implementation 'net.java.dev.jna:jna:4.5.1'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
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.
|
// Publishing to jcenter/bintray.
|
||||||
def libGroupId = properties.libGroupId
|
def libGroupId = properties.libGroupId
|
||||||
def libRepoName = properties.libRepositoryName
|
def libRepoName = properties.libRepositoryName
|
||||||
|
@ -71,7 +94,6 @@ artifacts {
|
||||||
archives sourcesJar
|
archives sourcesJar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
group = libGroupId
|
group = libGroupId
|
||||||
archivesBaseName = libProjectName
|
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