在Windows上链接可执行文件的正确方法是什么? [英] What's the proper way to link against an executable on Windows?

查看:125
本文介绍了在Windows上链接可执行文件的正确方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to use some symbols from the main executable in a plugin.

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

Linking against the executable causes the following linker errors:

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.

Now if I build the main executable with -shared -Wl,--export-all-symbols then linking against test.exe works, but the Windows loader (or at least the wine one) complains about test.exe being a dll.

所以我需要在没有-shared的情况下再次重新链接test.exe,这样我才能运行test.exe.

So I need to re-link test.exe once again without -shared so I am able to run 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++

那是超级黑客,但最后我确实有一个有效的插件...

That's super hackish, but at the end I do have a working plugin...

提出我的问题:

是否有更好的方法可以实现这一点(无需传递函数指针)?

我知道MSVC能够输出可执行文件的导入库,MinGW是否有类似的方式?

I know MSVC is able to output import libraries for executables, is there a similar way for MinGW?

我试图将-Wl,--out-implib,test.a添加到链接器标志中,以获取可执行文件的导入库, 但是--out-implib似乎在链接可执行文件时会被忽略.

I have tried to add -Wl,--out-implib,test.a to the linker flags to get an import library for the executable, but --out-implib seems to be ignored when linking an executable.

推荐答案

在这种情况下,您可能要做想要用__declspec(dllexport)限定.exe中的回调符号.属性.在我的Linux Mint Debian机器上交叉编译,以下最小示例对我有用:

This is a case where you probably do want to qualify the callback symbols, in the .exe, with the __declspec(dllexport) attribute. Cross-compiling on my Linux Mint Debian box, the following minimal example works for me:

$ 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工具列出导入库时所见):

This produces both a working executable, and an import library to map its exported symbols, for use when linking plug-ins, with just one invocation of the linker in the preceding commands, (as seen when running the executable under wine, and listing the import library using the native linux nm tool):

$ ~/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中调用):

Likewise, the executable runs just fine in WinXP, (running within VirtualBox on the LMDE box, with ~/src/exp mapped as drive E: in the WinXP VM, and invoked from the MSYS shell):

$ /e/foo.exe
16

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

FWIW, I can reproduce your failure to create a runnable executable, when adding the -shared attribute to the linker invocation; as you note, that is intended for creating DLLs, (which differ from executables in format only in having a different magic number embedded in the header; otherwise they are fundamentally the same).

总结:

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

对要从可执行文件中导出的符号进行限定 __declspec(dllexport)属性.

Do qualify symbols to be exported from the executable with the __declspec(dllexport) attribute.

在以下情况下请指定-Wl,--out-implib=lib<exename>.dll.a属性 链接可执行文件.

Do specify the -Wl,--out-implib=lib<exename>.dll.a attribute, when linking the executable.

这篇关于在Windows上链接可执行文件的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆