Skip to content

Commit

Permalink
Add new bindgen options to generate wrappers for inline functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Gopa Kumar committed May 22, 2023
1 parent 63b8713 commit 34a29e5
Show file tree
Hide file tree
Showing 2 changed files with 142 additions and 4 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,10 @@ build-time = "0.1" # For esp_app_desc!()
const_format = "0.2" # For esp_app_desc!()

[build-dependencies]
embuild = { version = "0.31.2", features = ["glob", "kconfig"] }
embuild = { git = "https://github.com/gopakumarce/embuild.git", branch = "gopa-inline_fns", features = ["glob", "kconfig"] }
anyhow = "1"
regex = "1.5"
bindgen = "0.63"
bindgen = { version = "0.65.1", features = ["experimental"] }
cargo_metadata = "0.15"
serde = { version = "1.0", features = ["derive"] }
strum = { version = "0.24", features = ["derive"] }
Expand Down
142 changes: 140 additions & 2 deletions build/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@
compile_error!("One of the features `pio` or `native` must be selected.");
use std::iter::once;

use crate::native::cargo_driver::chip::Chip;
use anyhow::*;
use bindgen::callbacks::{IntKind, ParseCallbacks};
use common::*;
use embuild::bindgen::BindgenExt;
use embuild::utils::OsStrExt;
use embuild::{bindgen as bindgen_utils, build, cargo, kconfig, path_buf};
use std::fs::File;
use std::io::BufReader;
use std::io::{BufRead, Write};
use std::str::FromStr;

mod common;
mod config;
Expand Down Expand Up @@ -48,6 +53,132 @@ impl ParseCallbacks for BindgenCallbacks {
}
}

const STATIC_INLINE: &str = "static_inlines";

fn static_inlines_c() -> String {
format!("{}.c", STATIC_INLINE)
}

fn static_inlines_o() -> String {
format!("{}.o", STATIC_INLINE)
}

fn static_inlines_tmp() -> String {
format!("{}_tmp.c", STATIC_INLINE)
}

fn static_inlines_a() -> String {
format!("lib{}.a", STATIC_INLINE)
}

// TODO: The symbols from the components/esp_rom/<mcu>/ld are hard coded
// addresses resolved during link time, rust linker cant find those symbols
// and hence the inlines that depend on those dont work. Ignore them for now
const IGNORE_STATIC_INLINES: [&str; 3] = [
"_xtos_interrupt_enable__extern",
"_xtos_interrupt_disable__extern",
"esp_cpu_intr_get_handler_arg__extern",
];

fn strip_quotes(args: &str) -> Vec<String> {
let mut out = vec![];
for arg in args.split_whitespace() {
let mut chars = arg.chars();
let first = chars.next();
chars.next_back();
let trim = if first == Some('\"') {
chars.as_str()
} else {
arg
};
out.push(trim.to_string());
}
out
}

fn ignore_api(api: &str) -> bool {
for ignore in IGNORE_STATIC_INLINES.iter() {
if api.contains(ignore) {
return true;
}
}
false
}

fn process_static_inlines(
build_output_args: &str,
clang_args: Vec<String>,
mcu: &str,
headers: Vec<std::path::PathBuf>,
) -> anyhow::Result<()> {
let chip = Chip::from_str(mcu)?;
let gcc = format!("{}-gcc", chip.gcc_toolchain());
let ar = format!("{}-gcc-ar", chip.gcc_toolchain());

let out_dir_path = cargo::out_dir();
let file = File::open(out_dir_path.join(static_inlines_c())).unwrap();
let mut tmp = File::create(out_dir_path.join(static_inlines_tmp())).unwrap();
let lines = BufReader::new(file).lines();
for line in lines {
let line = line.unwrap();
if !ignore_api(&line) {
tmp.write_all(line.as_bytes())?;
writeln!(tmp, "")?;
}
}
tmp.flush()?;

let mut gcc_cmd = std::process::Command::new(gcc);
let mut gcc_args = gcc_cmd
.arg("-mlongcalls")
.arg("-O")
.arg("-c")
.arg("-o")
.arg(out_dir_path.join(&static_inlines_o()))
.arg(out_dir_path.join(&static_inlines_tmp()));
for hdr in headers.iter() {
gcc_args = gcc_args.arg("-include").arg(hdr);
}
gcc_args = gcc_args.args(strip_quotes(build_output_args));
gcc_args = gcc_args.args(clang_args);

let gcc_output = gcc_args.output().unwrap();
if !gcc_output.status.success() {
panic!(
"Could not compile object file:\n{}",
String::from_utf8_lossy(&gcc_output.stderr)
);
}

#[cfg(not(target_os = "windows"))]
let lib_output = std::process::Command::new(ar)
.arg("rcs")
.arg(out_dir_path.join(&static_inlines_a()))
.arg(out_dir_path.join(&static_inlines_o()))
.output()
.unwrap();
#[cfg(target_os = "windows")]
let lib_output = std::process::Command::new("lib")
.arg(&out_dir_path.join(&static_inlines_o()))
.output()
.unwrap();

if !lib_output.status.success() {
panic!(
"Could not emit library file:\n{}",
String::from_utf8_lossy(&lib_output.stderr)
);
}

println!(
"cargo:rustc-link-search=native={}",
out_dir_path.to_string_lossy()
);
println!("cargo:rustc-link-lib=static={}", STATIC_INLINE);

Ok(())
}

fn main() -> anyhow::Result<()> {
let build_output = build_driver::build()?;

Expand Down Expand Up @@ -97,9 +228,13 @@ fn main() -> anyhow::Result<()> {
// Because we have multiple bindgen invocations and we can't clone a bindgen::Builder,
// we have to set the options every time.
let configure_bindgen = |bindgen: bindgen::Builder| {
let mut outdir = cargo::out_dir();
outdir.push(STATIC_INLINE);
Ok(bindgen
.parse_callbacks(Box::new(BindgenCallbacks))
.use_core()
.wrap_static_fns(true)
.wrap_static_fns_path(outdir)
.enable_function_attribute_detection()
.clang_arg("-DESP_PLATFORM")
.blocklist_function("strtold")
Expand Down Expand Up @@ -145,7 +280,7 @@ fn main() -> anyhow::Result<()> {
);

configure_bindgen(build_output.bindgen.clone().builder()?)?
.headers(headers)?
.headers(headers.clone())?
.generate()
.with_context(bindgen_err)?
.write_to_file(&bindings_file)
Expand Down Expand Up @@ -185,7 +320,7 @@ fn main() -> anyhow::Result<()> {
.into_iter()
.chain(EspIdfVersion::parse(bindings_file)?.cfg_args())
.chain(build_output.components.cfg_args())
.chain(once(mcu))
.chain(once(mcu.clone()))
.collect(),
};
cfg_args.propagate();
Expand All @@ -211,5 +346,8 @@ fn main() -> anyhow::Result<()> {
link_args.propagate();
}

let clang_args: Vec<String> = build_output.components.clang_args().collect();
process_static_inlines(&build_output.cincl_args.args, clang_args, &mcu, headers)?;

Ok(())
}

0 comments on commit 34a29e5

Please sign in to comment.