Skip to content

Instantly share code, notes, and snippets.

@willir
Created November 4, 2019 17:20
Show Gist options
  • Save willir/ed03396a9f2055a3914b7df0baa5a8f0 to your computer and use it in GitHub Desktop.
Save willir/ed03396a9f2055a3914b7df0baa5a8f0 to your computer and use it in GitHub Desktop.
Android Rust
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.Path
class BuildRust extends DefaultTask {
String variant
static String OUT_LIB_NAME = "libhello.so"
enum TargetType {
ARM64("arm64", "aarch64-linux-android", "arm64-v8a"),
ARM_V7("armv7", "armv7-linux-androideabi", "armeabi-v7a"),
X86("x86", "i686-linux-android", "x86"),
X86_64("x86_64", "x86_64-linux-android", "x86_64"),
final String id
final String rustTarget
final String jniLibDirName
private TargetType(String id, String rustTarget, String jniLibDirName) {
this.id = id
this.rustTarget = rustTarget
this.jniLibDirName = jniLibDirName
}
static TargetType fromId(String id) {
TargetType res = values().find {it.id == id}
if (res != null) {
return res
} else {
throw new GradleException(
"Wrong rust target: " + id + " supported: " + values().each {it.id})
}
}
boolean is64Bit() {
return this == ARM64 || this == X86_64
}
}
@TaskAction
void buildRust() {
TargetType rustTargetName = null
if (project.hasProperty("rustTarget")) {
rustTargetName = TargetType.fromId((String) project.findProperty("rustTarget"))
}
if (rustTargetName != null) {
buildTarget(rustTargetName)
} else {
for (target in TargetType.values()) {
buildTarget(target)
}
}
}
void buildTarget(TargetType target) {
int sdkVersion =
project.android.defaultConfig.minSdkVersion.getApiLevel()
if (target.is64Bit() && sdkVersion < 21) {
logger.warn(
"" + target + " doesn't support " + sdkVersion +
" SDK version. Changing to 21")
sdkVersion = 21
}
def cmd = ["cargo", "ndk",
"--target", target.rustTarget,
"--android-platform", sdkVersion.toString(),
"--", "build"]
if (isRelease()) {
cmd.add("--release")
}
logger.info("Executiong: " + cmd)
project.exec {
workingDir = getCargoPath()
commandLine = cmd
}.assertNormalExitValue()
copyTarget(target)
}
void copyTarget(TargetType target) {
def copyFrom = getRustLibOutPath(target)
def copyTo = getJniLibPath(target)
Files.deleteIfExists(copyTo)
Files.copy(copyFrom, copyTo)
logger.info("Copy ${copyFrom} -> ${copyTo}")
}
Path getRustLibOutPath(TargetType target) {
return Paths.get(getCargoPath().toString(), "target", target.rustTarget, variant, OUT_LIB_NAME)
}
Path getJniLibPath(TargetType target) {
return Paths.get(getSrcRootPath().toString(), "jniLibs", target.jniLibDirName, OUT_LIB_NAME)
}
Path getCargoPath() {
return Paths.get(getSrcRootPath().toString(), "rust")
}
Path getSrcRootPath() {
return Paths.get(project.rootDir.getPath(), "app", "src", "main")
}
boolean isRelease() {
return variant == "release"
}
}
task buildRustDebug(type: BuildRust) {
group = "Build"
description = "Build debug rust library"
variant = "debug"
}
task buildRustRelease(type: BuildRust) {
group = "Build"
description = "Build release rust library"
variant = "release"
}
tasks.whenTaskAdded { task ->
if (task.name == "compileDebugSources" || task.name == "mergeDebugJniLibFolders") {
task.dependsOn buildRustDebug
}
if (task.name == "compileReleaseSources" || task.name == "mergeReleaseJniLibFolders") {
task.dependsOn buildRustRelease
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment