Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this interface binary compatible between MSVC and mingw?

I am working on a library that allows its users (other libraries residing in the same process) to exchange data buffers and streams. The library has to be usable from both MSVC and mingw code (more compatibility doesn't hurt, but is not strictly necessary). In order to achieve this, the core functionality should be provided from a small, compiler-compatible interface that can be hidden later by a convenience layer that is compiled with the client code.

A challenging aspect of the library is that it has to be extensible, so that clients can provide their own buffer and stream implementations, but the core library interface must remain stable once it is released. If you are interested in further background, you can read about it in the forum thread discussion.

I have tried to learn about problems of binary compatibility between compilers, but since I am new to this topic I would be interested in comments on my result. I am not interested in standards-defined behaviour here (the structs probably fail that test), only in compatibility between mingw and MSVC and maybe other compilers if conveniently possible.

In particular, will the structs be compatible? They uniformly consist of function pointers, so I don't think padding will be an issue. Additionally, is the stdcall convention necessary here, or would cdecl work just as well? Could I leave it unspecified then since both compilers will default to cdecl? Should I? Here is what I have right now:

#include <stdint.h>

typedef struct {
        uint32_t (__stdcall *read)(void*, uint8_t*, uint32_t);
        void (__stdcall *write)(void*, const uint8_t*, uint32_t);
        uint32_t (__stdcall *getBytesLeft)(void*);
        uint8_t (__stdcall *destroy)(void*);
} SharedStreamInterface;

typedef struct {
        uint32_t (__stdcall *read)(void*, uint8_t*, uint32_t);
        void (__stdcall *write)(void*, const uint8_t*, uint32_t);
        uint32_t (__stdcall *getBytesLeft)(void*);
        uint8_t (__stdcall *destroy)(void*);

        uint32_t (__stdcall *getreadpos)(void*);
        uint32_t (__stdcall *getwritepos)(void*);
        uint32_t (__stdcall *getlength)(void*);
        void (__stdcall *setreadpos)(void*, uint32_t);
        void (__stdcall *setwritepos)(void*, uint32_t);
        void (__stdcall *setlength)(void*, uint32_t);
} SharedBufferInterface;

extern "C" {
        // Functions applicable for both buffers and streams
        __stdcall uint32_t readData(uint32_t id, uint8_t* data, uint32_t size);
        __stdcall void writeData(uint32_t id, const uint8_t* data, uint32_t size);
        __stdcall uint32_t getBytesLeft(uint32_t id);
        __stdcall void destroyStreamOrBuffer(uint32_t id);
        __stdcall uint8_t streamOrBufferExists(uint32_t id);

        // Functions only applicable for buffers
        __stdcall uint32_t getReadPos(uint32_t id);
        __stdcall uint32_t getWritePos(uint32_t id);
        __stdcall uint32_t getLength(uint32_t id);
        __stdcall void setReadPos(uint32_t id, uint32_t pos);
        __stdcall void setWritePos(uint32_t id, uint32_t pos);
        __stdcall void setLength(uint32_t id, uint32_t length);
        __stdcall uint8_t bufferExists(uint32_t id);

        // Adding new buffers/Streams
        __stdcall uint32_t addStream(SharedStreamInterface *interface, void *stream);
        __stdcall uint32_t addBuffer(SharedBufferInterface *interface, void *buffer);
}

Edit: The project this was meant for has been on hold for a while now and probably needs a lot of rethinking if it's ever unshelved again. I'm leaving the question up though, because I'm still interested in the answer.

like image 874
Medo42 Avatar asked May 22 '11 10:05

Medo42


People also ask

Should I use MinGW or MSVC?

Is MinGW (MinGW-64) better than Cygwin in terms of MSVC alternative for creating Windows application? If your program will run only on Windows, then MinGW is likely the better choice. MinGW is designed to create Windows applications. It doesn't require users to install additional software to run your application.

Is MinGW a compiler or ide?

MinGW is a compiler system based on the GNU GCC and Binutils projects that compiles and links code to be run on Win32 (Windows) systems. It provides C, C++ and Fortran compilers plus other related tools. 'MinGW' refers to the "Minimalist GNU for Windows" project.

What does MinGW do?

MinGW ("Minimalist GNU for Windows"), formerly mingw32, is a free and open source software development environment to create Microsoft Windows applications.


1 Answers

Yes, they will be compatible. That's the beauty with structs. As long as you don't introduce padding issues (which indeed wouldn't be the case here as you correctly pointed out), or in C++ add functionality to the structs that will result in - compiler-specific - vtable layouts, this will be always compatible.

You will also notice that from the Windows headers the C declarations of COM interfaces use structs in much the same way you do.

Side-note: the SharedStreamInterface::destroy member begs the question whether there is also one to "create" such a stream. You may want to share that as well. But your mileage may vary ...

As for the question of the calling convention, both __cdecl and __stdcall should work across the binaries, however I would always prefer __stdcall for another reason: it is compatible with more "languages" (i.e. tools) than __cdecl.

For style: use a #define to declare the calling convention explicitly (as you do) similar to WINAPI from the Windows headers.

like image 73
0xC0000022L Avatar answered Sep 30 '22 18:09

0xC0000022L