我需要在插件的主要可执行文件中使用一些符号.
链接可执行文件会导致以下链接器错误:
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链接到test.exe即可,
但是Windows加载器(或至少是酒类加载器)抱怨test.exe是dll.
因此,我需要在没有-shared的情况下再次重新链接test.exe,以便能够运行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++
那是超级骇客的,但最后我确实有一个有效的插件…
提出我的问题:
有没有更好的方法可以实现这一点(无需传递函数指针)?
我知道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在WinXP VM中映射为驱动器E :,并从MSYS Shell中调用):
$/e/foo.exe
16
FWIW,当将-shared属性添加到链接器调用时,我可以重现您无法创建可运行的可执行文件的情况;如您所注意到的,它是用于创建DLL的(它们与可执行文件的格式不同,只是在标头中嵌入了不同的幻数;否则,它们基本上是相同的).
综上所述:
>链接可执行文件时,请不要指定-shared.
>使用|来限定要从可执行文件中导出的符号
__declspec(dllexport)属性.
>请在-Wl,-out-implib = lib< exename> .dll.a属性时指定
链接可执行文件.