1use std::path::{Path, PathBuf};
2use std::process::Command;
3
4use ndk_build::cargo::cargo_ndk;
5use ndk_build::target::Target;
6
7use error::*;
8
9pub mod error;
10
11pub struct BuildConfig {
12 pub lib_name: String,
13 pub arch_list: Vec<String>,
14 pub is_release: bool,
15 pub target_dir: String,
16 pub project_dir: PathBuf,
17 pub sdk_version: u32,
18 pub rustc_param: String,
19 pub features_def: Vec<String>,
20}
21
22pub fn build(config: &BuildConfig) -> Result<()> {
23 println!("building android bridge project");
24
25 let ndk = ndk_build::ndk::Ndk::from_env()?;
26
27 let archs = &config.arch_list;
28
29 for arch in archs.iter() {
30 let target = Target::from_rust_triple(arch)?;
31 let mut cargo = cargo_ndk(&ndk, target, config.sdk_version)?;
32 cargo
33 .arg("rustc")
34 .arg("--target")
35 .arg(arch)
36 .arg("--lib")
37 .arg("--target-dir")
38 .arg(&config.target_dir);
39
40 if config.is_release {
41 cargo.arg("--release");
42 }
43
44 if !config.features_def.is_empty() {
45 let features = config.features_def.join(",");
46 cargo.arg("--features").arg(features);
47 }
48
49 if ndk.build_tag() > 7272597 {
56 cargo.arg("--");
57 let cargo_apk_link_dir = Path::new(&config.project_dir)
58 .join("target")
59 .join("cargo-apk-temp-extra-link-libraries");
60 std::fs::create_dir_all(&cargo_apk_link_dir)?;
61 let libgccfile = cargo_apk_link_dir.join("libgcc.a");
62 if !libgccfile.exists() {
63 std::fs::write(libgccfile, "INPUT(-lunwind)").expect("Failed to write");
64 }
65
66 cargo.arg("-L").arg(
67 PathBuf::new()
68 .join("target")
69 .join("cargo-apk-temp-extra-link-libraries"),
70 );
71
72 if !config.rustc_param.is_empty() {
73 cargo.arg(&config.rustc_param);
74 }
75 }
76
77 cargo.current_dir(&config.project_dir);
78
79 let status = cargo.status()?;
80 println!("process '{:?}' finished with: {}", cargo, status);
81
82 let debug_release = if config.is_release {
87 "release"
88 } else {
89 "debug"
90 };
91 let strip = ndk.toolchain_bin("strip", target)?;
92 let mut strip_comm = Command::new(strip);
93 let _strip_output = strip_comm
94 .arg("-s")
95 .arg(format!(
96 "{}/{}/{}/{}",
97 &config.target_dir, arch, debug_release, config.lib_name
98 ))
99 .current_dir(&config.project_dir)
100 .output()?;
101
102 let strip_status = strip_comm.status()?;
106 println!("process '{:?}' finished with: {}", strip_comm, strip_status);
107 }
108 Ok(())
109}
110
111#[cfg(test)]
112mod tests {
113 use std::path::Path;
114
115 use ndk_build::target::Target;
116
117 use crate::{build, BuildConfig};
118
119 #[test]
120 fn build_works() {
121 println!("current dir = {:?}", std::env::current_dir());
122 let config = BuildConfig {
123 lib_name: "testcode".to_string(),
124 arch_list: vec![
125 Target::Arm64V8a.rust_triple().to_owned(),
126 Target::ArmV7a.rust_triple().to_owned(),
127 Target::X86.rust_triple().to_owned(),
128 Target::X86_64.rust_triple().to_owned(),
129 ],
130 is_release: true,
131 target_dir: "target".to_string(),
132 project_dir: Path::new(".").to_path_buf(),
133 sdk_version: 21,
134 rustc_param: "--features rsbind".to_owned(),
135 features_def: vec![],
136 };
137 build(&config).unwrap()
138 }
139}