Skip to content

Support --use-core and --ctypes-prefix #218

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

Merged
merged 5 commits into from
Nov 8, 2016
Merged
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
15 changes: 14 additions & 1 deletion src/bin/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ extern crate log;
extern crate clang_sys;
extern crate rustc_serialize;

use bindgen::{BindgenOptions, Bindings, ClangVersion, LinkType, clang_version};
use bindgen::{BindgenOptions, Bindings, LinkType, clang_version};
use std::default::Default;
use std::env;
use std::fs;
Expand Down Expand Up @@ -67,6 +67,11 @@ Options:

--no-unstable-rust Avoid generating unstable rust.

--use-core Use built-in types from core instead of std.

--ctypes-prefix=<prefix> Use the given prefix before the raw types
instead of ::std::os::raw::.

--opaque-type=<type> Mark a type as opaque.

--blacklist-type=<type> Mark a type as hidden.
Expand Down Expand Up @@ -180,6 +185,14 @@ fn parse_args_or_exit(args: Vec<String>) -> (BindgenOptions, Box<io::Write>) {
"--no-unstable-rust" => {
options.unstable_rust = false;
}
"--use-core" => {
options.use_core = true;
}
"--ctypes-prefix" => {
let prefix = iter.next()
.expect("--ctypes-prefix expects a prefix after it");
options.ctypes_prefix = Some(prefix);
}
"--emit-clang-ast" => {
options.emit_ast = true;
}
Expand Down
43 changes: 26 additions & 17 deletions src/codegen/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,14 +533,15 @@ impl<'a> Bitfield<'a> {
let setter_name = ctx.ext_cx()
.ident_of(&format!("set_{}", &field_name));
let mask = ((1usize << width) - 1) << offset;
let prefix = ctx.trait_prefix();
// The transmute is unfortunate, but it's needed for enums in
// bitfields.
let item = quote_item!(ctx.ext_cx(),
impl X {
#[inline]
pub fn $getter_name(&self) -> $field_type {
unsafe {
::std::mem::transmute(
::$prefix::mem::transmute(
(
(self.$field_ident &
($mask as $bitfield_type))
Expand Down Expand Up @@ -942,8 +943,9 @@ impl CodeGenerator for CompInfo {
if !template_args_used[i] {
let name = ctx.resolve_type(*ty).name().unwrap();
let ident = ctx.rust_ident(name);
let prefix = ctx.trait_prefix();
let phantom = quote_ty!(ctx.ext_cx(),
::std::marker::PhantomData<$ident>);
::$prefix::marker::PhantomData<$ident>);
let field =
StructFieldBuilder::named(format!("_phantom_{}", i))
.pub_()
Expand Down Expand Up @@ -999,10 +1001,11 @@ impl CodeGenerator for CompInfo {
let fn_name = format!("bindgen_test_layout_{}", canonical_name);
let fn_name = ctx.rust_ident_raw(&fn_name);
let ident = ctx.rust_ident_raw(&canonical_name);
let size_of_expr =
quote_expr!(ctx.ext_cx(), ::std::mem::size_of::<$ident>());
let align_of_expr =
quote_expr!(ctx.ext_cx(), ::std::mem::align_of::<$ident>());
let prefix = ctx.trait_prefix();
let size_of_expr = quote_expr!(ctx.ext_cx(),
::$prefix::mem::size_of::<$ident>());
let align_of_expr = quote_expr!(ctx.ext_cx(),
::$prefix::mem::align_of::<$ident>());
let size = layout.size;
let align = layout.align;
let item = quote_item!(ctx.ext_cx(),
Expand Down Expand Up @@ -1414,7 +1417,13 @@ impl ItemToRustTy for Item {

fn raw_type(ctx: &BindgenContext, name: &str) -> P<ast::Ty> {
let ident = ctx.rust_ident_raw(&name);
quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident)
match ctx.options().ctypes_prefix {
Some(ref prefix) => {
let prefix = ctx.rust_ident_raw(prefix);
quote_ty!(ctx.ext_cx(), $prefix::$ident)
}
None => quote_ty!(ctx.ext_cx(), ::std::os::raw::$ident),
}
}

impl ToRustTy for Type {
Expand All @@ -1430,9 +1439,7 @@ impl ToRustTy for Type {
TypeKind::Void => raw!(c_void),
// TODO: we should do something smart with nullptr, or maybe *const
// c_void is enough?
TypeKind::NullPtr => {
quote_ty!(ctx.ext_cx(), *const ::std::os::raw::c_void)
}
TypeKind::NullPtr => raw!(c_void).to_ptr(true, ctx.span()),
TypeKind::Int(ik) => {
match ik {
IntKind::Bool => aster::ty::TyBuilder::new().bool(),
Expand Down Expand Up @@ -1755,35 +1762,37 @@ mod utils {

pub fn prepend_union_types(ctx: &BindgenContext,
result: &mut Vec<P<ast::Item>>) {
let prefix = ctx.trait_prefix();
let union_field_decl = quote_item!(ctx.ext_cx(),
#[derive(Debug)]
#[repr(C)]
pub struct __BindgenUnionField<T>(::std::marker::PhantomData<T>);
pub struct __BindgenUnionField<T>(
::$prefix::marker::PhantomData<T>);
)
.unwrap();

let union_field_impl = quote_item!(&ctx.ext_cx(),
impl<T> __BindgenUnionField<T> {
#[inline]
pub fn new() -> Self {
__BindgenUnionField(::std::marker::PhantomData)
__BindgenUnionField(::$prefix::marker::PhantomData)
}

#[inline]
pub unsafe fn as_ref(&self) -> &T {
::std::mem::transmute(self)
::$prefix::mem::transmute(self)
}

#[inline]
pub unsafe fn as_mut(&mut self) -> &mut T {
::std::mem::transmute(self)
::$prefix::mem::transmute(self)
}
}
)
.unwrap();

let union_field_default_impl = quote_item!(&ctx.ext_cx(),
impl<T> ::std::default::Default for __BindgenUnionField<T> {
impl<T> ::$prefix::default::Default for __BindgenUnionField<T> {
#[inline]
fn default() -> Self {
Self::new()
Expand All @@ -1793,7 +1802,7 @@ mod utils {
.unwrap();

let union_field_clone_impl = quote_item!(&ctx.ext_cx(),
impl<T> ::std::clone::Clone for __BindgenUnionField<T> {
impl<T> ::$prefix::clone::Clone for __BindgenUnionField<T> {
#[inline]
fn clone(&self) -> Self {
Self::new()
Expand All @@ -1803,7 +1812,7 @@ mod utils {
.unwrap();

let union_field_copy_impl = quote_item!(&ctx.ext_cx(),
impl<T> ::std::marker::Copy for __BindgenUnionField<T> {}
impl<T> ::$prefix::marker::Copy for __BindgenUnionField<T> {}
)
.unwrap();

Expand Down
16 changes: 12 additions & 4 deletions src/ir/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ impl<'ctx> BindgenContext<'ctx> {
/// Mangles a name so it doesn't conflict with any keyword.
pub fn rust_mangle<'a>(&self, name: &'a str) -> Cow<'a, str> {
use syntax::parse::token;
let ident = self.rust_ident_raw(&name);
let ident = self.rust_ident_raw(name);
let token = token::Ident(ident);
if token.is_any_keyword() || name.contains("@") ||
name.contains("?") || name.contains("$") ||
Expand All @@ -242,9 +242,7 @@ impl<'ctx> BindgenContext<'ctx> {
}

/// Returns a mangled name as a rust identifier.
pub fn rust_ident_raw<S>(&self, name: &S) -> Ident
where S: Borrow<str>,
{
pub fn rust_ident_raw(&self, name: &str) -> Ident {
self.ext_cx().ident_of(name.borrow())
}

Expand Down Expand Up @@ -912,6 +910,16 @@ impl<'ctx> BindgenContext<'ctx> {
to_iterate: to_iterate,
}
}

/// Convenient method for getting the prefix to use for most traits in
/// codegen depending on the `use_core` option.
pub fn trait_prefix(&self) -> Ident {
if self.options().use_core {
self.rust_ident_raw("core")
} else {
self.rust_ident_raw("std")
}
}
}

/// An iterator over whitelisted items.
Expand Down
14 changes: 8 additions & 6 deletions src/ir/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -677,19 +677,21 @@ impl Type {
// process of resolving them.
CXType_MemberPointer |
CXType_Pointer => {
let inner =
Item::from_ty_or_ref(ty.pointee_type().unwrap(), location,
parent_id, ctx);
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
location,
parent_id,
ctx);
TypeKind::Pointer(inner)
}
CXType_BlockPointer => TypeKind::BlockPointer,
// XXX: RValueReference is most likely wrong, but I don't think we
// can even add bindings for that, so huh.
CXType_RValueReference |
CXType_LValueReference => {
let inner =
Item::from_ty_or_ref(ty.pointee_type().unwrap(), location,
parent_id, ctx);
let inner = Item::from_ty_or_ref(ty.pointee_type().unwrap(),
location,
parent_id,
ctx);
TypeKind::Reference(inner)
}
// XXX DependentSizedArray is wrong
Expand Down
20 changes: 20 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,18 @@ impl Builder {
self
}

/// Use core instead of libstd in the generated bindings.
pub fn use_core(mut self) -> Builder {
self.options.use_core = true;
self
}

/// Use the given prefix for the raw types instead of `::std::os::raw`.
pub fn ctypes_prefix<T: Into<String>>(mut self, prefix: T) -> Builder {
self.options.ctypes_prefix = Some(prefix.into());
self
}

/// Generate the Rust bindings using the options built up thus far.
pub fn generate<'ctx>(self) -> Result<Bindings<'ctx>, ()> {
Bindings::generate(self.options, None)
Expand Down Expand Up @@ -273,6 +285,12 @@ pub struct BindgenOptions {
/// cannot.
pub unstable_rust: bool,

/// True if we should avoid using libstd to use libcore instead.
pub use_core: bool,

/// An optional prefix for the "raw" types, like `c_int`, `c_void`...
pub ctypes_prefix: Option<String>,

/// True if we should generate constant names that are **directly** under
/// namespaces.
pub namespaced_constants: bool,
Expand Down Expand Up @@ -310,6 +328,8 @@ impl Default for BindgenOptions {
derive_debug: true,
enable_cxx_namespaces: false,
unstable_rust: true,
use_core: false,
ctypes_prefix: None,
namespaced_constants: true,
msvc_mangling: false,
raw_lines: vec![],
Expand Down
23 changes: 23 additions & 0 deletions tests/expectations/tests/no-std.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]

#![no_std]
mod libc { pub type c_int = i32; pub enum c_void {} }

#[repr(C)]
#[derive(Debug, Copy)]
pub struct foo {
pub a: libc::c_int,
pub b: libc::c_int,
pub bar: *mut libc::c_void,
}
#[test]
fn bindgen_test_layout_foo() {
assert_eq!(::core::mem::size_of::<foo>() , 16usize);
assert_eq!(::core::mem::align_of::<foo>() , 8usize);
}
impl Clone for foo {
fn clone(&self) -> Self { *self }
}
22 changes: 22 additions & 0 deletions tests/expectations/tests/use-core.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/* automatically generated by rust-bindgen */


#![allow(non_snake_case)]

extern crate core;

#[repr(C)]
#[derive(Debug, Copy)]
pub struct foo {
pub a: ::std::os::raw::c_int,
pub b: ::std::os::raw::c_int,
pub bar: *mut ::std::os::raw::c_void,
}
#[test]
fn bindgen_test_layout_foo() {
assert_eq!(::core::mem::size_of::<foo>() , 16usize);
assert_eq!(::core::mem::align_of::<foo>() , 8usize);
}
impl Clone for foo {
fn clone(&self) -> Self { *self }
}
5 changes: 5 additions & 0 deletions tests/headers/no-std.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// bindgen-flags: --ctypes-prefix "libc" --use-core --raw-line "#![no_std]" --raw-line "mod libc { pub type c_int = i32; pub enum c_void {} }"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

poor man's libc :)

struct foo {
int a, b;
void* bar;
};
6 changes: 6 additions & 0 deletions tests/headers/use-core.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// bindgen-flags: --use-core --raw-line "extern crate core;"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't --use-core imply extern crate core; in the bindings? Shouldn't we automatically insert the extern crate definition?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, at least not completely automatically I guess.

It's not uncommon doing include!("path/to/bindings.rs"), in which case it's unnecessary. In general it's completely unnecessary as long as the bindings aren't the crate root, so I went the easy/safe way. if it's harmless we can do it in a followup, in which case is straight-forward to do.


struct foo {
int a, b;
void* bar;
};
3 changes: 2 additions & 1 deletion tests/tools/run-bindgen.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import sys
import subprocess
import tempfile
import shlex

BINDGEN_FLAGS_PREFIX = "// bindgen-flags: "

Expand Down Expand Up @@ -94,7 +95,7 @@ def get_bindgen_flags(header_path):
with open(header_path) as f:
for line in f:
if line.startswith(BINDGEN_FLAGS_PREFIX):
flags.extend(line.strip().split(BINDGEN_FLAGS_PREFIX)[1].split(" "))
flags.extend(shlex.split(line.strip().split(BINDGEN_FLAGS_PREFIX)[1]))
break

return flags
Expand Down