给出一个简单的程序:
#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文件链接程序?
答案 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
:
使用a.a
强制在-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
的路径,否则链接器将无法找到它。
答案 1 :(得分:0)
.a文件是静态库,就链接器而言。链接器仅从定义当前未解析的符号的存档中取出对象。因此,如果没有任何引用.a文件中定义的符号的目标文件,它们将不会被拉入。示例中的链接器输出为空,因此未定义WinMain。
实际上,当您定义标准main()时,它似乎有效。我认为这是因为语言标准需要对main()的引用。还有一个gcc / ld命令行选项,用于生成对符号的引用。尝试在.a文件之前添加-u WinMain@16
。
答案 2 :(得分:0)
我正在使用Code :: Blocks。今天我在静态库中遇到了与WinMain相同的问题。在我的情况下,改变库的顺序不起作用。我最终通过将-lmingw32
添加到 项目/构建选项/链接器设置/其他链接器选项来解决它。