MinGW和MSVC之间的链接困境(未定义的引用)。MinGW未能通过MSVC工程

MinGW和MSVC之间的链接困境(未定义的引用)。MinGW未能通过MSVC工程,c,visual-c++,dll,interop,mingw,C,Visual C++,Dll,Interop,Mingw,我正在尝试移植一个旧的C.dll库,它最初是用MSVC完成的,它使用BEA Tuxedo库来使用MinGW 我遇到过这样一种情况,MSVC编译并链接一个文件,但MinGW失败了。实际问题是在连接阶段。出现“未定义引用”错误 下面是创建dll的最简单示例:(tpsetunsol_test.c) 下面是错误: dllwrap --export-all-symbols -LD:/dev/tuxedo/lib -k --output-lib test.lib --output-def test.def

我正在尝试移植一个旧的C.dll库,它最初是用MSVC完成的,它使用BEA Tuxedo库来使用MinGW

我遇到过这样一种情况,MSVC编译并链接一个文件,但MinGW失败了。实际问题是在连接阶段。出现“未定义引用”错误

下面是创建dll的最简单示例:(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)
编辑:我发现在MSVC和GCC创建的对象文件上使用nm时,符号TPSETUNSUR是不同的

查看TPSETUNSOR符号,很明显MSVC和GCC产生不同的符号

GCC生产:
U\U tpsetunsol
和MSVC:
U_tpsetunsol@4

编辑:根据Haroogan的建议构建后的nm输出:

$ 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)


正如您已经发现的那样,可能在不同的编译器中有所不同。要解决问题,请按照说明进行操作:

  • 下载并安装(可以从源代码构建)
    gendef
    实用程序:

    • 如果您有常用的(目标为32位),则获取它
    • 如果您有(目标为64位),则获取
  • 运行
    gendef wtuxws32.dll
    (将生成
    wtuxws32.def

  • 运行
    dlltool-D wtuxws32.dll-D wtuxws32.def-l libwtuxws32.a
    (将生成
    libwtuxws32.a

  • 将libwtuxws32.a放到
    D:/dev/tuxedo/lib

  • 现在链接到它


  • 正如您已经发现的那样,可能在不同的编译器中有所不同。要解决问题,请按照说明进行操作:

  • 下载并安装(可以从源代码构建)
    gendef
    实用程序:

    • 如果您有常用的(目标为32位),则获取它
    • 如果您有(目标为64位),则获取
  • 运行
    gendef wtuxws32.dll
    (将生成
    wtuxws32.def

  • 运行
    dlltool-D wtuxws32.dll-D wtuxws32.def-l libwtuxws32.a
    (将生成
    libwtuxws32.a

  • 将libwtuxws32.a放到
    D:/dev/tuxedo/lib

  • 现在链接到它


  • atmi.h
    标题中的
    tpsetunsol()
    声明更改为:

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


    因此,函数将正确声明为库中的
    stdcall
    函数(如库中名称上的
    @4
    后缀所示)。

    atmi.h
    标题中的
    tpsetunso()
    声明更改为:

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


    因此,函数将正确地声明为库中的
    stdcall
    函数(如库中名称上的
    @4
    后缀所示)?MinGW显然不会将名称与
    @4
    相混淆,因为它无法识别它应该是
    \uu stdcall
    ,因为声明函数时
    \u TMDLLENTRY
    可能为空。这正是GCC处理和实现此类限定符的方式。摘录:您还可以在每个关键字前面和后面指定属性。这允许您在头文件中使用它们,而不必担心可能的同名宏。例如,您可以使用
    \uuuu noreturn\uuu
    而不是
    noreturn
    。当然,您不能简单地在
    *.def
    lib*.a
    文件中调用函数,因为在
    *.dll
    中它仍然被损坏,您将在运行时崩溃。MinGW必须知道它是
    stdcall
    。我猜是不是atmi.h中的函数指针声明与GCC不兼容?你知道
    tpsetunsol
    是在哪里定义的吗?@Haroogan是的,它是在一个BEA Tuxedo Library中定义的为什么
    #define"TMDLLENTRY"stdcall
    #define"TM"FAR
    都在函数声明之后?MinGW显然不会将名称与
    @4
    相混淆,因为它无法识别它应该是
    \uu stdcall
    ,因为声明函数时
    \u TMDLLENTRY
    可能为空。这正是GCC处理和实现此类限定符的方式。摘录:您还可以在每个关键字前面和后面指定属性。这允许您在头文件中使用它们,而不必担心可能的同名宏。例如,您可以使用
    \uuuu noreturn\uuu
    而不是
    noreturn
    。当然,您不能简单地在
    *.def
    lib*.a
    文件中调用函数,因为在
    *.dll
    中它仍然被损坏,您将在运行时崩溃。MinGW必须知道它是stdcall。谢谢你的回答。尝试过这个,但仍然不起作用。gendef生成了wtuxws32.def文件,并将tpsetunsol解析为:tpsetunsol@4-这与原始wtuxws32.lib中的相同。GCC编译器生成TPSETUNSUNS符号(注意最后缺少@4)。我在正确的轨道上吗?尝试删除
    --添加stdcall别名
    --启用stdcall fixup
    。不,它不会链接。添加了链接器的一些输出,以及库和对象文件中的nm,谢谢您的回答。尝试过这个,但仍然不起作用。gendef生成了wtuxws32.def文件并解析了tpsetu
    extern void (__attribute__((__stdcall__)) * __attribute__((__stdcall__)) tpsetunsol (void (__attribute__((__stdcall__)) *)(char *, long, long))) (char *, long, long);
    
    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));
    //                          ^                      ^