futhark-bindgen 0.2.8

Futhark binding generator
Documentation
use futhark_bindgen::*;

use argh::FromArgs;

fn parse_backend(s: &str) -> Result<Backend, String> {
    let mut s = s.to_string();
    s.make_ascii_lowercase();
    let x = serde_json::from_str(&format!("\"{}\"", s)).expect("Invalid backend");
    Ok(x)
}

#[derive(Debug, FromArgs)]
#[argh(description = "futhark binding generator")]
struct Main {
    #[argh(subcommand)]
    command: Commands,
}

#[derive(Debug, FromArgs)]
#[argh(subcommand)]
enum Commands {
    Run(Run),
    Libs(Libs),
}

#[derive(Debug, FromArgs)]
#[argh(
    name = "libs",
    description = "List libraries for the selected backend",
    subcommand
)]

struct Libs {
    #[argh(
        option,
        default = "Backend::C",
        from_str_fn(parse_backend),
        description = "futhark backend: c, cuda, opencl, multicore"
    )]
    backend: Backend,
}

#[derive(Debug, FromArgs)]
#[argh(name = "run", description = "generate bindings", subcommand)]
struct Run {
    #[argh(positional, description = "futhark input file")]
    input: std::path::PathBuf,

    #[argh(positional, description = "output file")]
    output: std::path::PathBuf,

    #[argh(
        option,
        default = "Backend::C",
        from_str_fn(parse_backend),
        description = "futhark backend: c, cuda, opencl, multicore"
    )]
    backend: Backend,

    #[argh(option, description = "path to futhark compiler")]
    compiler: Option<String>,

    #[argh(
        option,
        long = "futhark-arg",
        short = 'f',
        description = "arguments to be passed to the futhark compiler"
    )]
    futhark_args: Vec<String>,
}

fn main() -> Result<(), Error> {
    let args: Main = argh::from_env();

    match args.command {
        Commands::Run(mut args) => {
            if args.output.is_relative() {
                args.output = std::path::PathBuf::from(".").join(args.output);
            }
            let out_dir = args.output.parent().unwrap().canonicalize().unwrap();
            let mut compiler = Compiler::new(args.backend, &args.input)
                .with_extra_args(args.futhark_args)
                .with_output_dir(out_dir);
            if let Some(exe) = args.compiler {
                compiler = compiler.with_executable_name(exe);
            }
            let pkg = compiler.compile()?;
            let mut config = Config::new(args.output)?;
            let mut gen = config.detect().expect("Unable to detect output language");
            gen.generate(&pkg, &mut config)?;
        }
        Commands::Libs(args) => {
            args.backend
                .required_c_libs()
                .iter()
                .for_each(|x| print!("-l{x} "));
            println!();
        }
    }

    Ok(())
}