связывая дилемму (неопределенная ссылка) между MinGW и MSVC. MinGW не работает MSVC

Я пытаюсь перенести старую библиотеку C .dll, изначально выполненную с помощью MSVC, которая использует библиотеку BEA Tuxedo для использования MinGW.

Я столкнулся с ситуацией, когда MSVC компилирует и связывает один файл, но MinGW терпит неудачу. Реальная проблема заключается в стадии связывания. Появляется ошибка «неопределенной ссылки».

Вот минимальный пример создания dll: (tpsetunsol_test.c)

#include  void __stdcall msghandler(char *pszMessage, long lMessageLen, long lFlags) { } int Inittpsetunsol() { int ret = 0; tpsetunsol(msghandler); return ret; } 

Это компилируется без ошибок:

 gcc -Wall -fexceptions -g -O2 -DWIN32 -DNDEBUG -D_WINDOWS -ID:/dev/tuxedo/include -o tpsetunsol_test.o -c tpsetunsol_test.c 

Приходит ошибка:

 dllwrap --export-all-symbols -LD:/dev/tuxedo/lib -k --output-lib test.lib --output-def test.def --enable-stdcall-fixup --add-stdcall-alias -o IAWS.dll tpsetunsol_test.o -lkernel32 -luser32 -lgdi32 -lwinspool -lcomdlg32 -ladvapi32 -lshell32 -lwtuxws32 C:\MinGW\bin\dllwrap.exe: no export definition file provided. Creating one, but that may not be what you want tpsetunsol_test.o: In function `Inittpsetunsol': d:\dev\tpsetunsol_test.c:13: undefined reference to `tpsetunsol' collect2.exe: error: ld returned 1 exit status C:\MinGW\bin\dllwrap.exe: C:\MinGW\bin\gcc exited with status 1 

Объявление функции atmi.h:

 extern void (_TMDLLENTRY * _TMDLLENTRY tpsetunsol _((void (_TMDLLENTRY *)(char _TM_FAR *, long, long)))) _((char _TM_FAR *, long, long)); #define _TMDLLENTRY __stdcall #define _TM_FAR 

Версия:

 $ gcc -v Using built-in specs. COLLECT_GCC=C:\MinGW\bin\gcc.exe COLLECT_LTO_WRAPPER=c:/mingw/bin/../libexec/gcc/mingw32/4.7.2/lto-wrapper.exe Target: mingw32 Configured with: ../gcc-4.7.2/configure --enable- languages=c,c++,ada,fortran,objc,obj-c++ --disable-sjlj-exceptions --with-dwarf2 --enable-shared --enable-libgomp --disable-win32-registry --enable-libstdcxx-debug --disable-build-poststage1-with-cxx --enable-version-specific-runtime-libs --build=ming w32 --prefix=/mingw Thread model: win32 gcc version 4.7.2 (GCC) 

Изменить: я обнаружил использование nm на объектных файлах, созданных MSVC и GCC, что символ tpsetunsol отличается

Глядя на символ _tpsetunsol, совершенно очевидно, что MSVC и GCC создают разные символы.

GCC производит: U _tpsetunsol и MSVC: U _tpsetunsol@4

Edit: nm output после сборки с предложением Haroogan:

 $ dllwrap --export-all-symbols -LD:/dev/tuxedo.64/lib --output-lib test.lib --output-def test.def -o IAWS.dll tpsetunsol_test.o -lwtuxws32_new C:\MinGW\bin\dllwrap.exe: no export definition file provided. Creating one, but that may not be what you want tpsetunsol_test.o: In function `Inittpsetunsol': d:\dev\IA/tpsetunsol_test.c:13: undefined reference to `tpsetunsol' collect2.exe: error: ld returned 1 exit status C:\MinGW\bin\dllwrap.exe: C:\MinGW\bin\gcc exited with status 1 $ nm tpsetunsol_test.o 00000000 b .bss 00000000 d .data 00000000 N .debug_abbrev 00000000 N .debug_aranges 00000000 N .debug_info 00000000 N .debug_line 00000000 N .debug_loc 00000000 r .eh_frame 00000000 t .text 00000004 T _Inittpsetunsol 00000000 T _msghandler@12 U _tpsetunsol $ nm ../tuxedo.64/lib/libwtuxws32.a | grep -i tpsetuns 00000000 I __imp__tpsetunsol@4 00000000 T _tpsetunsol@4 

вывод из препроцессора gcc (-E) (объявляется только строка tpsetunsol)

 extern void (__attribute__((__stdcall__)) * __attribute__((__stdcall__)) tpsetunsol (void (__attribute__((__stdcall__)) *)(char *, long, long))) (char *, long, long); 

Измените объявление tpsetunsol() в заголовке atmi.h :

 extern void (_TMDLLENTRY * _TMDLLENTRY tpsetunsol _((void (_TMDLLENTRY *)(char _TM_FAR *, long, long)))) _((char _TM_FAR *, long, long)); 

чтобы:

 extern void (_TMDLLENTRY * (_TMDLLENTRY tpsetunsol) _((void (_TMDLLENTRY *)(char _TM_FAR *, long, long)))) _((char _TM_FAR *, long, long)); // ^ ^ 

поэтому функция будет правильно объявлена ​​как функция stdcall как она находится в библиотеке (как указано суффиксом @4 в имени в библиотеке).

Как вы уже обнаружили, вы можете указать, что для компиляторов могут быть разные имена . Чтобы решить вашу проблему, следуйте инструкциям:

  1. Загрузите и установите (можете создать из источника) утилиту gendef :

    • Если у вас есть обычный MinGW (таргетинг 32-разрядный), то получите его здесь ;
    • Если у вас есть MinGW-w64 (таргетинг на 64-разрядный), то получите его здесь .
  2. Запустите gendef wtuxws32.dll (сгенерирует wtuxws32.def );

  3. Запустите dlltool -D wtuxws32.dll -d wtuxws32.def -l libwtuxws32.a (сгенерирует libwtuxws32.a );

  4. Поместите libwtuxws32.a в D:/dev/tuxedo/lib ;

  5. Теперь ссылка на него.