polyhorn_cli/android/tasks/
build_runtime_library.rs

1use std::fs::{create_dir_all, read_dir};
2
3use super::{AndroidContext, AndroidError};
4use crate::android::Target;
5use crate::core::{CargoBuild, Manager, Task};
6
7/// This tasks builds the runtime library for the given target and with the
8/// given profile.
9pub struct BuildRuntimeLibrary {
10    /// The target ABI to compile for.
11    pub target: Target<'static>,
12
13    /// The profile to pass to Cargo, e.g. `debug` or `release`.
14    pub profile: &'static str,
15}
16
17impl BuildRuntimeLibrary {
18    fn setup_env(&self, context: &AndroidContext) -> Result<(), AndroidError> {
19        // We start by locating the toolchain within ndk-bundle.
20        let mut toolchain = context.android_sdk_root.clone().unwrap();
21        toolchain.push("ndk-bundle/toolchains/llvm/prebuilt");
22
23        let toolchain = match read_dir(&toolchain) {
24            Ok(mut dir) => match dir.next() {
25                Some(Ok(entry)) => entry.path(),
26                _ => return Err(AndroidError::AndroidNDKNotFound(toolchain)),
27            },
28            Err(_) => return Err(AndroidError::AndroidNDKNotFound(toolchain)),
29        };
30
31        // And we ask downstream crates that use `polyhorn-build-android` to
32        // store the jars that bundle their "native code" into the `lib` folder
33        // of our Android source tree.
34        let mut polyhorn_jar_dir = context.config.target_dir.clone();
35        polyhorn_jar_dir.push("polyhorn-android/app/libs");
36
37        let _ = create_dir_all(&polyhorn_jar_dir);
38
39        if let Some(android_sdk_root) = context.android_sdk_root.as_ref() {
40            std::env::set_var("ANDROID_SDK_ROOT", android_sdk_root);
41        }
42
43        if let Some(java_home) = context.java_home.as_ref() {
44            std::env::set_var("JAVA_HOME", java_home);
45        }
46
47        let mut sysroot = toolchain.to_path_buf();
48        sysroot.push("sysroot");
49
50        let mut toolchain = toolchain.to_path_buf();
51        toolchain.push("bin");
52
53        let mut ar = toolchain.to_path_buf();
54        ar.push(&self.target.ar);
55
56        let mut cc = toolchain.to_path_buf();
57        cc.push(&self.target.cc);
58
59        let mut cxx = toolchain.to_path_buf();
60        cxx.push(&self.target.cxx);
61
62        let mut linker = toolchain.to_path_buf();
63        linker.push(&self.target.linker);
64
65        std::env::set_var("TARGET_AR", ar);
66        std::env::set_var("TARGET_CC", cc);
67        std::env::set_var("TARGET_CXX", cxx);
68        std::env::set_var("POLYHORN_JAR_DIR", polyhorn_jar_dir);
69        std::env::set_var(
70            "CARGO_TARGET_".to_owned()
71                + &self.target.llvm_triple.replace("-", "_").to_uppercase()
72                + "_LINKER",
73            linker,
74        );
75
76        std::env::set_var(
77            "BINDGEN_EXTRA_CLANG_ARGS",
78            format!("--sysroot={}", sysroot.to_str().unwrap()),
79        );
80
81        std::env::set_var(
82            format!(
83                "CARGO_TARGET_{}_RUSTFLAGS",
84                self.target.llvm_triple.to_uppercase().replace("-", "_")
85            ),
86            "-Clink-arg=-lc++_static -Clink-arg=-lc++abi -Clink-arg=-fuse-ld=lld",
87        );
88
89        Ok(())
90    }
91}
92
93impl Task for BuildRuntimeLibrary {
94    type Context = AndroidContext;
95    type Error = AndroidError;
96
97    fn verb(&self) -> &str {
98        "Building"
99    }
100
101    fn message(&self) -> &str {
102        "runtime library"
103    }
104
105    fn detail(&self) -> &str {
106        "for Android"
107    }
108
109    fn run(
110        &self,
111        mut context: AndroidContext,
112        _manager: &mut Manager,
113    ) -> Result<AndroidContext, AndroidError> {
114        eprintln!("");
115
116        self.setup_env(&context)?;
117
118        let name = CargoBuild::new(&context.config.manifest_dir.join("Cargo.toml"))
119            .crate_type("cdylib")
120            .release(self.profile == "release")
121            .target(self.target.llvm_triple)
122            .build()?;
123
124        context.products.insert(
125            self.target.abi.to_owned(),
126            context.config.manifest_dir.join(format!(
127                "target/{}/{}/lib{}.so",
128                self.target.llvm_triple, self.profile, name
129            )),
130        );
131
132        Ok(context)
133    }
134}