www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Automatic translation from .h -> .d using nothing but CTFE!

reply Robert Fraser <fraserofthenight gmail.com> writes:
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

There was a convo a while back about using the import expression and 
CTFE/templates to automatically convert C/C++ .h files to .d files 
without requiring an external program like bcd.gen or htod... Well, I 
had a need for just such a thing, so I wrote a quick one up (that will 
only work if you've written the header file in a special format). I 
attached the relevant code, if you understand what's going on, you could 
probably modify it. This isn't a "release" of anything, since it has no 
comments, etc., but just an interesting proof-of-concept.

This D code:
mixin(sharedFromHeader_mixin!("platif.h")(LIB_NAME));

Generates the contents of the attached "formatted.d" (except not 
formatted, obviously :-)).

Basically, you need this macro in your C++ header:

#define FUN(__NAME__, __RV__, __PARAMS__) __RV__ __NAME__ __PARAMS__

You'll also want to redefine some types like so:

#define _CONST const
#define _VOID  void
#define _LINT  long // int masquerading as a long
#define _LUINT unsigned long
#define _INT   int
#define _UINT  unsigned int
#define _LONG  __int64
#define _ULONG unsigned __int64
#define _CHAR  char

To add new types to the D conversion function, see the convertCppTypes 
in sharedlib.d

Then anything you want copied directly into the D file, you need to wrap 
in // COPY and // END:

// COPY
struct MofIf
{
	_INT (*Stream_New)(_VOID**);
	_INT (*Stream_Read)(_VOID*, _VOID*, _LUINT, _LUINT*);
	_INT (*Stream_Seek)(_VOID*, _ULONG);
	_INT (*Stream_Tell)(_VOID*, _ULONG*);
	_INT (*Stream_GetSize)(_VOID*, _ULONG*);
	_INT (*Stream_GetAvailable)(_VOID*, _ULONG*);
};
// END

Then write your functions in an // FUNCTION // END block:

// FUNCTIONS
FUN(initMof,    _VOID, (MofIf* _mof));
FUN(mimeOnFire, _INT,  (_CONST _CHAR* path));
// END

Anything in the header outside those blocks will be ignored. Also the 
syntax is extremely specific, so the line must start with "FUN(" and end 
with ");" without spaces (you can have comments after that).

Be warned, though -- compile times are SLOOW, even with only two 
functions :-). I just started this part of the project, so when there's 
the 70+ I expect to have when it's done... uh oh. A better replace 
function could solve this (anyone have a good CTFE replace function 
sitting around? :-P)

There's also a simpler function used to wrap dynamic libraries. It's 
used like:

mixin(shared_mixin(LIB_NAME, [
         "int function(char*)",   "mimeOnFire",
	"void function(MofIf*)", "initMof"]));

which will generate function pointers for all the functions and 
"_loadLib()" and "_unloadLib()" functions which load the library, look 
up the symbols, etc. The header function actually calls this one, but 
you could easily modify it to toss out declarations for a static library 
as well.

Enjoy! Big thanks to Ary for Descent's CTFE debugger; this took 45 
minutes instead of 3 hours thanks to that!

(License : Public Domain)
Jun 12 2009
parent Robert Fraser <fraserofthenight gmail.com> writes:
Robert Fraser wrote:
 [...]

BTW, the code is D1+Tango... it shouldn't be overly hard to port, though, since the only part of Tango it uses is tango.sys.SharedLibrary. As for D2, change char[] to string, and all should be good.
Jun 12 2009