194 lines
6.6 KiB
Kotlin
194 lines
6.6 KiB
Kotlin
import javax.inject.Inject
|
|
import org.gradle.process.ExecOperations
|
|
|
|
plugins {
|
|
alias(libs.plugins.android.application)
|
|
alias(libs.plugins.kotlin.android)
|
|
alias(libs.plugins.kotlin.compose)
|
|
}
|
|
|
|
// Build isodrive native binary from submodule (only if binaries are missing)
|
|
abstract class BuildIsodriveTask @Inject constructor(
|
|
private val execOps: ExecOperations
|
|
) : DefaultTask() {
|
|
|
|
@get:InputDirectory
|
|
abstract val isodriveDir: DirectoryProperty
|
|
|
|
@get:OutputDirectory
|
|
abstract val outputDir: DirectoryProperty
|
|
|
|
@TaskAction
|
|
fun build() {
|
|
val isodrivePath = isodriveDir.get().asFile
|
|
val outputPath = outputDir.get().asFile
|
|
|
|
if (!isodrivePath.resolve("src").exists()) {
|
|
throw GradleException("isodrive submodule not initialized. Run: git submodule update --init")
|
|
}
|
|
|
|
val sourceFiles = listOf(
|
|
"src/util.cpp",
|
|
"src/configfsisomanager.cpp",
|
|
"src/androidusbisomanager.cpp",
|
|
"src/main.cpp"
|
|
)
|
|
val srcs = sourceFiles.joinToString(" ") { "$isodrivePath/$it" }
|
|
val cflags = "-I$isodrivePath/src/include -static-libstdc++ -Os -s"
|
|
|
|
val compilers = mapOf(
|
|
"arm64-v8a" to "aarch64-linux-android26-clang++",
|
|
"armeabi-v7a" to "armv7a-linux-androideabi26-clang++",
|
|
"x86_64" to "x86_64-linux-android26-clang++",
|
|
"x86" to "i686-linux-android26-clang++"
|
|
)
|
|
|
|
val useNixShell = File("/etc/NIXOS").exists() ||
|
|
Runtime.getRuntime().exec(arrayOf("which", "nix-shell")).waitFor() == 0
|
|
|
|
if (useNixShell) {
|
|
println("NixOS detected, using nix-shell for NDK...")
|
|
|
|
val buildScript = compilers.entries.joinToString("\n") { (arch, compiler) ->
|
|
val archDir = outputPath.resolve(arch)
|
|
val output = archDir.resolve("isodrive")
|
|
if (output.exists()) {
|
|
"echo 'isodrive for $arch already exists, skipping'"
|
|
} else {
|
|
"""
|
|
mkdir -p "$archDir"
|
|
echo "Building isodrive for $arch..."
|
|
"${'$'}TOOLCHAIN/$compiler" $cflags $srcs -o "$output"
|
|
""".trimIndent()
|
|
}
|
|
}
|
|
|
|
execOps.exec {
|
|
environment("NIXPKGS_ALLOW_UNFREE", "1")
|
|
commandLine("nix-shell", "-p", "androidenv.androidPkgs.ndk-bundle", "--run", """
|
|
SDK_ROOT=${'$'}(find /nix/store -maxdepth 1 -name "*android-sdk-ndk*" -type d 2>/dev/null | head -1)
|
|
NDK=${'$'}(ls -d "${'$'}SDK_ROOT/libexec/android-sdk/ndk/"* | head -1)
|
|
TOOLCHAIN="${'$'}NDK/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
|
echo "Using NDK: ${'$'}NDK"
|
|
$buildScript
|
|
echo "Done building isodrive"
|
|
""".trimIndent())
|
|
}
|
|
} else {
|
|
val ndkDir = listOfNotNull(
|
|
System.getenv("ANDROID_NDK_HOME"),
|
|
System.getenv("ANDROID_NDK")
|
|
).firstOrNull { File(it).exists() }
|
|
?: throw GradleException("Android NDK not found. Set ANDROID_NDK_HOME or install NDK via SDK Manager.")
|
|
|
|
val toolchain = "$ndkDir/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
|
if (!File(toolchain).exists()) {
|
|
throw GradleException("NDK toolchain not found at: $toolchain")
|
|
}
|
|
|
|
compilers.forEach { (arch, compiler) ->
|
|
val archDir = outputPath.resolve(arch)
|
|
val output = archDir.resolve("isodrive")
|
|
|
|
if (output.exists()) {
|
|
println("isodrive for $arch already exists, skipping")
|
|
return@forEach
|
|
}
|
|
|
|
archDir.mkdirs()
|
|
println("Building isodrive for $arch...")
|
|
execOps.exec {
|
|
commandLine("sh", "-c", "$toolchain/$compiler $cflags $srcs -o $output")
|
|
}
|
|
}
|
|
println("Done building isodrive")
|
|
}
|
|
}
|
|
}
|
|
|
|
val buildIsodrive by tasks.registering(BuildIsodriveTask::class) {
|
|
group = "native"
|
|
description = "Build isodrive binary for all Android architectures"
|
|
|
|
isodriveDir.set(rootProject.file("isodrive"))
|
|
outputDir.set(file("src/main/assets/bin"))
|
|
|
|
val architectures = listOf("arm64-v8a", "armeabi-v7a", "x86_64", "x86")
|
|
val outDir = file("src/main/assets/bin")
|
|
onlyIf { !architectures.all { arch -> outDir.resolve("$arch/isodrive").exists() } }
|
|
}
|
|
|
|
tasks.matching { it.name.startsWith("merge") && it.name.endsWith("Assets") }.configureEach {
|
|
dependsOn(buildIsodrive)
|
|
}
|
|
|
|
android {
|
|
namespace = "sh.sar.isodroid"
|
|
compileSdk = 36
|
|
|
|
defaultConfig {
|
|
applicationId = "sh.sar.isodroid"
|
|
minSdk = 26
|
|
targetSdk = 36
|
|
versionCode = 7
|
|
versionName = "1.7"
|
|
|
|
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
|
}
|
|
|
|
buildTypes {
|
|
release {
|
|
isMinifyEnabled = false
|
|
proguardFiles(
|
|
getDefaultProguardFile("proguard-android-optimize.txt"),
|
|
"proguard-rules.pro"
|
|
)
|
|
}
|
|
}
|
|
compileOptions {
|
|
sourceCompatibility = JavaVersion.VERSION_11
|
|
targetCompatibility = JavaVersion.VERSION_11
|
|
}
|
|
kotlinOptions {
|
|
jvmTarget = "11"
|
|
}
|
|
buildFeatures {
|
|
compose = true
|
|
buildConfig = true
|
|
}
|
|
}
|
|
|
|
dependencies {
|
|
implementation(libs.androidx.core.ktx)
|
|
implementation(libs.androidx.appcompat)
|
|
implementation(libs.material)
|
|
|
|
// Compose
|
|
implementation(platform(libs.androidx.compose.bom))
|
|
implementation(libs.androidx.compose.ui)
|
|
implementation(libs.androidx.compose.ui.graphics)
|
|
implementation(libs.androidx.compose.ui.tooling.preview)
|
|
implementation(libs.androidx.compose.material3)
|
|
implementation(libs.androidx.compose.material.icons.extended)
|
|
implementation(libs.androidx.activity.compose)
|
|
implementation(libs.androidx.lifecycle.viewmodel.compose)
|
|
implementation(libs.androidx.lifecycle.runtime.compose)
|
|
implementation(libs.androidx.navigation.compose)
|
|
debugImplementation(libs.androidx.compose.ui.tooling)
|
|
|
|
// libsu for root access
|
|
implementation(libs.libsu.core)
|
|
implementation(libs.libsu.service)
|
|
|
|
// DataStore for preferences
|
|
implementation(libs.androidx.datastore.preferences)
|
|
|
|
// Coil for image loading (SVG support)
|
|
implementation(libs.coil.compose)
|
|
implementation(libs.coil.svg)
|
|
|
|
testImplementation(libs.junit)
|
|
androidTestImplementation(libs.androidx.junit)
|
|
androidTestImplementation(libs.androidx.espresso.core)
|
|
}
|