A Rust crate for automatically generating C header files from Rust source file.

Overview

Please be aware that this crate is no longer actively maintained, please look into the much more feature rich cbindgen instead.

rusty-cheddar

Build Status crates.io MIT licensed

rusty-cheddar is a library for converting Rust source files into C header files.

A note on versioning: While rusty-cheddar is still in a significant flux (i.e. pre-v1.0.0) it will likely go through numerous breaking changes. However, until v1.0.0, any time a breaking change is made the minor version will be bumped and any time a new feature is added the path version will be bumped.

rusty-cheddar targets C99 or later (for sane single line comments and use of stdint.h and stdbool.h), if you really really really really really have to use an older standard then please open an issue at the repo and I will begrudgingly figure out how to implement support for it (after arguing with you lots and lots).

The most useful way to use rusty-cheddar is in a build script. To do this add the following build-dependencies section to your Cargo.toml (to use it as a normal library simply replace build-dependencies with dependencies):

# Cargo.toml

[build-dependencies]
rusty-cheddar = "0.3.0"

Then create the following build.rs:

// build.rs

extern crate cheddar;

fn main() {
    cheddar::Cheddar::new().expect("could not read manifest")
        .run_build("include/my_header.h");
}

This should work as is providing you've set up your project correctly. Don't forget to add a build = ... to your [package] section, see the cargo docs for more info.

rusty-cheddar will then create a my_header.h file in include/. Note that rusty-cheddar emits very few warnings, it is up to the programmer to write a library which can be correctly called from C.

API In a Module

You can also place your API in a module to help keep your source code neat. To do this you must supply the name of the module to Cheddar, then ensure that the items are available in the top-level scope:

// build.rs

extern crate cheddar;

fn main() {
    cheddar::Cheddar::new().expect("could not read manifest")
        .module("c_api").expect("malformed module path")
        .run_build("target/include/rusty.h");
}
// src/lib.rs

pub use c_api::*;

mod c_api {
    // api goes here ...
}

There is also the .compile() and .compile_code() methods for finer control.

Conversions

In the examples below, boilerplate has been omitted from the header.

Typedefs

rusty-cheddar converts pub type A = B into typedef B A;. Types containing generics are ignored.

Rust:

type UInt32 = u32;
pub type UInt64 = u64;
pub type MyOption<T> = Option<T>

Header:

// Some boilerplate omitted.
typedef uint64_t UInt64;
// Some more boilerplate omitted.

Enums

rusty-cheddar will convert public enums which are marked #[repr(C)]. If the enum is generic or contains tuple or struct variants then cheddar will fail. rusty-cheddar should correctly handle explicit discriminants.

Rust:

#[repr(C)]
pub enum Colours {
    Red = -6,
    Blue,
    Green = 7,
    Yellow,
}

// This would fail if it was #[repr(C)].
pub enum Tastes<T> {
    Savoury(T),
    Sweet,
}

// This would fail if it was public.
#[repr(C)]
enum Units {
    Kg(f64),
    M(f64),
    S(f64),
    A(f64),
    K(f64),
    Mol(f64),
    Cd(f64),
}

Header:

// Some boilerplate omitted.
typedef enum Colours {
        Red = -6,
        Blue,
        Green = 7,
        Yellow,
} Colours;
// Some more boilerplate omitted.

Structs

Structs are handled very similarly to enums, they must be public, marked #[repr(C)], and they must not contain generics (this currently only checked at the struct-level, generic fields are not checked).

Rust:

#[repr(C)]
pub struct Person {
    age: i32,
    height: f64,
    weight: f64,
}

Header:

// Some boilerplate omitted.
typedef struct Person {
        int32_t age;
        double height;
        double weight;
} Person;
// Some more boilerplate omitted.

Opaque Structs

One common C idiom is to hide the implementation of a struct using an opaque struct, which can only be used behind a pointer. This is especially useful in Rust-C interfaces as it allows you to use any arbitrary Rust struct in C.

To define an opaque struct you must define a public newtype which is marked as #[repr(C)].

Rust:

struct Foo<T> {
    bar: i32,
    baz: Option<T>,
}

#[repr(C)]
pub struct MyCrate_Foo(Foo<PathBuf>);

Header:

// Some boilerplate omitted.
typedef struct MyCrate_Foo MyCrate_Foo;
// Some boilerplate omitted.

Note that the newtype must not be generic but the type that it wraps can be arbitrary.

Functions

For rusty-cheddar to pick up on a function declaration it must be public, marked #[no_mangle] and have one of the following ABIs:

  • C
  • Cdecl
  • Stdcall
  • Fastcall
  • System

I'm not totally up to speed on calling conventions so if you believe one of these has been including in error, or if one has been omitted, then please open an issue at the repo.

rusty-cheddar will fail on functions which are marked as diverging (-> !).

Rust:

use std::ops::Add;

#[no_mangle]
pub extern fn hello() {
    println!("Hello!");
}

fn add<O, R, L: Add<R, Output=O>>(l: L, r: R) -> O {
    l + r
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn MyAdd_add_u8(l: u8, r: u8) -> u8 {
    add(l, r)
}

#[no_mangle]
#[allow(non_snake_case)]
pub extern fn MyAdd_add_u16(l: u16, r: u16) -> u16 {
    add(l, r)
}

Header:

// Some boilerplate omitted.
void hello();

uint8_t MyAdd_add_u8(uint8_t l, uint8_t r);

uint16_t MyAdd_add_u16(uint16_t l, uint16_t r);
// Some more boilerplate omitted.

Paths

You must not put types defined in other modules in an exported type signature without hiding it behind an opaque struct. This is because the C compiler must know the layout of the type and rusty-cheddar can not yet search other modules.

The very important exception to this rule are the C ABI types defined in the libc crate and std::os::raw. Types from these two modules must be fully qualified (e.g. libc::c_void or std::os::raw::c_longlong) so that they can be converted properly. Importing them with a use` statement will not work.

Contributing

Contributions to rusty-cheddar are more than welcome.

Bugs

If you find a bug or have a feature request please open an issue. I can't guarantee that I'll fix it but I'll give it a damn good go.

If you find the source code unclear in any way then I consider that a bug. I try to make my source code as clear as possible but I'm not very good at it, so any help in that regard is appreciated.

PRs

I love pull requests they tend to make my job much easier, so if you want to fix a bug or implement a feature yourself then that would be great. If you're confused by anything or need some pointers on how to proceed then feel free to open an issue so that I can help, otherwise these docs are a good place to start.

Tests

The tests require you to have a recent version (> v2.7.2) of CppHeaderParser installed for the version of Python which is installed as python (usually Python 2). Furthermore due to the fact that the tests are a massive pile of wanky hacks, you must be in the same directory as rusty-cheddar's Cargo.toml to successfully run them.

Comments
  • Support generics, enums with non-unit variants, and opaque structs.

    Support generics, enums with non-unit variants, and opaque structs.

    rustc is absolutely fine with adding #[repr(C)] to generic structs, generic enums, and enums with non-unit variants so it's perfectly possible that these types might map nicely to C.

    opened by Sean1708 6
  • Handle more conversions between Rust types and C types.

    Handle more conversions between Rust types and C types.

    • Currently does not handle any pointers.
      • Do we force the programmers to use pointers or do we do some magic behind the scenes with references?
    • How do we handle strings?
    • Should we warn (or even error) on any types?
    opened by Sean1708 4
  • Support std::os::raw variants of libc types.

    Support std::os::raw variants of libc types.

    Until the libc crate becomes part of the stable toolchain, it's nice to have these versions work too for situations where external crate dependencies are difficult.

    opened by rillian 3
  • Allow the user to add custom code.

    Allow the user to add custom code.

    Allows the inclusion of custom includes, macros and static functions.

    Maybe have a prepend(&mut self, &str) and append(&mut self, &str).

    Probably best to move the boilerplate generation (include-guards, inlcludes, etc) into .compile_to_string() so we don't have to pass more stuff to the parse:: functions. Plus they never really should have been in a parsing function anyway.

    opened by Sean1708 3
  • Default header file name.

    Default header file name.

    When no path is specified there should be a sane default path, currently this is cheddar.h. Ideally it would be

    • target/debug/include/<crate name>.h for debug cargo builds.
    • target/release/include/<crate name>.h for release cargo build.
    • include/<crate name>.h for non-cargo build.
    opened by Sean1708 3
  • [WIP] Rewrite to use rusty-binder

    [WIP] Rewrite to use rusty-binder

    • Rewrite cheddar to use rusty-binder
    • Check current uses while resolving types
    • Allow the extend cheddar with custom type modules (like it's done with libc and std::os::raw)

    Before merging this, the syntex update to rusty-binder should land.

    opened by weiznich 2
  • Namespace generated enum members with the name of the enum.

    Namespace generated enum members with the name of the enum.

    Rust enum members are namespaced by the enum, whereas C enum members leak into the containing namespace. This makes constructs such as:

    #[repr(C)]
    pub enum Foo {
        WIN = 1,
        LOSE = 2,
    }
    
    #[repr(C)]
    pub enum Bar {
        WIN = 3,
        LOSE = 4,
    }
    

    ...ambiguous within C when they're valid in Rust. The solution offered in this PR is to prefix the enum members with the enum's name to provide a form of namespacing.

    I'm not sure if you'd merge this as-is because it breaks compatibility with existing output

    opened by kinetiknz 2
  • Header ifdef guard should filter out illegal characters

    Header ifdef guard should filter out illegal characters

    The ifdef guard is currently defined as

    "#ifndef cheddar_generated_{0}_h"
    

    (likewise for the next line) where {0} is filled in with the header filename. For typical header filenames, this creates preprocessor tokens that look like cheddar_generated_filename.h_h, but . is not a legal preprocessor identifier character (clang under OS X gives a warning about "extra tokens following an identifier", pointing to the .).

    opened by jgallagher 2
  • Handle univariant enums.

    Handle univariant enums.

    Currently you can't have #[repr(C)] univariant enums like the following:

    #[repr(C)]
    enum Foo {
        Bar,
    }
    

    The error message is rather cryptic because we automatically add #[repr(C)] (so it isn't shown in the error message), should we warn about this?

    opened by Sean1708 2
  • Write comments and docstrings to the header file.

    Write comments and docstrings to the header file.

    Comments are a common form of documentation in header files so any rust docstrings should be written to the header file.

    Should rust comments be written to the header file too?

    opened by Sean1708 2
  • Bump syntex_syntax to 0.27.0 to fix build on nightly rustc

    Bump syntex_syntax to 0.27.0 to fix build on nightly rustc

    Hi. https://github.com/rust-lang/rust/pull/42136 is going to turn some old compatibility lints in rustc into hard errors. Testing discovered that this crate uses an old version of syntex_syntax affected by one of those errors. This PR updates syntex_syntax to 0.27.0, which is the minimal version building successfully with https://github.com/rust-lang/rust/pull/42136

    opened by petrochenkov 1
  • macOS Could not compile syntex_syntax v0.24.0

    macOS Could not compile syntex_syntax v0.24.0

    Cargo.lock: [[package]] name = "rusty-cheddar" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "clap 1.5.6 (registry+https://github.com/rust-lang/crates.io-index)", "syntex_syntax 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.30 (registry+https://github.com/rust-lang/crates.io-index)", ]

    when I cargo build and then I will get following error:

    error: to use a constant of type codemap::Span in a pattern, codemap::Span must be annotated with #[derive(PartialEq, Eq)] --> /Users/zoey.weng/.cargo/registry/src/github.com-1ecc6299db9ec823/syntex_syntax-0.24.0/src/errors/emitter.rs:100:18 | 100 | Some(COMMAND_LINE_SP) => self.emit_(FileLine(COMMAND_LINE_SP), msg, code, lvl), | ^^^^^^^^^^^^^^^ error: aborting due to previous error error: Could not compile syntex_syntax.

    "syntex_syntax 0.59.1" is ok. But rusty-cheddar use "syntex_syntax 0.24.0".

    opened by piaojin 3
  • Include license notice in generated headers

    Include license notice in generated headers

    Hi, some licenses such as the GPLv2 require a notice in the headers produced, this is just a simple operation of prepending a comment to the generated headers, would you please be able to add this feature to your library?

    This is more of a convinience feature as I can just as well open each header file and prepend the license text myself. (Which is what im currently doing)

    If this is more appropriate for the rusty-binder crate tell me and ill open an issue there.

    opened by afonso360 1
  • arrays should be supported

    arrays should be supported

    When attempting to use cheddar i stumbles across:

    cheddar can not handle the type [f64; 3]

    I dont really see why this is not supported? Should be convertible easily into double x[3].

    opened by fulara 0
  • Type conversions are syntactic

    Type conversions are syntactic

    use libc; ... libc::c_char becomes char but use libc::c_char; ... c_char becomes c_char. I guess the path check uses the literal textual form?

    https://github.com/Sean1708/rusty-cheddar/blob/1654acd2df7ece1db7208c04069932e2004b5615/src/types.rs#L137

    opened by solidsnack 0
Releases(v0.3.3)
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
Create a Python project automatically with rust (like create-react-app but for python)

create-python-project Create a Python project automatically with rust (like create-react-app but for python) Installation cargo install create-python-

Dhravya Shah 2 Mar 12, 2022
This tool converts Lua code to TS automatically, including the conversion of common standards to their TS equivalents.

lua-to-ts This tool converts Lua code to TS automatically, including the conversion of common standards to their TS equivalents. Code that fails to be

Dion 11 Nov 21, 2022
ruby-build is a command-line utility that makes it easy to install virtually any version of Ruby, from source.

ruby-build ruby-build is a command-line utility that makes it easy to install virtually any version of Ruby, from source. It is available as a plugin

null 3.7k Jan 5, 2023
Node.js bindings to the ripgrep library, for fast file searching in JavaScript without child processes!

ripgrepjs ripgrepjs: Node.js bindings to the ripgrep library, for direct integration with JS programs without spawning an extra subprocess! This proje

Annika 1 May 10, 2022
List the symbols within a wasm file

wasm-nm List the symbols within a wasm file. Library Executable License Contributing Executable To install the wasm-nm executable, run $ cargo install

Nick Fitzgerald 38 Nov 6, 2022
Magnesium-Oxide (MGO) - a secure file uploader with support for ShareX.

A blazingly fast, ShareX uploader coded in Rust (using actix web) which utilizes AES-256-GCM-SIV to securely store uploaded content.

Magnesium 26 Nov 25, 2022
A Zellij plugin to fuzzy find file names and contents in style 🧐

About This Zellij plugin is a fuzzy finder for file names and their contents. It can open results in your $EDITOR (scrolled to the correct line), as f

Aram Drevekenin 11 Jun 22, 2023
eJNI is a Rust crate to make working with Java's JNI less painful by providing abstractions.

eJNI provides abstractions for often-used classes from the Java standard library, like Map and List. Besides this eJNI also provides easy ways to work with Java's primitives and their object counterparts (e.g int and Integer).

Tobias de Bruijn 11 Feb 13, 2022
A cross-platform crate with FFI bindings to allow for complex vehicle ECU diagnostics.

ecu_diagnostics A cross-platform crate with FFI bindings to allow for complex vehicle ECU diagnostics. IMPORTANT Currently this crate is not 100% read

Ashcon Mohseninia 80 Dec 24, 2022
A simple code for checking crate 'prost' on WebAssembly (πŸ¦€ + πŸ•ΈοΈ = πŸ’–)

rust-wasm-prost This repository is a simple code for checking crate 'prost' on WebAssembly ( ?? + ??️ = ?? ). What is prost? prost is a Protocol Buffe

Chris Ohk 6 Apr 5, 2022
Osmon's compiler crate. Programming language made for starter & novice Uzbek audience.

Osmon Tili Osmon bu registrlarga asoslangan virtual mashinalik va yengil dasturlash tili Osmon boshqa o'zbek open source dasturchisi Sukhrob Khakimovn

Osmon 31 Dec 22, 2022
witgen is a library to generate .wit files for WebAssembly in Rust

witgen witgen is a library to help you generate wit definitions in a wit file for WebAssembly. Using this lib in addition to wit-bindgen will help you

Coenen Benjamin 28 Nov 9, 2022
Webpack loader for Rust files.

Webpack loader for Rust files.

Max Eliseev 36 Jan 12, 2022
πŸ“¦ Pack hundreds of Garry's Mod Lua files into just a handful

?? gluapack gluapack is a program that can pack hundreds of Garry's Mod Lua files into just a handful. Features Quick, easy and portable - perfect for

null 11 Aug 10, 2021
Slitter is a C- and Rust-callable slab allocator implemented primarily in Rust, with some C for performance or to avoid unstable Rust features.

Slitter is a less footgunny slab allocator Slitter is a classically structured thread-caching slab allocator that's meant to help write reliable long-

Backtrace Labs 133 Dec 5, 2022
Rust-ffi-guide - A guide for doing FFI using Rust

Using unsafe for Fun and Profit A guide to traversing the FFI boundary between Rust and other languages. A rendered version is available here. This gu

Michael Bryan 261 Dec 1, 2022
Rust library for build scripts to compile C/C++ code into a Rust library

A library to compile C/C++/assembly into a Rust library/application.

Alex Crichton 1.3k Dec 21, 2022
Rust based WASM/JS bindings for ur-rust

ur-wasm-js WASM/JS bindings for the ur-rust rust library Getting started Installation Either build the library yourself with wasm-pack or install for

Lightning Digital Entertainment 5 Feb 28, 2024