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`. All dependency
5//! building (thirdparty libs, MuPDF, libwebp, mupdf_wrapper) is
6//! handled automatically by `build.rs` when cargo build runs.
7//!
8//! Pre-flight steps performed before invoking cargo:
9//!
10//! 1. Verify the Linaro ARM toolchain (`arm-linux-gnueabihf-gcc`)
11//!    is on `PATH`.
12//!
13//! Git submodules are not initialised up-front here: the Rust build
14//! script clones them lazily, only when the cached Kobo build
15//! artefacts in `libs/` and `target/cadmus-build-deps/...` are
16//! missing. This keeps warm-cache CI runs fast by avoiding the
17//! recursive submodule clone done by `actions/checkout`.
18//!
19//! The Kobo build is only available on Linux and macOS hosts.
20
21use anyhow::{Result, bail};
22use clap::Args;
23
24use build_deps::versions::CROSS_ENV;
25
26use super::util::{cmd, workspace};
27
28/// Arguments for `cargo xtask build-kobo`.
29#[derive(Debug, Args)]
30pub struct BuildKoboArgs {
31    /// Cargo feature flags to pass to the Cadmus build (e.g. `test`).
32    #[arg(long)]
33    pub features: Option<String>,
34}
35
36/// Cross-compiles Cadmus for Kobo ARM devices.
37///
38/// # Errors
39///
40/// Returns an error if:
41/// - The host platform is not Linux or macOS.
42/// - The Linaro ARM toolchain is not on `PATH`.
43/// - The underlying `cargo build` invocation fails.
44///
45/// Git submodules are initialised lazily by the Rust build script
46/// when the cached Kobo artefacts are missing; this task no longer
47/// triggers a recursive submodule clone unconditionally.
48pub fn run(args: BuildKoboArgs) -> Result<()> {
49    if !cfg!(any(target_os = "linux", target_os = "macos")) {
50        bail!(
51            "Kobo cross-compilation is only available on Linux and macOS.\n\
52             On other platforms, please use Docker or a Linux VM instead."
53        );
54    }
55
56    let root = workspace::root()?;
57
58    ensure_linaro_toolchain()?;
59
60    cargo_build_kobo(&root, args.features.as_deref())?;
61
62    Ok(())
63}
64
65fn ensure_linaro_toolchain() -> Result<()> {
66    cmd::run(
67        "arm-linux-gnueabihf-gcc",
68        &["--version"],
69        std::path::Path::new("."),
70        &[],
71    )
72    .map_err(|_| {
73        anyhow::anyhow!(
74            "arm-linux-gnueabihf-gcc not found on PATH.\n\
75             Install the Linaro toolchain or run inside the devenv shell."
76        )
77    })
78}
79
80fn cargo_build_kobo(root: &std::path::Path, features: Option<&str>) -> Result<()> {
81    let mut cargo_args = vec![
82        "build",
83        "--release",
84        "--target",
85        "arm-unknown-linux-gnueabihf",
86        "-p",
87        "cadmus",
88    ];
89
90    if let Some(f) = features {
91        cargo_args.push("--features");
92        cargo_args.push(f);
93    }
94
95    cmd::run("cargo", &cargo_args, root, CROSS_ENV)
96}
97
98#[cfg(test)]
99mod tests {
100    #[test]
101    fn symlink_list_has_no_duplicates() {
102        let mut link_names: Vec<&str> = build_deps::versions::SONAMES.to_vec();
103        link_names.sort_unstable();
104        let original_len = link_names.len();
105        link_names.dedup();
106        assert_eq!(link_names.len(), original_len, "duplicate link names found");
107    }
108}