xtask_lib/tasks/util/
mupdf_wrapper.rs

1//! MuPDF wrapper C library compilation helpers.
2//!
3//! Compiles `mupdf_wrapper.c` into a static library using the C compiler
4//! directly.
5//!
6//! ## Output
7//!
8//! The compiled object and static library are placed in
9//! `target/mupdf_wrapper/<target_os>/`:
10//!
11//! - `mupdf_wrapper.o`
12//! - `libmupdf_wrapper.a`
13
14use std::path::Path;
15
16use anyhow::{Context, Result};
17
18use super::cmd;
19
20/// Compiles the mupdf_wrapper C library for the native platform only if the
21/// output artifact does not already exist.
22///
23/// # Errors
24///
25/// Returns an error if compilation or archiving fails.
26pub fn build_native_if_needed(root: &Path) -> Result<()> {
27    let target_os = native_target_os();
28    let lib = native_lib_path(root, target_os);
29
30    if lib.exists() {
31        println!("mupdf_wrapper already built for {target_os}.");
32        return Ok(());
33    }
34
35    build(root, target_os, "cc", "ar", &[])
36}
37
38fn native_target_os() -> &'static str {
39    if cfg!(target_os = "macos") {
40        "Darwin"
41    } else {
42        "Linux"
43    }
44}
45
46fn native_lib_path(root: &Path, target_os: &str) -> std::path::PathBuf {
47    root.join(format!(
48        "target/mupdf_wrapper/{target_os}/libmupdf_wrapper.a"
49    ))
50}
51
52/// Compiles the mupdf_wrapper C library for the Kobo ARM target.
53///
54/// Uses the Linaro cross-compiler (`arm-linux-gnueabihf-gcc`) and
55/// `arm-linux-gnueabihf-ar`.
56///
57/// # Errors
58///
59/// Returns an error if compilation or archiving fails.
60pub fn build_kobo(root: &Path) -> Result<()> {
61    build(
62        root,
63        "Kobo",
64        "arm-linux-gnueabihf-gcc",
65        "arm-linux-gnueabihf-ar",
66        &[],
67    )
68}
69
70/// Compiles `mupdf_wrapper.c` into `libmupdf_wrapper.a`.
71///
72/// Equivalent to the shell commands:
73/// ```text
74/// $CC -I../thirdparty/mupdf/include -c mupdf_wrapper.c -o $BUILD_DIR/mupdf_wrapper.o
75/// $AR -rcs $BUILD_DIR/libmupdf_wrapper.a $BUILD_DIR/mupdf_wrapper.o
76/// ```
77///
78/// # Errors
79///
80/// Returns an error if the compiler or archiver invocation fails.
81fn build(root: &Path, target_os: &str, cc: &str, ar: &str, extra_cflags: &[&str]) -> Result<()> {
82    let wrapper_dir = root.join("mupdf_wrapper");
83    let build_dir = root.join(format!("target/mupdf_wrapper/{target_os}"));
84
85    std::fs::create_dir_all(&build_dir)
86        .with_context(|| format!("failed to create {}", build_dir.display()))?;
87
88    let include = root.join("thirdparty/mupdf/include");
89    let obj = build_dir.join("mupdf_wrapper.o");
90    let lib = build_dir.join("libmupdf_wrapper.a");
91
92    let include_flag = format!("-I{}", include.display());
93    let obj_str = obj.to_string_lossy().into_owned();
94
95    let mut compile_args = vec![
96        include_flag.as_str(),
97        "-c",
98        "mupdf_wrapper.c",
99        "-o",
100        &obj_str,
101    ];
102
103    for flag in extra_cflags {
104        compile_args.push(flag);
105    }
106
107    cmd::run(cc, &compile_args, &wrapper_dir, &[])
108        .with_context(|| format!("failed to compile mupdf_wrapper.c with {cc}"))?;
109
110    let lib_str = lib.to_string_lossy().into_owned();
111    let obj_str2 = obj.to_string_lossy().into_owned();
112
113    cmd::run(ar, &["-rcs", &lib_str, &obj_str2], &wrapper_dir, &[])
114        .with_context(|| format!("failed to archive libmupdf_wrapper.a with {ar}"))
115}