Skip to content

Commit

Permalink
add standalone option to compiler functions
Browse files Browse the repository at this point in the history
  • Loading branch information
martinjrobins committed Sep 6, 2023
1 parent a8e78e5 commit 6758f9c
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 36 deletions.
13 changes: 11 additions & 2 deletions src/bin/diffeq.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use clap::Parser;
use anyhow::Result;
use diffeq::compile;
use diffeq::{compile, CompilerOptions};

/// compiles a model in continuous (.cs) or discrete (.ds) format to an object file
#[derive(Parser, Debug)]
Expand All @@ -24,10 +24,19 @@ struct Args {
/// Compile to WASM
#[arg(short, long)]
wasm: bool,

/// Compile to standalone executable
#[arg(short, long)]
standalone: bool,
}

fn main() -> Result<()> {
let cli = Args::parse();
compile(&cli.input, cli.out.as_deref(), cli.model.as_deref(), cli.compile, cli.wasm)
let options = CompilerOptions {
compile: cli.compile,
wasm: cli.wasm,
standalone: cli.standalone,
};
compile(&cli.input, cli.out.as_deref(), cli.model.as_deref(), options)
}

115 changes: 81 additions & 34 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,14 @@ pub mod discretise;
pub mod continuous;
pub mod codegen;

pub struct CompilerOptions {
pub compile: bool,
pub wasm: bool,
pub standalone: bool,
}


pub fn compile(input: &str, out: Option<&str>, model: Option<&str>, compile: bool, wasm: bool) -> Result<()> {
pub fn compile(input: &str, out: Option<&str>, model: Option<&str>, options: CompilerOptions) -> Result<()> {
let inputfile = Path::new(input);
let is_discrete = inputfile.extension().unwrap_or(OsStr::new("")).to_str().unwrap() == "ds";
let is_continuous = inputfile.extension().unwrap_or(OsStr::new("")).to_str().unwrap() == "cs";
Expand All @@ -32,18 +38,20 @@ pub fn compile(input: &str, out: Option<&str>, model: Option<&str>, compile: boo
} else {
inputfile.file_stem().unwrap().to_str().unwrap()
};
let text = std::fs::read_to_string(inputfile)?;
compile_text(text.as_str(), out, model_name, compile, wasm, is_discrete)
}

pub fn compile_text(text: &str, out: Option<&str>, model_name: &str, compile: bool, wasm: bool, is_discrete: bool) -> Result<()> {
let out = if let Some(out) = out {
out.clone()
} else if compile {
} else if options.compile {
"out.o"
} else {
"out"
};
let text = std::fs::read_to_string(inputfile)?;
compile_text(text.as_str(), out, model_name, options, is_discrete)
}

pub fn compile_text(text: &str, out: &str, model_name: &str, options: CompilerOptions, is_discrete: bool) -> Result<()> {
let CompilerOptions { compile, wasm, standalone } = options;

let is_continuous = !is_discrete;

let objectname = if compile { out.to_owned() } else { format!("{}.o", out) };
Expand Down Expand Up @@ -101,55 +109,94 @@ pub fn compile_text(text: &str, out: Option<&str>, model_name: &str, compile: bo
return Ok(());
}

let command_name = if wasm { "emcc" } else { "clang" };


// link the object file and our runtime library
let output = if wasm {
let exported_functions = vec![
"Vector_destroy",
"Vector_create",
"Vector_create_with_capacity",
"Vector_push",

"Options_destroy",
"Options_create",

"Sundials_destroy",
"Sundials_create",
"Sundials_init",
"Sundials_solve",
];
let mut linked_files = vec![
"libdiffeq_runtime_lib_wasm.a",
"libsundials_idas_wasm.a",
"libargparse_wasm.a",
];
if standalone {
linked_files.push("libdiffeq_runtime_wasm.a");
}
let linked_files = linked_files;
let library_paths_env = env::var("LIBRARY_PATH").unwrap_or("".to_owned());
let library_paths = library_paths_env.split(":").collect::<Vec<_>>();
let mut runtime_path = None;
for path in library_paths {
println!("checking {}", path);
// check if the library path contains the runtime library
let runtime_path_test = Path::new(path).join("libdiffeq_runtime_wasm.a");
if runtime_path_test.exists() {
let all_exist = linked_files.iter().all(|file| {
let file_path = Path::new(path).join(file);
file_path.exists()
});
if all_exist {
runtime_path = Some(path);
}
};
if runtime_path.is_none() {
return Err(anyhow!("Could not find libdiffeq_runtime_wasm.a in LIBRARY_PATH"));
return Err(anyhow!("Could not find {:?} in LIBRARY_PATH", linked_files));
}
let runtime_path = runtime_path.unwrap();
let runtime_file = Path::new(runtime_path).join("libdiffeq_runtime_wasm.a");
let runtime_lib_file = Path::new(runtime_path).join("libdiffeq_runtime_lib_wasm.a");
let sundials_lib_file = Path::new(runtime_path).join("libsundials_idas_wasm.a");
let argparse_lib_file = Path::new(runtime_path).join("libargparse_wasm.a");
Command::new("emcc")
.arg("-o")
.arg(out)
.arg(objectname.clone())
.arg(runtime_file)
.arg(runtime_lib_file)
.arg(sundials_lib_file)
.arg(argparse_lib_file)
.output()?
println!("using runtime path {}", runtime_path);
let mut command = Command::new(command_name);
command.arg("-o").arg(out).arg(objectname.clone());
for file in linked_files {
command.arg(Path::new(runtime_path).join(file));
}
if !standalone {
let exported_functions = exported_functions.into_iter().map(|s| format!("_{}", s)).collect::<Vec<_>>().join(",");
command.arg("-s").arg(format!("EXPORTED_FUNCTIONS={}", exported_functions));
command.arg("--no-entry");
}
command.output()
} else {
Command::new("clang")
.arg("-o")
.arg(out)
.arg(objectname.clone())
.arg("-ldiffeq_runtime")
.output()?
let mut command = Command::new(command_name);
command.arg("-o").arg(out).arg(objectname.clone());
if standalone {
command.arg("-ldiffeq_runtime");
} else {
command.arg("-ldiffeq_runtime_lib");
}
command.output()
};

let output = match output {
Ok(output) => output,
Err(e) => {
return Err(anyhow!("Error running {}: {}", command_name, e));
}
};


// clean up the object file
std::fs::remove_file(objectfile)?;

if let Some(code) = output.status.code() {
if code != 0 {
println!("{}", String::from_utf8_lossy(&output.stderr));
return Err(anyhow!("clang returned error code {}", code));
return Err(anyhow!("{} returned error code {}", command_name, code));
}
}

println!("Compiled to {:?}", output);

// clean up the object file
std::fs::remove_file(objectfile)?;

Ok(())
}

Expand Down

0 comments on commit 6758f9c

Please sign in to comment.