Skip to content

jesse-anderson/xllgen

Repository files navigation

xllgen

Proc-macro helpers for generating Excel XLL wrappers using xll-rs.

Status

Working WIP. Macros generate wrappers, registration, and optional manifest helpers.

Type mapping spec: see TYPE_MAPPING.md.

Quick Start

use xllgen::{xll_bindgen, xll_auto_open};
use xll_rs::types::{XllError, XLLError};

#[xll_bindgen]
pub fn add(a: f64, b: f64) -> f64 {
    a + b
}

#[xll_bindgen(name = "MEAN", args = "a, b", help = "Average of two numbers")]
pub fn mean(a: f64, b: f64) -> f64 {
    (a + b) / 2.0
}

#[xll_bindgen(name = "SCI.SCALE", threadsafe, category = "xllgen")]
pub fn scale(x: f64, factor: f64) -> f64 {
    x * factor
}

#[xll_bindgen]
pub fn must_be_positive(x: f64) -> Result<f64, XllError> {
    if x < 0.0 {
        return Err(XllError::msg(XLLError::VALUE, "x must be >= 0"));
    }
    Ok(x)
}

xll_auto_open!();

Native .xll Output (No Renaming)

Add a build.rs in your XLL crate:

fn main() {
    let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
    if target_os != "windows" {
        return;
    }

    let target_env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
    if target_env != "msvc" {
        println!("cargo:warning=Non-MSVC toolchain detected; .xll output rename is not configured.");
        return;
    }

    let manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
    let profile = std::env::var("PROFILE").unwrap_or_else(|_| "debug".to_string());
    let target_dir = std::env::var("CARGO_TARGET_DIR")
        .map(std::path::PathBuf::from)
        .unwrap_or_else(|_| manifest_dir.join("target"));
    let out = target_dir.join(&profile).join("your_crate_name.xll");

    println!("cargo:rustc-cdylib-link-arg=/OUT:{}", out.display());
}

This emits target/<profile>/<your_crate_name>.xll on every build.

Naming Defaults

  • Prefix defaults to the crate name (uppercased) and can be overridden:
    • xll_auto_open!(prefix = "SCI")
  • If no name is provided, the Excel name defaults to:
    • PREFIX.<RUST_FN_NAME> (uppercased)
  • If name = "FOO" (no dot), it becomes PREFIX.FOO.
  • If name = "PREFIX.FOO", it is treated as fully qualified.

Custom Errors

Return Result<T, XllError>:

  • XllError::new(XLLError::VALUE) -> returns #VALUE!
  • XllError::msg(XLLError::VALUE, "bad input") -> returns "bad input" (string)
  • "VALUE: bad input".into() is also supported

Excel cells can display an error or a string message, not both.

Optional Export Manifest

xll_auto_open!(manifest = "json") generates:

  • xllgen_exports() -> slice of XllExport
  • xllgen_exports_json() -> JSON string

Registration Diagnostics

xll_auto_open! always registers XLLGEN.REG_ERRORS:

  • Returns OK or a ;-separated list of failed registrations.
  • Use strict to fail xlAutoOpen if any registration fails:
xll_auto_open!(strict);
// or
xll_auto_open!(strict = true);

XLLGEN.REG_ERRORS is a reserved name. You can disable it:

xll_auto_open!(reg_errors = false);

About

Proc-macro toolkit for generating Excel XLL wrappers in Rust.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages