4

I use and Application compiled with the Visual C++ Compiler. It can load plugins in form of a .dll. It is rather unimportant what exactly it does, fact is:

UML Diagram

This includes calling functions from the .dll that return a pointer to an object of the Applications API, etc.

My question is, what problems may appear when the Application calls a function from the .dll, retrieves a pointer from it and works with it. For example, something that comes into my mind, is the size of a pointer. Is it different in VC++ and G++? If yes, this would probably crash the Application?

I don't want to use the Visual Studio IDE (which is unfortunately the "preferred" way to use the Applications SDK). Can I configure G++ to compile like VC++?

PS: I use MINGW GNU G++

Niklas R
  • 16,299
  • 28
  • 108
  • 203
  • 2
    What is "G++" ? Do you mean, the GNU C++ compiler ("g++"), which I assume is some variation of MinGW. Yes? – selbie Feb 03 '12 at 22:06
  • Yes, you are correct. I will ad this to the question. – Niklas R Feb 03 '12 at 22:11
  • You can always serialize/marshal/(many other names) any structures you send. Just google c++ stuct padding to understand any issues you may have. If you treat data like you would to a file or network you will be ok. You can cut corners on how detailed your headers are, just make sure data is in right places (ie no padding) – Joe McGrath Feb 03 '12 at 22:17
  • Where'd that graph come from? I like the style. – ssube Feb 03 '12 at 22:41
  • @peachykeen checkout [yuml.me](http://yuml.me) – Niklas R Feb 03 '12 at 22:43

6 Answers6

7

As long as both application and DLL are compiled on the same machine, and as long as they both only use the C ABI, you should be fine.

What you can certainly not do is share any sort of C++ construct. For example, you mustn't new[] an array in the main application and let the DLL delete[] it. That's because there is no fixed C++ ABI, and thus no way in which any given compiler knows how a different compiler implements C++ data structures. This is even true for different versions of MSVC++, which are not ABI-compatible.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
4

All C++ language features are going to be entirely incompatible, I'm afraid. Everything from the name-mangling to memory allocation to the virtual-call mechanism are going to be completely different and not interoperable. The best you can hope for is a quick, merciful crash.

If your components only use extern "C" interfaces to talk to one another, you can probably make this work, although even there, you'll need to be careful. Both C++ runtimes will have startup and shutdown code, and there's no guarantee that whichever linker you use to assemble the application will know how to include this code for the other compiler. You pretty much must link g++-compiled code with g++, for example.

If you use C++ features with only one compiler, and use that compiler's linker, then it gets that much more likely to work.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
  • 1
    The OP is talking about using a plugin in the form of a DLL. That always works just fine, as long as only C data structures are passed back and forth. (What you said about the linker, while true, is not relevant here.) – markgz Feb 03 '12 at 22:19
4

This should be OK if you know what you are doing. But there's some things to watch out for:

I'm assuming the interface between EXE and DLL is a "C" interface or something COM like where the only C++ classes exposed are through pure-virutal interfaces. It gets messier if you are exporting a concrete class through a DLL.

  1. 32-bit vs. 64bit. The 32-bit app won't load a 64-bit DLL and vice-versa. Make sure they match.

  2. Calling convention. __cdecl vs __stdcall. Often times Visual Studio apps are compiled with flags that assuming __stdcall as the default calling convention (or the function prototype explicitly says so). So make sure that the g++ compilers generates code that matches the calling type expected by the EXE. Otherwise, the exported function might run, but the stack can get trashed on return. If you debug through a crash like this, there's a good chance the cdecl vs stdcall convention was incorrectly specified. Easy to fix.

  3. C-Runtimes will not likely be shared between the EXE and DLL, so don't mix and match. A pointer allocated with new or malloc in the EXE should not be released with delete or free in the DLL (and vice versa). Likewise, FILE handles returned by fopen() can not be shared between EXE and DLL. You'll likely crash if any of this happens.... which leads me to my next point....

  4. C++ header files with inline code cause enough headaches and are the source of issues I called out in #3. You'll be OK if the interface between DLL And EXE is a pure "C" interface.

  5. Name mangling issues. If you run into issues where the function name exported doesn't match because of name mangling or because of a leading underscore, you can fix that up in a .DEF file. At least that's what I've done in the past with Visual Studio. Not sure if the equivalent exists in g++/MinGW. Example below. Learn to use "dumpbin.exe /exports" to you can validate your DLL is exporting function with the right name. Using extern "C" will also help fix this as well.

     EXPORTS
      FooBar=_Foobar@12
      BlahBlah=??BlahBlah@@QAE@XZ @236 NONAME
    

Those are the issues that I know of. I can't tell you much more since you didn't explain the interface between the DLL and EXE.

selbie
  • 100,020
  • 15
  • 103
  • 173
1

The size of a pointer won't vary; that is dependent on the platform and module bitness and not the compiler (32-bit vs 64-bit and so on).

What can vary is the size of basically everything else, and what will vary are templates.

Padding and alignment of structs tends to be compiler-dependent, and often settings-within-compiler dependent. There are so loose rules, like pointers typically being on a platform-bitness-boundary and bools having 3 bytes after them, but it's up to the compiler how to handle that.

Templates, particularly from the STL (which is different for each compiler) may have different members, sizes, padding, and mostly anything. The only standard part is the API, the backend is left to the STL implementation (there are some rules, but compilers can still compile templates differently). Passing templates between modules from one build is bad enough, but between different compilers it can often be fatal.

Things which aren't standardized (name mangling) or are highly specific by necessity (memory allocation) will also be incompatible. You can get around both of those issues by only destroying from the library that creates (good practice anyway) and using STL objects that take a deleter, for allocation, and exporting using undecorated names and/or the C style (extern "C") for exported methods.

I also seem to remember a catch with how the compilers handle virtual destructors in the vtable, with some small difference.

If you can manage to only pass references of your own objects, avoid externally visible templates entirely, work primarily with pointers and exported or virtual methods, you can avoid a vast majority of the issues (COM does precisely this, for compatibility with most compilers and languages). It can be a pain to write, but if you need that compatibility, it is possible.

To alleviate some, but not all, of the issues, using an alternate to the STL (like Qt's core library) will remove that particular problem. While throwing Qt into any old project is a hideous waste and will cause more bloat than the "boost ALL THE THINGS!!!" philosophy, it can be useful for decoupling the library and the compiler to a greater extent than using a stock STL can.

ssube
  • 47,010
  • 7
  • 103
  • 140
0

The main problems are the function signatures and way parameters are passed to library code. I've had great difficulty getting VC++ dll's to work in gnu based compilers in the past. This was way back when VC++ always cost money and mingw was the free solution.

My experience was with DirectX API's. Slowly a subset got it's binaries modified by enthusiasts but it was never as up-to-date or reliable so after evaluating it I switched to a proper cross platform API, that was SDL.

This wikipedia article describes the different ways libraries can be compiled and linked. It is rather more in depth than I am able to summarise here.

John
  • 6,433
  • 7
  • 47
  • 82
0

You can't pass C runtime objects between them. For example you can not open a FILE buffer in one and pass it to be used in the other. You can't free memory allocated on the other side.

MK.
  • 33,605
  • 18
  • 74
  • 111
  • Hm, the latter would not apply. The API implements it's own memory-organisation. But every object that "comes from" the Application is freed by the Application, and the other way round. The first is more what makes me headache. E.g. there is a class (think of any), I allocate it in the G++ compiled `.dll` and a pointer to it is passed to the Application, can it work with it? – Niklas R Feb 03 '12 at 22:14
  • Passing pointers should be OK assuming the fields are aligned (packed) exactly the same way on both sides. – MK. Feb 03 '12 at 22:16
  • Passing a pointer to a class to the other side and dereferencing it on that side will not work at all. – markgz Feb 03 '12 at 22:21
  • @markgz Although they are aligned equally? Isn't there the possibility to say G++ to represent the data-structures like Vc++ does? – Niklas R Feb 03 '12 at 22:28
  • actually here's a duplicate question http://stackoverflow.com/questions/440161/c-dll-compatibility-between-compilers – MK. Feb 03 '12 at 22:47
  • @NiklasR: structure fields will have the same alignment, provided that there are no bit-fields. Calling a method will fail, hopefully resulting in a crash. – markgz Feb 03 '12 at 23:45
  • @MK. Thanks! I haven't found this one, very nice answer there. – Niklas R Feb 04 '12 at 08:38