Skip to main content

xtask_lib/tasks/
build_kobo.rs

1//! `cargo xtask build-kobo` — cross-compile Cadmus for Kobo devices.
2//!
3//! This task is a thin wrapper around `cargo build --release
4//! --target arm-unknown-linux-gnueabihf -p cadmus`. Most dependency
5//! building (thirdparty libs, MuPDF, libwebp, mupdf_wrapper) is
6//! handled automatically by `build.rs` when cargo build runs.
7//!
8//! In addition, `run()` performs these eager preflight steps
9//! before invoking cargo:
10//!
11//! 1. Verify the Linaro ARM toolchain (`arm-linux-gnueabihf-gcc`)
12//!    is on `PATH`.
13//! 2. Initialize git submodules.
14//! 3. Build SQLite from source with UDL support for the ARM target
15//!    (placed in `target/cadmus-build-deps/arm-unknown-linux-gnueabihf/sqlite/`).
16//!
17//! The Kobo build is only available on Linux and macOS hosts.
18
19use anyhow::{Context, Result, bail};
20use clap::Args;
21
22use build_deps::build::sqlite;
23use build_deps::versions::CROSS_ENV;
24
25use super::util::{cmd, workspace};
26
27/// Arguments for `cargo xtask build-kobo`.
28#[derive(Debug, Args)]
29pub struct BuildKoboArgs {
30    /// Cargo feature flags to pass to the Cadmus build (e.g. `test`).
31    #[arg(long)]
32    pub features: Option<String>,
33}
34
35/// Cross-compiles Cadmus for Kobo ARM devices.
36///
37/// # Errors
38///
39/// Returns an error if:
40/// - The host platform is not Linux or macOS.
41/// - The Linaro ARM toolchain is not on `PATH`.
42/// - The underlying `cargo build` invocation fails.
43///
44/// The `ensure_submodules` and `ensure_sqlite` preflight steps run
45/// eagerly so that `libs/` and `target/cadmus-build-deps/...` are
46/// populated before `cargo build` starts.
47pub fn run(args: BuildKoboArgs) -> Result<()> {
48    if !cfg!(any(target_os = "linux", target_os = "macos")) {
49        bail!(
50            "Kobo cross-compilation is only available on Linux and macOS.\n\
51             On other platforms, please use Docker or a Linux VM instead."
52        );
53    }
54
55    let root = workspace::root()?;
56
57    ensure_linaro_toolchain()?;
58
59    build_deps::ensure_submodules(&root).context("failed to initialise git submodules")?;
60    sqlite::ensure_sqlite(&root, sqlite::KOBO_TARGET).context("failed to build SQLite for Kobo")?;
61
62    cargo_build_kobo(&root, args.features.as_deref())?;
63
64    Ok(())
65}
66
67fn ensure_linaro_toolchain() -> Result<()> {
68    cmd::run(
69        "arm-linux-gnueabihf-gcc",
70        &["--version"],
71        std::path::Path::new("."),
72        &[],
73    )
74    .map_err(|_| {
75        anyhow::anyhow!(
76            "arm-linux-gnueabihf-gcc not found on PATH.\n\
77             Install the Linaro toolchain or run inside the devenv shell."
78        )
79    })
80}
81
82fn cargo_build_kobo(root: &std::path::Path, features: Option<&str>) -> Result<()> {
83    let mut cargo_args = vec![
84        "build",
85        "--release",
86        "--target",
87        "arm-unknown-linux-gnueabihf",
88        "-p",
89        "cadmus",
90    ];
91
92    if let Some(f) = features {
93        cargo_args.push("--features");
94        cargo_args.push(f);
95    }
96
97    cmd::run("cargo", &cargo_args, root, CROSS_ENV)
98}
99
100#[cfg(test)]
101mod tests {
102    #[test]
103    fn symlink_list_has_no_duplicates() {
104        let mut link_names: Vec<&str> = build_deps::versions::SONAMES.to_vec();
105        link_names.sort_unstable();
106        let original_len = link_names.len();
107        link_names.dedup();
108        assert_eq!(link_names.len(), original_len, "duplicate link names found");
109    }
110}