extern crate bindgen;
extern crate clang_sys;
extern crate libc;
use std::env;
use std::ffi::{CStr, CString};
use std::fs::{remove_file, File};
use std::io::Write;
use std::path::PathBuf;
use clang_sys::*;
use libc::c_void;
fn main() {
println!("cargo:rerun-if-changed=wrapper.h");
let bindings = bindgen::Builder::default()
.header("wrapper.h")
.whitelist_type("jmp_buf")
.whitelist_type("sigjmp_buf")
.parse_callbacks(Box::new(bindgen::CargoCallbacks))
.generate()
.expect("Unable to generate bindings");
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
bindings
.write_to_file(out_path.join("jmpbuf.rs"))
.expect("Couldn't write bindings!");
let c_file_path = out_path.join("find_symbols.c");
let mut c_file = File::create(&c_file_path).unwrap();
c_file.write_all(&c_contents()).unwrap();
let symbols = find_symbols(&c_file_path);
remove_file(&c_file_path).unwrap();
let mut file = File::create(out_path.join("decls.rs")).unwrap();
file.write_all(&decls_contents(symbols)).unwrap();
}
fn find_symbols(filename: &PathBuf) -> Vec<String> {
let mut vec: Vec<String> = Vec::new();
unsafe {
let filename_cstr = CString::new(filename.to_str().unwrap()).unwrap();
let index = clang_createIndex(0, 0);
let tu = clang_parseTranslationUnit(
index,
filename_cstr.as_ptr(),
std::ptr::null_mut(),
0,
std::ptr::null_mut(),
0,
CXTranslationUnit_None,
);
let cursor = clang_getTranslationUnitCursor(tu);
clang_visitChildren(cursor, visitor, &mut vec as *mut Vec<String> as *mut c_void);
}
assert!(vec.len() == 4);
vec
}
extern "C" fn visitor(
cursor: CXCursor,
_parent: CXCursor,
client_data: CXClientData,
) -> CXChildVisitResult {
unsafe {
let symbols: &mut Vec<String> = &mut *(client_data as *mut Vec<String>);
let cursor_name = clang_getCursorSpelling(cursor);
let cursor_cstr = CStr::from_ptr(clang_getCString(cursor_name));
let cursor_str = cursor_cstr.to_str().unwrap();
let cursorkind: CXCursorKind = clang_getCursorKind(cursor);
if cursorkind == CXCursor_CallExpr {
symbols.push(cursor_str.to_string());
}
}
CXChildVisit_Recurse
}
fn c_contents() -> Vec<u8> {
return r###"
#include <setjmp.h>
int find_symbols()
{
jmp_buf jmpbuf;
sigjmp_buf sigjmpbuf;
setjmp(jmpbuf);
sigsetjmp(sigjmpbuf, 0);
longjmp(jmpbuf, 1);
siglongjmp(sigjmpbuf, 1);
}
"###
.as_bytes()
.to_vec();
}
fn decls_contents(symbols: Vec<String>) -> Vec<u8> {
return format!(
r###"
extern "C" {{
#[link_name="{}"]
pub fn setjmp(env: *mut jmp_buf) -> c_int;
#[link_name="{}"]
pub fn sigsetjmp(env: *mut sigjmp_buf, savesigs: c_int) -> c_int;
#[link_name="{}"]
pub fn longjmp(env: *mut jmp_buf, val: c_int) -> !;
#[link_name="{}"]
pub fn siglongjmp(env: *mut sigjmp_buf, val: c_int) -> !;
}}
"###,
symbols[0], symbols[1], symbols[2], symbols[3]
)
.as_bytes()
.to_vec();
}