Skip to content
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

#define + sizeof(...) fails to emit constant #666

Open
vvanders opened this issue Apr 26, 2017 · 9 comments
Open

#define + sizeof(...) fails to emit constant #666

vvanders opened this issue Apr 26, 2017 · 9 comments
Labels

Comments

@vvanders
Copy link

Not sure if I'm missing a feature that's not supported yet but I hit issue and narrowed it down when trying to generate bindings for Lua.

Input C/C++ Header

#define SIZEOF_INT sizeof(int)

Bindgen Invokation

    bindgen::Builder::default()
        .header("test.h")
        .generate().unwrap()
        .write_to_file("src/out.rs").unwrap();

Actual Results

/* automatically generated by rust-bindgen */



Expected Results

RUST_LOG=bindgen Output

No logging emitted when I set env var

Full repro repo also exists here for easier debugging: https://github.com/vvanders/bindgen_repro

@vvanders
Copy link
Author

Also looks like:

static const int EXT_SIZEOF_INT = SIZEOF_INT;

Does generate the output I expect, so that's at least a somewhat reasonable work around.

@emilio
Copy link
Contributor

emilio commented Apr 26, 2017

Yeah, macros depend on where they're instantiated to get their values, so we can't really do anything about it without looking at all the places it's used and verifying it's the expected thing.

We have some code to evaluate constants though, so as you said, doing that works.

I'm not sure we can fix this properly without introducing correctness issues, to be honest.

@vvanders
Copy link
Author

That's kinda unfortunate since it makes drop-in ports pretty difficult. I guess feel free to close this though unless you think there's any reasonable path forward.

@emilio
Copy link
Contributor

emilio commented Apr 28, 2017

I can try to add an API to libclang to try to evaluate a macro in a global context...

@fitzgen
Copy link
Member

fitzgen commented Aug 29, 2017

Copying the proposal by @target-san from #937 here for posterity:

ATM if bindgen user needs to parse macros by hand, he's forced to do it manually - know all headers involved, parse them by hand and finally do something with parsing results.

I think it would be beneficial if ParseCallbacks would provide way to not only get notified that certain macro was parsed, but also have its body, at least as a string.
Changes proposed, discussion welcome:

pub trait ParseCallbacks {
    // Provides callback implementor ways to customize macro parsing
    // @param  name - macro name
    // @param  args - list of macro arguments; None for constant macro;
    //                Some(...) for function-like macro,
    //                with vector containing argument identifiers
    // @param  body - raw macro body as a string slice, allows to parse it by hand
    // @return        None to perform default parsing;
    //                Some(...) to insert specified text into generated bindings module
    fn parsed_macro(&self, name: &str, args: Option<Vec<&str>>, body: &str) -> Option<String>;
    // ... leftover
}

@target-san
Copy link

@emilio
Would be really nice - although it'll work only for constant-style macros. I'm dealing with a proprietary C lib, where initialization of certain structs is performed via macro of sorts:

#define INIT(s) ( (s).field1 = value1, (s).field2 = value2 )

So I'd have an option to do this by hand anyway.

@emilio
Copy link
Contributor

emilio commented Aug 29, 2017

How would your API work for varargs macros? Should we just pass the string of arguments, and let the caller do whatever he thinks it's appropriate?

We could probably pass another boolean as an argument I guess...

@target-san
Copy link

target-san commented Aug 29, 2017

Boolean would be okay I think. The sample above is of course a sketch, not a final proposal.
Also, there's a good question on how to organize API.
Because user may want to either filter first all macros by himself - or only those not handled by bindgen.
Something like

pub trait ParseCallbacks {
    // Invoked when bindgen just stumbles upon some macro, before its body is parsed
    // @param  name - macro name
    // @param  args - list of macro arguments; None for constant macro;
    //                Some(...) for function-like macro,
    //                with vector containing argument identifiers
    // @param  body - raw macro body as a string slice, allows to parse it by hand
    // @return        None to perform default parsing
    //                Some(...) to insert specified text into generated bindings module
    fn before_parse_macro(&self, name: &str, args: Option<(Vec<&str>, bool)>, body: &str) -> Option<String>;
    // Invoked after bindgen tried to parse macro on its own
    // @param  name - macro name
    // @param  args - list of macro arguments; None for constant macro;
    //                Some(...) for function-like macro,
    //                with vector containing argument identifiers
    // @param  raw_body - raw macro body as a string slice, allows to parse it by hand
    // @param  body_expr - parsed macro body, if bindgen was able to parse it
    // @return        None to insert macro as it was parsed by bindgen; if macro wasn't parsed, then nothing is inserted
    //                Some(...) to insert specified text into generated bindings module, instead of parsed piece
    fn after_parse_macro(&self, name: &str, args: Option<(Vec<&str>, bool)>, raw_body: &str, body_expr: &MacroExpr) -> Option<String>;
    // ... leftover
}

@oberien
Copy link

oberien commented May 25, 2020

Is there a solution planned for this problem yet? I'm currently using a workaround similar to the one suggested in #666 (comment), but it feels super hacky:

#define SIZEOF_INT sizeof(int)

#pragma push_macro("SIZEOF_INT")
#undef SIZEOF_INT
size_t SIZEOF_INT =
#pragma pop_macro("SIZEOF_INT")
    SIZEOF_INT;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants