为啥“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 &amp;&amp; ar rcs a.a a.o &amp;&amp; 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.acrt0_c.o,它构成了mingw 运行时的一部分,确实调用了您的WinMain

解决方案

有两种方法可以确保包含来自您的a.aWinMain

    使用-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?

链接静态库时链接器可以省略目标文件吗?

typedef 结构在链接静态库时会导致名称冲突吗?

当存在同名的共享库时,如何强制链接静态库

qt creator qt5.1 vs2010 使用静态库时链接器错误

DEBUG 为 False 时无静态文件