atilaneves / dpp

Directly include C headers in D source code
Boost Software License 1.0
231 stars 31 forks source link

C macros that declare an extern variable cause D code that won't compile due to multiple definitions #154

Closed Laeeth closed 5 years ago

Laeeth commented 5 years ago

Eg postgresql pgmagic has extern int dummy variable; repeated

atilaneves commented 5 years ago

I googled postgresql pgmagic and didn't find anything. I don't see how C macros declaring things twice can be a bug either unless they're used in a way that wasn't intended?

I need an example to know what it is I'd be fixing.

Laeeth commented 5 years ago

It's not a bug in C. It's that right now dpp permits multiple extern declarations of variables and that's illegal.

atilaneves commented 5 years ago

This currently works (as in, it only gets emitted once):

extern int dummy;
extern int dummy;

Is there a concrete example you know to not work?

atilaneves commented 5 years ago

The issue is:

In postgres, specifically the file src/include/fmgr.h, there are these two macros:

#define PG_FUNCTION_INFO_V1(funcname) \
extern Datum funcname(PG_FUNCTION_ARGS); \
extern PGDLLEXPORT const Pg_finfo_record * CppConcat(pg_finfo_,funcname)(void); \
const Pg_finfo_record * \
CppConcat(pg_finfo_,funcname) (void) \
{ \
    static const Pg_finfo_record my_finfo = { 1 }; \
    return &my_finfo; \
} \
extern int no_such_variable

#define PG_MODULE_MAGIC \
extern PGDLLEXPORT const Pg_magic_struct *PG_MAGIC_FUNCTION_NAME(void); \
const Pg_magic_struct * \
PG_MAGIC_FUNCTION_NAME(void) \
{ \
    static const Pg_magic_struct Pg_magic_data = PG_MODULE_MAGIC_DATA; \
    return &Pg_magic_data; \
} \
extern int no_such_variable

If dpp translates this and the .dpp file tries using both of them, the resulting D code will have two declarations of extern int no_such_variable, which isn't allowed in D.

The reason why the macros look like that is probably to allow them to be used with a semicolon.

atilaneves commented 5 years ago

I don't see how this is fixable. I've never seen this idiom before; if it were more common it might make sense to include code to handle it in dpp, but without knowing what other forms this might take (is it always extern int? Is the dummy variable always on the last line?), it would be brittle.

atilaneves commented 5 years ago

The more I think about it the more I'm convinced that the way to do this is by running dpp with --preprocess-only, then use sed to remove the dummy declarations as part of the build system.