atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git
xtask/src/kotlin.rsRust179 lines5.0 KB
1
use std::fs::create_dir_all;
2
3
use camino::{Utf8Path, Utf8PathBuf};
4
use clap::{Args, Subcommand, ValueEnum};
5
use uniffi_bindgen::bindings::{GenerateOptions, TargetLanguage, generate};
6
use xshell::cmd;
7
8
use crate::{Result, sh, workspace};
9
10
struct PackageValues {
11
    name: &'static str,
12
    features: &'static str,
13
}
14
15
#[derive(ValueEnum, Clone)]
16
enum Package {
17
    CryptoSDK,
18
    FullSDK,
19
}
20
21
impl Package {
22
    fn values(self) -> PackageValues {
23
        match self {
24
            Package::CryptoSDK => PackageValues { name: "matrix-sdk-crypto-ffi", features: "" },
25
            Package::FullSDK => PackageValues { name: "matrix-sdk-ffi", features: "sentry" },
26
        }
27
    }
28
}
29
30
#[derive(Args)]
31
pub struct KotlinArgs {
32
    #[clap(subcommand)]
33
    cmd: KotlinCommand,
34
}
35
36
#[derive(Subcommand)]
37
enum KotlinCommand {
38
    /// Builds the SDK for Android as an AAR.
39
    BuildAndroidLibrary {
40
        #[clap(value_enum, long)]
41
        package: Package,
42
43
        /// Build with the release profile
44
        #[clap(long)]
45
        release: bool,
46
47
        /// Build with a custom profile, takes precedence over `--release`
48
        #[clap(long)]
49
        profile: Option<String>,
50
51
        /// Build the given target only
52
        #[clap(long)]
53
        only_target: Option<String>,
54
55
        /// Move the generated files into the given src directory
56
        #[clap(long)]
57
        src_dir: Utf8PathBuf,
58
    },
59
}
60
61
impl KotlinArgs {
62
    pub fn run(self) -> Result<()> {
63
        let sh = sh();
64
        let _p = sh.push_dir(workspace::root_path()?);
65
66
        match self.cmd {
67
            KotlinCommand::BuildAndroidLibrary {
68
                release,
69
                profile,
70
                src_dir,
71
                only_target,
72
                package,
73
            } => {
74
                let profile = profile.as_deref().unwrap_or(if release { "release" } else { "dev" });
75
                build_android_library(profile, only_target, &src_dir, package)
76
            }
77
        }
78
    }
79
}
80
81
fn build_android_library(
82
    profile: &str,
83
    only_target: Option<String>,
84
    src_dir: &Utf8Path,
85
    package: Package,
86
) -> Result<()> {
87
    let package_values = package.values();
88
    let package_name = package_values.name;
89
    let package_features = package_values.features;
90
91
    let jni_libs_dir = src_dir.join("jniLibs");
92
    let jni_libs_dir_str = jni_libs_dir.as_str();
93
94
    let kotlin_generated_dir = src_dir.join("kotlin");
95
    create_dir_all(kotlin_generated_dir.clone())?;
96
97
    let uniffi_lib_path = if let Some(target) = only_target {
98
        println!("-- Building for {target} [1/1]");
99
        build_for_android_target(
100
            target.as_str(),
101
            profile,
102
            jni_libs_dir_str,
103
            package_name,
104
            package_features,
105
        )?
106
    } else {
107
        println!("-- Building for x86_64-linux-android[1/4]");
108
        build_for_android_target(
109
            "x86_64-linux-android",
110
            profile,
111
            jni_libs_dir_str,
112
            package_name,
113
            package_features,
114
        )?;
115
        println!("-- Building for aarch64-linux-android[2/4]");
116
        build_for_android_target(
117
            "aarch64-linux-android",
118
            profile,
119
            jni_libs_dir_str,
120
            package_name,
121
            package_features,
122
        )?;
123
        println!("-- Building for armv7-linux-androideabi[3/4]");
124
        build_for_android_target(
125
            "armv7-linux-androideabi",
126
            profile,
127
            jni_libs_dir_str,
128
            package_name,
129
            package_features,
130
        )?;
131
        println!("-- Building for i686-linux-android[4/4]");
132
        build_for_android_target(
133
            "i686-linux-android",
134
            profile,
135
            jni_libs_dir_str,
136
            package_name,
137
            package_features,
138
        )?
139
    };
140
141
    println!("-- Generate uniffi files");
142
    generate_uniffi_bindings(&uniffi_lib_path, &kotlin_generated_dir)?;
143
144
    println!("-- All done and hunky dory. Enjoy!");
145
    Ok(())
146
}
147
148
fn generate_uniffi_bindings(library_path: &Utf8Path, ffi_generated_dir: &Utf8Path) -> Result<()> {
149
    println!("-- library_path = {library_path}");
150
    generate(GenerateOptions {
151
        languages: vec![TargetLanguage::Kotlin],
152
        source: library_path.to_path_buf(),
153
        out_dir: ffi_generated_dir.to_path_buf(),
154
        ..GenerateOptions::default()
155
    })?;
156
    Ok(())
157
}
158
159
fn build_for_android_target(
160
    target: &str,
161
    profile: &str,
162
    dest_dir: &str,
163
    package_name: &str,
164
    features: &str,
165
) -> Result<Utf8PathBuf> {
166
    let sh = sh();
167
    cmd!(
168
        sh,
169
        "cargo ndk --target {target} -o {dest_dir} build --profile {profile} --package {package_name} --features {features}"
170
    )
171
    .run()?;
172
173
    // The builtin dev profile has its files stored under target/debug, all
174
    // other targets have matching directory names
175
    let profile_dir_name = if profile == "dev" { "debug" } else { profile };
176
    let package_camel = package_name.replace('-', "_");
177
    let lib_name = format!("lib{package_camel}.so");
178
    Ok(workspace::target_path()?.join(target).join(profile_dir_name).join(lib_name))
179
}