链接到Windows上的可执行文件的正确方法是什么?

我需要使用插件中的主要可执行文件中的一些符号。

链接到可执行文件导致以下链接器错误:

i686-w64-mingw32-g++ example.cpp -shared -I.. -std=c++11 -o test.dll ../../test.exe -static-libgcc -static-libstdc++ -fvisibility=hidden [..]/test.exe:cygming-crtbegin.c:(.text+0x500): multiple definition of `__gcc_register_frame' /usr/lib/gcc/i686-w64-mingw32/5.1.0/crtbegin.o:cygming-crtbegin.c:(.text+0x0): first defined here [..]/test.exe:cygming-crtbegin.c:(.text+0x560): multiple definition of `__gcc_deregister_frame' /usr/lib/gcc/i686-w64-mingw32/5.1.0/crtbegin.o:cygming-crtbegin.c:(.text+0x60): first defined here [..]/test.exe: In function `ZlsRSoRK5Color': [..]src/tools.h:212: multiple definition of `operator<<(std::ostream&, Color const&)' /tmp/ccC97Hkz.o:example.cpp:(.text$_ZlsRSoRK5Color[__ZlsRSoRK5Color]+0x0): first defined here ../../test.exe: In function `ZN7MessageILb0EElsIcEERS0_OT_': [..]/src/tools.h:241: multiple definition of `Message<false>& Message<false>::operator<< <char>(char&&)' /tmp/ccC97Hkz.o:example.cpp:(.text$_ZN7MessageILb0EElsIcEERS0_OT_[__ZN7MessageILb0EElsIcEERS0_OT_]+0x0): first defined here [..]/test.exe:crtexe.c:(.idata+0x3f0): multiple definition of `_imp__GeoIP_country_code' [..]/test.exe:crtexe.c:(.idata+0x3f0): first defined here [..]/test.exe:crtexe.c:(.idata+0x3f4): multiple definition of `_imp__GeoIP_country_name' [..]/test.exe:crtexe.c:(.idata+0x3f4): first defined here /usr/lib/gcc/i686-w64-mingw32/5.1.0/crtbegin.o:cygming-crtbegin.c:(.text+0x22): undefined reference to `_Jv_RegisterClasses' collect2: error: ld returned 1 exit status 

现在,如果我用-shared -Wl,--export-all-symbols生成主要的可执行文件-shared -Wl,--export-all-symbols然后链接到test.exe工作,但Windows加载器(或至less酒的一个)抱怨test.exe是一个DLL。

所以我需要重新链接test.exe没有-shared所以我能够运行test.exe

即:

 # produce the import executable i686-w64-mingw32-g++ tools.o main.o [...] -o ../test.exe -shared -Wl,--export-all-symbols [...] -static-libgcc -static-libstdc++ # produce the real executable i686-w64-mingw32-g++ tools.o main.o [...] -o ../test.exe -Wl,--export-all-symbols [...] -static-libgcc -static-libstdc++ 

这是超级hackish,但最后我有一个工作插件…

回到我的问题:

有没有更好的方法来实现这个(不传递函数指针)?

我知道MSVC能够输出可执行文件的导入库,对于MinGW有没有类似的方法?

我已经尝试添加-Wl,--out-implib,test.a到链接器标志以获得可执行文件的导入库,但--out-implib在链接可执行文件时似乎被忽略。

在这种情况下,您可能希望使用__declspec(dllexport)属性在.exe限定回调符号。 在我的Linux Mint Debian盒子上交叉编译,以下最简单的例子适用于我:

 $ cat foo.c #include <stdio.h> int __declspec(dllexport) foo( int bar ){ return bar << 2; } int main(){ printf( "%d\n", foo( 4 ) ); return 0; } $ mingw32-gcc -o ~/src/exp/foo.exe -Wl,--out-implib=libfoo.dll.a foo.c 

这将生成一个工作可执行文件一个导入库来映射其导出的符号,以便在链接插件时使用,只需在前面的命令中调用一个链接器即可(如在wine下运行可执行文件时所看到的,使用本机linux nm工具导入库):

 $ ~/src/exp/foo.exe 16 $ nm -A libfoo.dll.a libfoo.dll.a:d000002.o:00000000 I _foo_exe_iname libfoo.dll.a:d000002.o:00000000 i .idata$4 libfoo.dll.a:d000002.o:00000000 i .idata$5 libfoo.dll.a:d000002.o:00000000 i .idata$7 libfoo.dll.a:d000000.o: U _foo_exe_iname libfoo.dll.a:d000000.o:00000000 I __head_foo_exe libfoo.dll.a:d000000.o:00000000 i .idata$2 libfoo.dll.a:d000000.o:00000000 i .idata$4 libfoo.dll.a:d000000.o:00000000 i .idata$5 libfoo.dll.a:d000001.o:00000001 a @feat.00 libfoo.dll.a:d000001.o:00000000 T _foo libfoo.dll.a:d000001.o: U __head_foo_exe libfoo.dll.a:d000001.o:00000000 i .idata$4 libfoo.dll.a:d000001.o:00000000 i .idata$5 libfoo.dll.a:d000001.o:00000000 i .idata$6 libfoo.dll.a:d000001.o:00000000 i .idata$7 libfoo.dll.a:d000001.o:00000000 I __imp__foo libfoo.dll.a:d000001.o:00000000 t .text 

同样,WinXP中的可执行文件运行得很好(在LMDE框的VirtualBox中运行,〜/ src / exp映射为驱动器E:在WinXP虚拟机中,并从MSYS shell调用):

 $ /e/foo.exe 16 

FWIW,当将-shared属性添加到链接器调用时,我可以重现您创建可运行可执行文件的失败; 正如你注意到的那样,它是用来创建DLL的(不同于可执行文件格式, 只是在头文件中嵌入了不同的幻数),否则它们基本上是相同的。

综上所述:

  • 链接可执行文件时不要指定-shared

  • 使用__declspec(dllexport)属性限定要从可执行文件导出的符号。

  • 链接可执行文件时-Wl,--out-implib=lib<exename>.dll.a指定-Wl,--out-implib=lib<exename>.dll.a属性。

基思·马歇尔Keith Marshall )在评论中指出的那样,“ -Wl,--out-implib实际上可以与以下任何一种结合起来:

  • -Wl,--export-all-symbols

  • 通过用__declspec(dllexport)声明符号

  • 或通过提供一个.def文件

我去了第三个选项,并写了一个bash脚本来生成一个def文件/版本脚本,以避免导出大量不需要的符号。

脚本可以在这里找到。

像这样使用它:

 export SYMBOLS_TO_EXPORT="*tools* *network* _Z8compressPvRjPKvjib ..." # use mangled names and skip leading underscores on i686 export HOSTPREFIX=i686-w64-mingw32 # unneeded on Windows i686-w64-mingw32-g++ $(OBJS) `./gen_export_file $(OBJS)` -Wl,--out-implib=foo.exe.a -o foo.exe