为啥“WinMain”在链接为 *.a 静态库时无法解析?
Posted
技术标签:
【中文标题】为啥“WinMain”在链接为 *.a 静态库时无法解析?【英文标题】:Why is "WinMain" unresolved when linked as a *.a static library?为什么“WinMain”在链接为 *.a 静态库时无法解析? 【发布时间】:2013-10-27 23:39:43 【问题描述】:给定一个简单的程序:
#include <windows.h>
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev,
LPSTR lpCmdLine, int nCmdShow)
return 0;
如果我运行g++ a.cpp
,它工作正常。
但是,运行 g++ -c a.cpp && ar rcs a.a a.o && g++ a.a
会出现以下错误:
c:/mingw32/bin/../lib/gcc/i686-w64-mingw32/4.8.1/../../../../i686-w64-mingw32/lib/../lib/libmingw32.a(lib32_libmingw32_a-crt0_c.o):crt0_c.c:(.text.startup+0x39): undefined reference to `WinMain@16'
collect2.exe: error: ld returned 1 exit status
关于为什么会发生这种情况的任何见解?如何链接一个只有 .a 文件的程序?
【问题讨论】:
【参考方案1】:gcc ld
链接器处理*.a
静态库与*.o
目标文件略有不同。特别是,静态库中的符号不会包含在最终的二进制映像可执行文件中,除非之前链接的目标文件或其他静态库使用它。
此外,您在静态库中传递的顺序对ld
很重要。例如,假设libb.a
需要liba.a
中的函数。如果你像这样链接它:
g++ -Wall example.cpp -o example.exe -la -lb
这将无法解决,因为在处理 liba
时,它看不到 -lb
需要哪些符号(libb
尚未处理)。从liba.a
检索到的唯一符号是它所看到的所有内容到那时。
为什么这很重要?
如果您将上述过程应用于您的问题,您就会清楚为什么 WinMain
没有得到解决。
g++ a.a
当ld
处理a.a
时,它会说“哦,没有使用WinMain
,所以我不会包含它”;这在处理点上是正确的,因为在它之前没有提供其他目标文件。
您在上面没有看到的是,默认情况下,mingw还包含一堆重要的样板代码,您的程序需要这些代码才能运行。其中之一是来自mingw32.a
的crt0_c.o
,它构成了mingw 运行时的一部分,确实调用了您的WinMain
。
解决方案
有两种方法可以确保包含来自您的a.a
的WinMain
:
使用-Wl,--whole-archive
强制包含a.a
中的所有符号,以便它们可用于符号解析。之后附加-Wl,--no-whole-archive
,这样它就不会错误地将其应用于后面的其他库。例如。
g++ -o example.exe -Wl,--whole-archive a.a -Wl,--no-whole-archive
第二种方法是手动包含mingw32.a
之前 a.a
因此WinMain
在处理a.a
时成为待处理的未解析符号:
g++ -o example.exe -lmingw32 a.a
或
g++ -o example.exe libmingw32.a a.a
但您可能需要完全限定libmingw32.a
的路径,否则链接器将找不到它。
【讨论】:
【参考方案2】:.a 文件是静态库,就链接器而言。链接器仅从定义当前未解析符号的档案中取出对象。因此,如果没有任何引用 .a 文件中定义的符号的目标文件,它们将不会被拉入。您示例中的链接器输出为空,因此未定义 WinMain。
实际上,当您定义标准 main() 时,它似乎可以工作。我认为这是因为语言标准需要对 main() 的引用。还有一个 gcc / ld 命令行选项来生成对符号的引用。尝试在 .a 文件前添加-u WinMain@16
。
【讨论】:
那么在 .a 中使用 WinMain 编译一个可执行文件是根本不可能的? 我已经以一种可能的方式进行了编辑,尽管我不知道这样做的全部意义。所有 .a 档案通常都是库,将您的实际程序放入其中是不寻常且令人困惑的,包括 main 函数。g++ -u WinMain@16 a.a
不起作用。我在我的项目中使用 .a 文件来模块化我的代码。比如说,我有子目录“core”、“graphics”、“input”,每个目录都是独立构建的,将其目标文件存档,那么最终的项目应该能够将存档文件链接在一起。
@user1641398 可以将 .a 用于模块,只是不要将您的入口点放入这些模块中。使main
(或WinMain
,在你的情况下)在一个目标文件中的静态库中发挥作用。【参考方案3】:
我正在使用 Code::Blocks。今天我在静态库中遇到了与 WinMain 相同的问题。在我的情况下,更改库的顺序不起作用。我终于通过将-lmingw32
添加到项目/构建选项/链接器设置/其他链接器选项来解决它。
【讨论】:
以上是关于为啥“WinMain”在链接为 *.a 静态库时无法解析?的主要内容,如果未能解决你的问题,请参考以下文章
为啥使用nar-maven编译静态库时添加编译器选项/MD?