Skip to content

[WIP] reexport the static inline functions and TLS variables with C/CPP wrapper #1460

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions bindgen-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "bindgen-build"
description = "A package to link C/C++ inline functions"
version = "0.1.0"
authors = ["Flier Lu <[email protected]>"]

[dependencies]
failure = "0.1"
syn = { version = "0.15", features = ["full"] }
cc = "1.0"
86 changes: 86 additions & 0 deletions bindgen-build/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#[macro_use]
extern crate failure;
extern crate cc;
extern crate syn;

use std::env;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::result::Result as StdResult;

type Result<T> = StdResult<T, failure::Error>;

pub fn build<P, S, F>(path: P, name: S, config: F) -> Result<()>
where
P: AsRef<Path>,
S: AsRef<str>,
F: FnOnce(&mut cc::Build),
{
let mut gen = Generator::default();

// parse and extract C/C++ code
{
let mut f = File::open(path)?;
let mut content = String::new();
f.read_to_string(&mut content)?;
let ast = syn::parse_file(&content)?;
syn::visit::visit_file(&mut gen, &ast);
}

let mut build = cc::Build::new();
build
.cpp(gen.saw_cpp)
.static_flag(true)
.cargo_metadata(true);

// apply user configuration
config(&mut build);

// generate the C/C++ wrapper file
{
let out_dir = env::var("OUT_DIR")?;
let out_file = Path::new(&out_dir).join(&format!(
"{}.{}",
name.as_ref(),
if gen.saw_cpp { "cpp" } else { "c" }
));
build.file(&out_file);

let mut f = File::create(out_file)?;
writeln!(f, "// generated by bindgen; DO NOT EDIT\n")?;
writeln!(f, "#pragma GCC diagnostic push")?;
writeln!(f, "#pragma GCC diagnostic ignored \"-Wdeprecated-declarations\"")?;
writeln!(f, "{}", gen.code)?;
writeln!(f, "#pragma GCC diagnostic pop")?;
}

// build the C/C++ wrapper file
build
.try_compile(&format!("lib{}.a", name.as_ref()))
.map_err(|err| format_err!("fail to build, {:?}", err))?;

Ok(())
}

#[derive(Debug, Default)]
struct Generator {
code: String,
saw_cpp: bool,
}

impl<'ast> syn::visit::Visit<'ast> for Generator {
fn visit_item_macro(&mut self, item: &'ast syn::ItemMacro) {
if item.mac.path.is_ident("c") || item.mac.path.is_ident("cpp") {
self.code.push_str(
item.mac
.tts
.to_string()
.trim_start_matches('{')
.trim_end_matches('}'),
);
self.code.push_str("\n");
self.saw_cpp |= item.mac.path.is_ident("cpp");
}
}
}
70 changes: 70 additions & 0 deletions src/clang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,15 @@ impl Cursor {
unsafe { clang_Cursor_isFunctionInlined(self.x) != 0 }
}

/// Determine the "thread-local storage (TLS) kind" of the declaration.
pub fn tls(&self) -> CXTLSKind {
if clang_getCursorTLSKind::is_loaded() {
unsafe { clang_getCursorTLSKind(self.x) }
} else {
CXTLS_None
}
}

/// Get the width of this cursor's referent bit field, or `None` if the
/// referent is not a bit field.
pub fn bit_width(&self) -> Option<u32> {
Expand Down Expand Up @@ -550,6 +559,15 @@ impl Cursor {
}
}

/// Get the availability of the cursor's referent.
pub fn availability(&self) -> CXAvailabilityKind {
if clang_getCursorAvailability::is_loaded() {
unsafe { clang_getCursorAvailability(self.x) }
} else {
CXAvailability_Available
}
}

/// Given that this cursor's referent is a function, return cursors to its
/// parameters.
pub fn args(&self) -> Option<Vec<Cursor>> {
Expand Down Expand Up @@ -877,6 +895,16 @@ impl Type {
unsafe { clang_isConstQualifiedType(self.x) != 0 }
}

/// Is this type volatile qualified?
pub fn is_volatile(&self) -> bool {
unsafe { clang_isVolatileQualifiedType(self.x) != 0 }
}

/// Is this type is typedef?
pub fn is_typedef(&self) -> bool {
self.x.kind == CXType_Typedef
}

/// What is the size of this type? Paper over invalid types by returning `0`
/// for them.
pub fn size(&self) -> usize {
Expand Down Expand Up @@ -1527,6 +1555,39 @@ pub fn type_to_str(x: CXTypeKind) -> String {
unsafe { cxstring_into_string(clang_getTypeKindSpelling(x)) }
}

/// Convert a linkage kind to a static string.
pub fn linkage_to_str(x: CXLinkageKind) -> &'static str {
match x {
CXLinkage_Invalid => "invalid",
CXLinkage_NoLinkage => "non-extern",
CXLinkage_Internal => "internal",
CXLinkage_UniqueExternal => "unique-external",
CXLinkage_External =>"external",
_ => unreachable!(),
}
}

/// Convert a availability kind to a static string.
pub fn availability_to_str(x: CXAvailabilityKind) -> &'static str {
match x {
CXAvailability_Available => "available",
CXAvailability_Deprecated => "deprecated",
CXAvailability_NotAvailable => "not available",
CXAvailability_NotAccessible => "not accessible",
_ => unreachable!(),
}
}

/// Convert a TLS kind into a static string.
pub fn tls_to_str(x: CXTLSKind) -> &'static str {
match x {
CXTLS_None => "none",
CXTLS_Dynamic => "dynamic",
CXTLS_Static => "static",
_ => unreachable!(),
}
}

/// Dump the Clang AST to stdout for debugging purposes.
pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
fn print_indent<S: AsRef<str>>(depth: isize, s: S) {
Expand All @@ -1546,6 +1607,15 @@ pub fn ast_dump(c: &Cursor, depth: isize) -> CXChildVisitResult {
depth,
format!(" {}spelling = \"{}\"", prefix, c.spelling()),
);
print_indent(
depth,
format!(" {}linkage = {}", prefix, linkage_to_str(c.linkage())),
);
print_indent(
depth,
format!(" {}availability = {}", prefix, availability_to_str(c.availability())),
);
print_indent(depth, format!(" {}tls-kind = {}", prefix, tls_to_str(c.tls())));
print_indent(depth, format!(" {}location = {}", prefix, c.location()));
print_indent(
depth,
Expand Down
12 changes: 12 additions & 0 deletions src/codegen/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ pub mod attributes {
#[link_name = #name]
}
}

pub fn deprecated(note: Option<&str>) -> proc_macro2::TokenStream {
if let Some(note) = note {
quote! {
#[deprecated(note = #note)]
}
} else {
quote! {
#[deprecated]
}
}
}
}

/// Generates a proper type for a field or type with a given `Layout`, that is,
Expand Down
Loading