pappl-sys 0.1.0

Raw bindgen FFI bindings for PAPPL, the Printer Application Programming Library
use std::env;
use std::path::PathBuf;

fn main() {
    // PAPPL ≥1.0 floor: a clear pkg-config failure beats a cryptic
    // "undefined symbol" later. 1.4+ APIs (e.g. papplSystemCreatePrinters)
    // are guarded by wrappers in lib.rs, so older PAPPL still links.
    let pappl = pkg_config::Config::new()
        .atleast_version("1.0")
        .probe("pappl")
        .expect("pkg-config: pappl not found (need ≥1.0)");
    let cups = pkg_config::probe_library("cups").expect("pkg-config: cups not found");

    let mut builder = bindgen::Builder::default()
        .header("wrapper.h")
        .allowlist_type("pappl_.*")
        .allowlist_type("cups_option_t")
        .allowlist_type("cups_page_header2_t")
        .allowlist_type("ipp_t")
        .allowlist_type("ipp_orient_t")
        .allowlist_type("ipp_quality_t")
        .allowlist_function("pappl.*")
        .allowlist_var("PAPPL_.*")
        .allowlist_var("IPP_ORIENT_.*")
        .allowlist_var("IPP_QUALITY_.*")
        // Keep PAPPL's private `_pappl_*_s` structs opaque so we don't pull
        // half the C internals into the generated bindings.
        .opaque_type("_pappl_.*_s")
        .derive_default(true)
        // Suppress C-header doc comments; they're noise in rustdoc and
        // sometimes don't parse cleanly.
        .generate_comments(false);

    for path in pappl.include_paths.iter().chain(cups.include_paths.iter()) {
        builder = builder.clang_arg(format!("-I{}", path.display()));
    }

    let bindings = builder.generate().expect("bindgen failed");

    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("failed to write bindings");

    // `cargo:rustc-cfg` applies only to this crate; dependents can't see it.
    // They call the `try_system_create_printers` wrapper in lib.rs instead.
    println!("cargo:rustc-check-cfg=cfg(pappl_1_4)");
    {
        let parts: Vec<u32> = pappl
            .version
            .split('.')
            .filter_map(|s: &str| s.parse().ok())
            .collect();
        let (major, minor) = (
            parts.first().copied().unwrap_or(0),
            parts.get(1).copied().unwrap_or(0),
        );
        if major > 1 || (major == 1 && minor >= 4) {
            println!("cargo:rustc-cfg=pappl_1_4");
        }
    }
}