pythondllmingwstdcall

Missing leading underscore in exported stdcall functions with minGW


I am maintaining some DLL for Windows that is delivered in 32 and 64 bit versions. It has been build with Visual Studio 2010, but for some reasons I recently changed to MinGW (7.3, also tried 9.2). For the 64 bit version everything seems to be ok, but the 32 bit version doesn't work when loaded in Python or LabView; both can load the DLL but don't find the functions. A simplified example:

// mydll.h
extern "C" __declspec(dllexport) int __stdcall myFunc( int x );

// mydll.cpp
#include "mydll.h"
int _stdcall myFunc( int x )
{
  return 2*x;
}

# test.py
import ctypes
lib = ctypes.windll.LoadLibrary('.\mydll.dll')
lib.myFunc.argtypes = [ctypes.c_int32]
print(lib.myFunc(1))

Commands, using MinGW 7.3 and Python 3.7.2 (32 bit):

> g++ -shared -o mydll.dll mydll.cpp
> python test.py
Traceback (most recent call last):
  File "test.py", line 3, in <module>
    print(lib.myFunc(1))
  ...
AttributeError: function 'myFunc' not found

The same code runs and prints "2" when compiled with MSVC-32bit or with MinGW-64bit.

Why doesn't it work with MinGW-32bit? I suspect it's an issue of the C name mangling: The exported symbol names of the DLL as reported by "dumpbin /exports mydll.dll" are _myFunc@4 (MSVC) and myFunc@4 (MinGW) - MinGW's output misses a leading underscore. As far as I understand, Python and LV expect the mangled names in the MSVC style (and hide the mangling in their user interface).

I have tried a couple of MinGW Options such as -Wl,-fleading_underscore, -Wl,--add-stdcall-alias, -Wl,--enable-stdcall-fixup to achieve compatible export names, but without success. One would expect that this is a common problem as the combination C/Python isn't really exotic, but I can't find any discussion of the problem on the net. What I am doing wrong?


Solution

  • I ran into the same problem. Theoretically dlltool might be able to help somehow, with its --add-stdcall-underscore option, but I couldn't get that to work.. it sucks that MinGW's ld doesn't have that option.

    Anyway, I found another solution: Create your own mydll.def file with aliases, like

    LIBRARY "mydll.dll"
    EXPORTS
    
    myFunc@4
    _myFunc@4 = myFunc@4
    
    myFunc2@42
    _myFunc2@42 = myFunc2@42
    

    (Using the gendef tool on your current state of the DLL could help to get an initial version of that .def, but it was a bit buggy for me, generating both myfunc@4 and myfunc@4@4 lines)

    Then build the DLL with g++ -shared -o mydll.dll mydll.def mydll.cpp

    You could also add -Wl,--add-stdcall-alias to also automatically create aliases without the @4 at the end (might be necessary to make GetProcAddress(myDllHandle, "myFunc"); work?), and it may be a good idea to use --static-libgcc so your DLL works without bundling libgcc_s_dw2-1.dll.