atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git

Blame: xtask/src/kotlin.rs

7ff8adafe9e4atagen2026-10-22 12:30 UTC1
use std::fs::create_dir_all;
7ff8adafe9e4atagen2026-10-22 12:30 UTC2
7ff8adafe9e4atagen2026-10-22 12:30 UTC3
use camino::{Utf8Path, Utf8PathBuf};
7ff8adafe9e4atagen2026-10-22 12:30 UTC4
use clap::{Args, Subcommand, ValueEnum};
7ff8adafe9e4atagen2026-10-22 12:30 UTC5
use uniffi_bindgen::bindings::{GenerateOptions, TargetLanguage, generate};
7ff8adafe9e4atagen2026-10-22 12:30 UTC6
use xshell::cmd;
7ff8adafe9e4atagen2026-10-22 12:30 UTC7
7ff8adafe9e4atagen2026-10-22 12:30 UTC8
use crate::{Result, sh, workspace};
7ff8adafe9e4atagen2026-10-22 12:30 UTC9
7ff8adafe9e4atagen2026-10-22 12:30 UTC10
struct PackageValues {
7ff8adafe9e4atagen2026-10-22 12:30 UTC11
    name: &'static str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC12
    features: &'static str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC13
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC14
7ff8adafe9e4atagen2026-10-22 12:30 UTC15
#[derive(ValueEnum, Clone)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC16
enum Package {
7ff8adafe9e4atagen2026-10-22 12:30 UTC17
    CryptoSDK,
7ff8adafe9e4atagen2026-10-22 12:30 UTC18
    FullSDK,
7ff8adafe9e4atagen2026-10-22 12:30 UTC19
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC20
7ff8adafe9e4atagen2026-10-22 12:30 UTC21
impl Package {
7ff8adafe9e4atagen2026-10-22 12:30 UTC22
    fn values(self) -> PackageValues {
7ff8adafe9e4atagen2026-10-22 12:30 UTC23
        match self {
7ff8adafe9e4atagen2026-10-22 12:30 UTC24
            Package::CryptoSDK => PackageValues { name: "matrix-sdk-crypto-ffi", features: "" },
7ff8adafe9e4atagen2026-10-22 12:30 UTC25
            Package::FullSDK => PackageValues { name: "matrix-sdk-ffi", features: "sentry" },
7ff8adafe9e4atagen2026-10-22 12:30 UTC26
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC27
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC28
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC29
7ff8adafe9e4atagen2026-10-22 12:30 UTC30
#[derive(Args)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC31
pub struct KotlinArgs {
7ff8adafe9e4atagen2026-10-22 12:30 UTC32
    #[clap(subcommand)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC33
    cmd: KotlinCommand,
7ff8adafe9e4atagen2026-10-22 12:30 UTC34
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC35
7ff8adafe9e4atagen2026-10-22 12:30 UTC36
#[derive(Subcommand)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC37
enum KotlinCommand {
7ff8adafe9e4atagen2026-10-22 12:30 UTC38
    /// Builds the SDK for Android as an AAR.
7ff8adafe9e4atagen2026-10-22 12:30 UTC39
    BuildAndroidLibrary {
7ff8adafe9e4atagen2026-10-22 12:30 UTC40
        #[clap(value_enum, long)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC41
        package: Package,
7ff8adafe9e4atagen2026-10-22 12:30 UTC42
7ff8adafe9e4atagen2026-10-22 12:30 UTC43
        /// Build with the release profile
7ff8adafe9e4atagen2026-10-22 12:30 UTC44
        #[clap(long)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC45
        release: bool,
7ff8adafe9e4atagen2026-10-22 12:30 UTC46
7ff8adafe9e4atagen2026-10-22 12:30 UTC47
        /// Build with a custom profile, takes precedence over `--release`
7ff8adafe9e4atagen2026-10-22 12:30 UTC48
        #[clap(long)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC49
        profile: Option<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC50
7ff8adafe9e4atagen2026-10-22 12:30 UTC51
        /// Build the given target only
7ff8adafe9e4atagen2026-10-22 12:30 UTC52
        #[clap(long)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC53
        only_target: Option<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC54
7ff8adafe9e4atagen2026-10-22 12:30 UTC55
        /// Move the generated files into the given src directory
7ff8adafe9e4atagen2026-10-22 12:30 UTC56
        #[clap(long)]
7ff8adafe9e4atagen2026-10-22 12:30 UTC57
        src_dir: Utf8PathBuf,
7ff8adafe9e4atagen2026-10-22 12:30 UTC58
    },
7ff8adafe9e4atagen2026-10-22 12:30 UTC59
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC60
7ff8adafe9e4atagen2026-10-22 12:30 UTC61
impl KotlinArgs {
7ff8adafe9e4atagen2026-10-22 12:30 UTC62
    pub fn run(self) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC63
        let sh = sh();
7ff8adafe9e4atagen2026-10-22 12:30 UTC64
        let _p = sh.push_dir(workspace::root_path()?);
7ff8adafe9e4atagen2026-10-22 12:30 UTC65
7ff8adafe9e4atagen2026-10-22 12:30 UTC66
        match self.cmd {
7ff8adafe9e4atagen2026-10-22 12:30 UTC67
            KotlinCommand::BuildAndroidLibrary {
7ff8adafe9e4atagen2026-10-22 12:30 UTC68
                release,
7ff8adafe9e4atagen2026-10-22 12:30 UTC69
                profile,
7ff8adafe9e4atagen2026-10-22 12:30 UTC70
                src_dir,
7ff8adafe9e4atagen2026-10-22 12:30 UTC71
                only_target,
7ff8adafe9e4atagen2026-10-22 12:30 UTC72
                package,
7ff8adafe9e4atagen2026-10-22 12:30 UTC73
            } => {
7ff8adafe9e4atagen2026-10-22 12:30 UTC74
                let profile = profile.as_deref().unwrap_or(if release { "release" } else { "dev" });
7ff8adafe9e4atagen2026-10-22 12:30 UTC75
                build_android_library(profile, only_target, &src_dir, package)
7ff8adafe9e4atagen2026-10-22 12:30 UTC76
            }
7ff8adafe9e4atagen2026-10-22 12:30 UTC77
        }
7ff8adafe9e4atagen2026-10-22 12:30 UTC78
    }
7ff8adafe9e4atagen2026-10-22 12:30 UTC79
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC80
7ff8adafe9e4atagen2026-10-22 12:30 UTC81
fn build_android_library(
7ff8adafe9e4atagen2026-10-22 12:30 UTC82
    profile: &str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC83
    only_target: Option<String>,
7ff8adafe9e4atagen2026-10-22 12:30 UTC84
    src_dir: &Utf8Path,
7ff8adafe9e4atagen2026-10-22 12:30 UTC85
    package: Package,
7ff8adafe9e4atagen2026-10-22 12:30 UTC86
) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC87
    let package_values = package.values();
7ff8adafe9e4atagen2026-10-22 12:30 UTC88
    let package_name = package_values.name;
7ff8adafe9e4atagen2026-10-22 12:30 UTC89
    let package_features = package_values.features;
7ff8adafe9e4atagen2026-10-22 12:30 UTC90
7ff8adafe9e4atagen2026-10-22 12:30 UTC91
    let jni_libs_dir = src_dir.join("jniLibs");
7ff8adafe9e4atagen2026-10-22 12:30 UTC92
    let jni_libs_dir_str = jni_libs_dir.as_str();
7ff8adafe9e4atagen2026-10-22 12:30 UTC93
7ff8adafe9e4atagen2026-10-22 12:30 UTC94
    let kotlin_generated_dir = src_dir.join("kotlin");
7ff8adafe9e4atagen2026-10-22 12:30 UTC95
    create_dir_all(kotlin_generated_dir.clone())?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC96
7ff8adafe9e4atagen2026-10-22 12:30 UTC97
    let uniffi_lib_path = if let Some(target) = only_target {
7ff8adafe9e4atagen2026-10-22 12:30 UTC98
        println!("-- Building for {target} [1/1]");
7ff8adafe9e4atagen2026-10-22 12:30 UTC99
        build_for_android_target(
7ff8adafe9e4atagen2026-10-22 12:30 UTC100
            target.as_str(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC101
            profile,
7ff8adafe9e4atagen2026-10-22 12:30 UTC102
            jni_libs_dir_str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC103
            package_name,
7ff8adafe9e4atagen2026-10-22 12:30 UTC104
            package_features,
7ff8adafe9e4atagen2026-10-22 12:30 UTC105
        )?
7ff8adafe9e4atagen2026-10-22 12:30 UTC106
    } else {
7ff8adafe9e4atagen2026-10-22 12:30 UTC107
        println!("-- Building for x86_64-linux-android[1/4]");
7ff8adafe9e4atagen2026-10-22 12:30 UTC108
        build_for_android_target(
7ff8adafe9e4atagen2026-10-22 12:30 UTC109
            "x86_64-linux-android",
7ff8adafe9e4atagen2026-10-22 12:30 UTC110
            profile,
7ff8adafe9e4atagen2026-10-22 12:30 UTC111
            jni_libs_dir_str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC112
            package_name,
7ff8adafe9e4atagen2026-10-22 12:30 UTC113
            package_features,
7ff8adafe9e4atagen2026-10-22 12:30 UTC114
        )?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC115
        println!("-- Building for aarch64-linux-android[2/4]");
7ff8adafe9e4atagen2026-10-22 12:30 UTC116
        build_for_android_target(
7ff8adafe9e4atagen2026-10-22 12:30 UTC117
            "aarch64-linux-android",
7ff8adafe9e4atagen2026-10-22 12:30 UTC118
            profile,
7ff8adafe9e4atagen2026-10-22 12:30 UTC119
            jni_libs_dir_str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC120
            package_name,
7ff8adafe9e4atagen2026-10-22 12:30 UTC121
            package_features,
7ff8adafe9e4atagen2026-10-22 12:30 UTC122
        )?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC123
        println!("-- Building for armv7-linux-androideabi[3/4]");
7ff8adafe9e4atagen2026-10-22 12:30 UTC124
        build_for_android_target(
7ff8adafe9e4atagen2026-10-22 12:30 UTC125
            "armv7-linux-androideabi",
7ff8adafe9e4atagen2026-10-22 12:30 UTC126
            profile,
7ff8adafe9e4atagen2026-10-22 12:30 UTC127
            jni_libs_dir_str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC128
            package_name,
7ff8adafe9e4atagen2026-10-22 12:30 UTC129
            package_features,
7ff8adafe9e4atagen2026-10-22 12:30 UTC130
        )?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC131
        println!("-- Building for i686-linux-android[4/4]");
7ff8adafe9e4atagen2026-10-22 12:30 UTC132
        build_for_android_target(
7ff8adafe9e4atagen2026-10-22 12:30 UTC133
            "i686-linux-android",
7ff8adafe9e4atagen2026-10-22 12:30 UTC134
            profile,
7ff8adafe9e4atagen2026-10-22 12:30 UTC135
            jni_libs_dir_str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC136
            package_name,
7ff8adafe9e4atagen2026-10-22 12:30 UTC137
            package_features,
7ff8adafe9e4atagen2026-10-22 12:30 UTC138
        )?
7ff8adafe9e4atagen2026-10-22 12:30 UTC139
    };
7ff8adafe9e4atagen2026-10-22 12:30 UTC140
7ff8adafe9e4atagen2026-10-22 12:30 UTC141
    println!("-- Generate uniffi files");
7ff8adafe9e4atagen2026-10-22 12:30 UTC142
    generate_uniffi_bindings(&uniffi_lib_path, &kotlin_generated_dir)?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC143
7ff8adafe9e4atagen2026-10-22 12:30 UTC144
    println!("-- All done and hunky dory. Enjoy!");
7ff8adafe9e4atagen2026-10-22 12:30 UTC145
    Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC146
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC147
7ff8adafe9e4atagen2026-10-22 12:30 UTC148
fn generate_uniffi_bindings(library_path: &Utf8Path, ffi_generated_dir: &Utf8Path) -> Result<()> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC149
    println!("-- library_path = {library_path}");
7ff8adafe9e4atagen2026-10-22 12:30 UTC150
    generate(GenerateOptions {
7ff8adafe9e4atagen2026-10-22 12:30 UTC151
        languages: vec![TargetLanguage::Kotlin],
7ff8adafe9e4atagen2026-10-22 12:30 UTC152
        source: library_path.to_path_buf(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC153
        out_dir: ffi_generated_dir.to_path_buf(),
7ff8adafe9e4atagen2026-10-22 12:30 UTC154
        ..GenerateOptions::default()
7ff8adafe9e4atagen2026-10-22 12:30 UTC155
    })?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC156
    Ok(())
7ff8adafe9e4atagen2026-10-22 12:30 UTC157
}
7ff8adafe9e4atagen2026-10-22 12:30 UTC158
7ff8adafe9e4atagen2026-10-22 12:30 UTC159
fn build_for_android_target(
7ff8adafe9e4atagen2026-10-22 12:30 UTC160
    target: &str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC161
    profile: &str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC162
    dest_dir: &str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC163
    package_name: &str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC164
    features: &str,
7ff8adafe9e4atagen2026-10-22 12:30 UTC165
) -> Result<Utf8PathBuf> {
7ff8adafe9e4atagen2026-10-22 12:30 UTC166
    let sh = sh();
7ff8adafe9e4atagen2026-10-22 12:30 UTC167
    cmd!(
7ff8adafe9e4atagen2026-10-22 12:30 UTC168
        sh,
7ff8adafe9e4atagen2026-10-22 12:30 UTC169
        "cargo ndk --target {target} -o {dest_dir} build --profile {profile} --package {package_name} --features {features}"
7ff8adafe9e4atagen2026-10-22 12:30 UTC170
    )
7ff8adafe9e4atagen2026-10-22 12:30 UTC171
    .run()?;
7ff8adafe9e4atagen2026-10-22 12:30 UTC172
7ff8adafe9e4atagen2026-10-22 12:30 UTC173
    // The builtin dev profile has its files stored under target/debug, all
7ff8adafe9e4atagen2026-10-22 12:30 UTC174
    // other targets have matching directory names
7ff8adafe9e4atagen2026-10-22 12:30 UTC175
    let profile_dir_name = if profile == "dev" { "debug" } else { profile };
7ff8adafe9e4atagen2026-10-22 12:30 UTC176
    let package_camel = package_name.replace('-', "_");
7ff8adafe9e4atagen2026-10-22 12:30 UTC177
    let lib_name = format!("lib{package_camel}.so");
7ff8adafe9e4atagen2026-10-22 12:30 UTC178
    Ok(workspace::target_path()?.join(target).join(profile_dir_name).join(lib_name))
7ff8adafe9e4atagen2026-10-22 12:30 UTC179
}