为什么" WinMain"链接为* .a静态库时未解析?

时间:2013-10-27 23:39:43

标签: c++ gcc mingw

给出一个简单的程序:

#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文件链接程序?

3 个答案:

答案 0 :(得分:6)

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所以我不会包含它”;并且在那个处理点上确实如此,因为在它之前没有提供其他目标文件。

上面没有看到的是,默认情况下, 还包括 程序运行所需的一堆重要样板代码。其中一个是来自crt0_c.o的{​​{1}},它构成了 调用您的mingw32.a的mingw运行时的一部分。

解决方案

有两种方法可以确保WinMain中包含WinMain

  1. 使用a.a强制在-Wl,--whole-archive中包含所有符号,以便它们可用于符号解析。之后附加a.a,以便它不会错误地将其应用于之后的其他库。例如

    -Wl,--no-whole-archive
  2. 第二种方法是在 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
    
  3. 但是您可能需要完全限定g++ -o example.exe libmingw32.a a.a 的路径,否则链接器将无法找到它。

答案 1 :(得分:0)

.a文件是静态库,就链接器而言。链接器仅从定义当前未解析的符号的存档中取出对象。因此,如果没有任何引用.a文件中定义的符号的目标文件,它们将不会被拉入。示例中的链接器输出为空,因此未定义WinMain。

实际上,当您定义标准main()时,它似乎有效。我认为这是因为语言标准需要对main()的引用。还有一个gcc / ld命令行选项,用于生成对符号的引用。尝试在.a文件之前添加-u WinMain@16

答案 2 :(得分:0)

我正在使用Code :: Blocks。今天我在静态库中遇到了与WinMain相同的问题。在我的情况下,改变库的顺序不起作用。我最终通过将-lmingw32添加到 项目/构建选项/链接器设置/其他链接器选项来解决它。