sean1708 / rusty-cheddar Goto Github PK
View Code? Open in Web Editor NEWA Rust crate for automatically generating C header files from Rust source file.
Home Page: http://sean1708.github.io/rusty-cheddar/
A Rust crate for automatically generating C header files from Rust source file.
Home Page: http://sean1708.github.io/rusty-cheddar/
Would you mind publishing a new point release with so we can use the crates.io version with std::os::raw
type support from #36?
But only when it makes sense.
For example a public C function which is not #[no_mangle]
is likely that way because the author forgot to include it. On the other hand, a public struct is quite likely to be not intended to be used from C so we don't want to warn about that.
Combinations which should be warned:
pub extern <C style ABI> fn
with no #[no_mangle]
#[no_mangle] pub fn
with no extern
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?
Line 137 in 1654acd
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?
This should make things more flexible for developers when we implement an extensible compiler interface.
Probably need to use a custom session type to abstract away any breaking changes in syntex.
Support generating C++ headers with generics support.
See also:
rust-lang/rfcs#602
https://internals.rust-lang.org/t/better-c-interoperability/2650
This issue is reserved for the future.
This could be done using noreturn
, but that isn't yet standard and it probably plays badly with panics.
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.
A source file containing a question mark ?
operator leads to a parsing error and therefore to an invalid build, e.g. re-writing the example from Macro std::try
works fine:
use std::io;
use std::fs::File;
use std::io::prelude::*;
enum MyError {
FileWriteError
}
impl From<io::Error> for MyError {
fn from(e: io::Error) -> MyError {
MyError::FileWriteError
}
}
fn write_to_file_using_try() -> Result<(), MyError> {
let mut file = try!(File::create("my_best_friends.txt"));
try!(file.write_all(b"This is a list of my best friends."));
println!("I wrote to the file");
Ok(())
}
But adding the following function leads to a build error if cheddar is active for the build.
fn write_to_file_using_qm() -> Result<(), MyError> {
let mut file = File::create("my_best_friends.txt")?;
file.write_all(b"This is a list of my best friends.")?;
println!("I wrote to the file");
Ok(())
}
The error is the following:
cargo build
Compiling tmp v0.1.0 (file://~/tmp)
error: failed to run custom build command for `tmp v0.1.0 (file://~/tmp)`
process didn't exit successfully: `~/tmp/target/debug/build/tmp-61d2999a3a4c1c18/build-script-build` (exit code: 101)
--- stderr
src/lib.rs:25:55: 25:56 error: expected one of `.`, `;`, or an operator, found `?`
src/lib.rs:25 let mut file = File::create("my_best_friends.txt")?;
^
thread 'main' panicked at 'Box<Any>', ~/.cargo/registry/src/github.com-1ecc6299db9ec823/syntex_syntax-0.24.0/src/parse/mod.rs:79
note: Run with `RUST_BACKTRACE=1` for a backtrace.
#[repr(u8)]
, etc. control the size of a C-like enum, there doesn't seem to be a portable way of specifying this in C but I could be missing something.
#[repr(packed)]
removes any padding in the item. Maybe this can be done with
#pragma pack(push)
#pragma pack(1)
// ...
#pragma pack(pop)
but I'm not yet sure whether there are any guarantees that the two are equivalent.
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 .
).
It would be handy if I could annotate types with the name I want the C header to use. This wouldn't work with functions (since the name in the header must correspond to the name in the library), but it would for types, since the thing we actually care about there is the ABI rather than the name.
As things stand today, I have to live with non-C-friendly type names (e.g., State
, which is a recipe for trouble in C's flat namespace) or else I need to compromise on my Rust names (e.g., struct foolib_state
). I'd like the ability to explicitly name my generated C types:
#[repr(C)]
#[cheddar(name=foolib_state)]
pub struct State {
// ...
}
Alternatively (or also?), it would be great if I could tell rusty-cheddar how to automatically C-ify my names:
Cheddar::new()
.expect(...)
.prefix("foolib_")
.convert_camel_cased_type_names(true)
.run_build(...)
Is this necessarily a bad thing? I can't think of a situation in which it would be useful.
To be called from C the crate must either be a dynamic or static library so it would make sense to automatically set a crate attribute for it. Is this possible?
Currently attributes are ignored which is obviously not optimal.
Currently any function pointer without a name errors, this is incorrect since you can have function pointers as a return type (and therefore having no name).
Let's face it, I'm a bit crap at writing documentation. I'm thinking the module level docs should start by explaining how each Item is converted including pitfalls then go on to give a full example.
Currently
type MyOption = Option<i32>;
will be converted into
typedef Option MyOption;
which is very obviously wrong, it should just be ignored.
Also generics in structs should cause an error.
After looking through the issues in syntex
(serde-deprecated/syntex#45), I am fairly sure it is their issue not yours, but I thought I would ask anyway.
I have a macro like this:
#[macro_export]
macro_rules! opaque_struct {
($inner:ty, $opaque:ident, $opaqueBoxed:ident, $deleteFunction:ident) => {
#[repr(C)]
pub struct $opaque(pub $inner);
// ...and so on
}
}
The #[repr(C)]
structs and extern functions aren't converted to the C header.
I also understand you are rewriting the code into a more general framework. Will that change the way macros are/aren't expanded?
In the far future I think it would be great if rustc
allowed multiple compilation 'targets', and users could then create targets that weren't actual targets for a specific processor. That sounds weird, but is perhaps best explained with examples:
The key differentiating factor between this system and lints/syntax extensions/build scripts would be that it would have access to ALL type information and the implementation/MIR of ALL crates (currently only generic functions/structs from foreign crates are put into metadata and made available to lints/trans).
If you think that is an interesting proposition taking to http://internals.rust-lang.org or whatever, then let me know.
Although the README states upfront that a nightly compiler is necessary for the following steps, then introduces steps that need nightly, then introduces steps for working with stable.
I think it should be the other way around: "I have a stable compiler from the website installed, how do I use it".
In generall, I also think that #[plugin()]
usage for tools like this should be avoided.
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.
My initial thought is to write a few minimal cheddar blocks in various different files and use rust to compile, run and clean them.
Probably require moving to a ParseSess based error handling.
Store the languages requested as a vector of trait-objects.
Hopefully be able to stop special casing C (so generating a header file would just be a case of requesting the C interface).
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?
When creating a function item we need to set things up properly.
C
.system
be better? Or could this bite us in the arse?cdecl
?If not, what do they span?
pointer.rs wraps Data in a newtype to make it opaque to C, but datalib_data_f64_append attempts to access the fields of (*data) as if it was of type Data. It needs to access the wrapper value via .0 to be valid Rust.
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".
Library using syntex which can called from build.rs or run as a standalone tool.
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.Currently, they are declared ret-ty name();
, which will allow C code to pass any number of paramters
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].
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.
instead of void func(T thing)
.
As it stands any typedefs of that form which are not generic will be put into the header, this should cover most use cases but it's not impossible for people to do something like
pub type MyResult = Result<String, ()>;
which would put
typedef Result<String, ()> MyResult;
into the header file.
The two obvious ways to combat this are using #[repr(C)]
(which rustc
seems to be fine with) or adding a lint group and using #[allow(cheddar_typedef)]
(I'm not sure whether this would actually work).
Because the parser will have vastly better error messages.
It might require reworking some of the logic.
With the new pull request, I'd really like to be able to access it from my project on crates.io; would you mind updating to 0.3.3?
Currently this is done like so
header_path.file_stem().map(|p| p.to_str().unwrap_or("default")).unwrap_or("default"),
because both .file_stem()
and .to_str()
return Option
. Is there a cleaner way to do this? Should we die if we can't get the .file_stem()
(because it might suggest problems down the road)?
If I declare the following struct in Rust:
#[repr(C)]
pub struct foo {
bar: extern "C" fn(blah: *mut libc::c_void)
}
rusty-cheddar (correctly) generates this in its header:
typedef struct foo {
void (*bar)(void *blah);
} foo;
C code is able to set bar to NULL
, but on the Rust side, there's no way to check for that. It appears the expected way of handling this (see here or here) is to change the type on the Rust side to an Option:
#[repr(C)]
pub struct foo {
bar: Option<extern "C" fn(blah: *mut libc::c_void)>
}
but rusty-cheddar does not handle this appropriately.
The current way special cases newtypes which don't have any direct C equivalent. This would be a breaking change.
Currently *const *const f32
would be turned into const float**
, it should be turned into float const* const*
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.