use super::prelude::*;
use regex::Regex;
use std::{fs::File, io::Read, path::Path};
pub struct Android;
const API_LEVEL: &str = "26";
impl PlatformDetails for Android {
fn uses_freetype(&self, _config: &BuildConfiguration) -> bool {
true
}
fn cmake_args(&self, config: &BuildConfiguration, builder: &mut CMakeArgsBuilder) {
let (arch, _) = config.target.arch_abi();
let ndk = ndk();
builder
.arg("ndk", quote(&ndk))
.arg("ndk_api", API_LEVEL)
.arg("target_cpu", quote(clang::target_arch(arch)))
.arg("skia_enable_fontmgr_android", yes());
let major = ndk_major_version(Path::new(&ndk));
let mut extra_skia_cflags = extra_skia_cflags();
if major >= 23 && arch == "aarch64" {
extra_skia_cflags.push("-mno-outline-atomics".to_string());
}
builder.cflags(extra_skia_cflags);
}
fn bindgen_args(&self, target: &Target, builder: &mut BindgenArgsBuilder) {
builder.args(additional_clang_args(
&target.to_string(),
&target.architecture,
));
}
fn link_libraries(&self, features: &Features) -> Vec<String> {
link_libraries(features)
.iter()
.map(|l| l.to_string())
.collect()
}
fn filter_platform_features(
&self,
_use_system_libraries: bool,
features: Features,
) -> Features {
features
}
}
fn ndk() -> String {
cargo::env_var("ANDROID_NDK_HOME").expect("ANDROID_NDK_HOME variable not set")
}
fn host_tag() -> String {
if cfg!(target_os = "windows") {
"windows-x86_64"
} else if cfg!(target_os = "linux") {
"linux-x86_64"
} else if cfg!(target_os = "macos") {
"darwin-x86_64"
} else {
panic!("host os is not supported")
}
.to_string()
}
fn ndk_major_version(ndk_dir: &Path) -> u32 {
let re = Regex::new(r"Pkg.Revision = (\d+)\.(\d+)\.(\d+)").unwrap();
let mut source_properties =
File::open(ndk_dir.join("source.properties")).expect("Couldn't open source.properties");
let mut buf = "".to_string();
source_properties
.read_to_string(&mut buf)
.expect("Could not read source.properties");
let captures = re
.captures(&buf)
.expect("source.properties did not match the regex");
captures[1].parse().expect("could not parse major version")
}
pub fn additional_clang_args(target: &str, target_arch: &str) -> Vec<String> {
let mut args: Vec<String> = Vec::new();
match target_arch {
"i686" => args.push("-m32".into()),
"x86_64" => args.push("-m64".into()),
_ => {}
};
let ndk = ndk();
let major = ndk_major_version(Path::new(&ndk));
if major < 22 {
args.push(format!("--sysroot={ndk}/sysroot"));
args.push(format!("-isystem{ndk}/sources/cxx-stl/llvm-libc++/include"));
} else {
let host_toolchain = format!("{}/toolchains/llvm/prebuilt/{}", ndk, host_tag());
args.push(format!("--sysroot={host_toolchain}/sysroot"));
};
args.push(format!("-I{ndk}/sources/android/cpufeatures"));
args.push(format!("--target={target}"));
args.extend(extra_skia_cflags());
args
}
pub fn extra_skia_cflags() -> Vec<String> {
vec![format!("-D__ANDROID_API__={API_LEVEL}")]
}
pub fn link_libraries(_features: &Features) -> Vec<&str> {
let libs = vec!["log", "android", "c++_shared", "c++abi"];
libs
}