Thread overview
Interfacing with C libs: weeding through C/C++ macros and such in header files
Jan 13, 2019
Alec Stewart
Jan 13, 2019
Alex
Jan 13, 2019
Alec Stewart
Jan 14, 2019
Mike Parker
January 13, 2019
Hello all!

So while I have a decent grasp on D, I've been having trouble figuring out specific projects that I could do in D, so I thought I'd maybe find a little C or C++ library I could transfer over to D. I decided to make my life easier and look for something that's just a single header file, and while that does make things easier there are a TON of macros and inline functions that it almost seems ridiculous and it's somewhat overwhelming.

Example without code; for some reason a macro is defined for the stdlib functions `malloc`, `realloc`, and `free`. Maybe it's just because I don't have any pro experience with C or C++, but that seems a bit excessive. Or I could just be dumb.

Example with code (because I need help figuring out how whether I even need this or not):

    #ifndef RS_API
    #ifdef RS_NOINLINE
    /* GCC version 3.1 required for the no inline attribute. */
    #if RS_GCC_VERSION > 30100
    #define RS_API static __attribute__((noinline))
    #elif defined(_MSC_VER)
    #define RS_API static __declspec(noinline)
    #else
    #define RS_API static
    #endif
    #elif RS_C99
    #define RS_API static inline
    #elif defined(__GNUC__)
    #define RS_API static __inline__
    #elif defined(_MSC_VER)
    #define RS_API static __forceinline
    #else
    #define RS_API static
    #endif
    #endif

I understand what it's doing, but do I really any of this with D? And then there's this inline function

    #define RS_DATA_SIZE(f, s, input)                                       \
	    do {                                                            \
		    if (rs_is_heap(input))                                  \
			    f(s, input->heap.buffer, rs_heap_len(input));   \
		    else                                                    \
			    f(s, input->stack.buffer, rs_stack_len(input)); \
	    } while (0)

so yea. There's a little over 300 lines of preprocessor stuff. My question is how you all determine what to carry over from C libs in terms of preprocessor stuff. I imagine most useful values everyone just makes an enum for, and structs and unions are kept.

Thanks for any help you give!
January 13, 2019
On Sunday, 13 January 2019 at 22:40:57 UTC, Alec Stewart wrote:
> Example without code; for some reason a macro is defined for the stdlib functions `malloc`, `realloc`, and `free`. Maybe it's just because I don't have any pro experience with C or C++, but that seems a bit excessive. Or I could just be dumb.
>

These three are members of the standard library in D.
https://dlang.org/phobos/core_memory.html

> Example with code (because I need help figuring out how whether I even need this or not):
>
>     #ifndef RS_API
>     #ifdef RS_NOINLINE
>     /* GCC version 3.1 required for the no inline attribute. */
>     #if RS_GCC_VERSION > 30100
>     #define RS_API static __attribute__((noinline))
>     #elif defined(_MSC_VER)
>     #define RS_API static __declspec(noinline)
>     #else
>     #define RS_API static
>     #endif
>     #elif RS_C99
>     #define RS_API static inline
>     #elif defined(__GNUC__)
>     #define RS_API static __inline__
>     #elif defined(_MSC_VER)
>     #define RS_API static __forceinline
>     #else
>     #define RS_API static
>     #endif
>     #endif
>
> I understand what it's doing, but do I really any of this with D? And then there's this inline function
>
>     #define RS_DATA_SIZE(f, s, input)
>           \
> 	    do {
>    \
> 		    if (rs_is_heap(input))                                  \
> 			    f(s, input->heap.buffer, rs_heap_len(input));   \
> 		    else                                                    \
> 			    f(s, input->stack.buffer, rs_stack_len(input)); \
> 	    } while (0)
>
> so yea. There's a little over 300 lines of preprocessor stuff. My question is how you all determine what to carry over from C libs in terms of preprocessor stuff. I imagine most useful values everyone just makes an enum for, and structs and unions are kept.
>
> Thanks for any help you give!

At first, I would suggest to try out some automatic converters, which are written by the community:
https://wiki.dlang.org/Bindings#Binding_generators
especially dstep and dpp

I had some ambivalent experience with the procedure of converting C --> D, but there is C code out there, which behaves very well in this respect... So, generally, I pursued the tactics of
automatic conversion
trying to compile
rewriting missing parts.

Also, if there is a possibility to compile the C/C++ library, you could provide the interface only to the functions you need. Then, you reuse the existent code directly and interface the library by declaring the interfaces as extern in your D sources.
https://dlang.org/spec/attribute.html#linkage
January 13, 2019
On Sunday, 13 January 2019 at 23:23:50 UTC, Alex wrote:
> These three are members of the standard library in D.
> https://dlang.org/phobos/core_memory.html
>


Ah, yea that's way easier.

> At first, I would suggest to try out some automatic converters, which are written by the community:
> https://wiki.dlang.org/Bindings#Binding_generators
> especially dstep and dpp
>


That would make it easier because there's a lot of preprocessor stuff that ends up being circular references if I use `enum` or `const`.

> Also, if there is a possibility to compile the C/C++ library, you could provide the interface only to the functions you need. Then, you reuse the existent code directly and interface the library by declaring the interfaces as extern in your D sources.
> https://dlang.org/spec/attribute.html#linkage


That would also be easier. :P Thanks!
January 14, 2019
On Sunday, 13 January 2019 at 22:40:57 UTC, Alec Stewart wrote:

>
> Example without code; for some reason a macro is defined for the stdlib functions `malloc`, `realloc`, and `free`. Maybe it's just because I don't have any pro experience with C or C++, but that seems a bit excessive. Or I could just be dumb.

Generally this is done to allow the compile-time configuration of memory allcoators. Back in my C days I had a little memory module that tracked total allocated and unallocated bytes and logged a few stats to a file at shutdown. I used macros to switch between it and the default stdlib calls.


> I understand what it's doing, but do I really any of this with D?

No.

> And then there's this inline function
>
>     #define RS_DATA_SIZE(f, s, input)
>           \
> 	    do {
>    \
> 		    if (rs_is_heap(input))                                  \
> 			    f(s, input->heap.buffer, rs_heap_len(input));   \
> 		    else                                                    \
> 			    f(s, input->stack.buffer, rs_stack_len(input)); \
> 	    } while (0)
>

Generally, this sort of thing can be moved into a D function or template if it's repeated in several places. Without the do...while, of course. And in case you're unfamiliar with its purpose here:

https://stackoverflow.com/questions/154136/why-use-apparently-meaningless-do-while-and-if-else-statements-in-macros