C++ 为什么是;“WinMain”;链接为*.a静态库时未解决?

C++ 为什么是;“WinMain”;链接为*.a静态库时未解决?,c++,gcc,mingw,C++,Gcc,Mingw,给出一个简单的程序: #include <windows.h> int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, LPSTR lpCmdLine, int nCmdShow) { return 0; } 关于为什么会发生这种情况,有什么见解吗?如何仅使用.a文件链接程序?.a文件是静态库,就链接器而言。链接器仅从定义当前未解析符号的存档中取出对象。因此,如果没有任何引用.a

给出一个简单的程序:

#include <windows.h>

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, 
                   LPSTR lpCmdLine, int nCmdShow)
{
  return 0;
}

关于为什么会发生这种情况,有什么见解吗?如何仅使用.a文件链接程序?

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


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

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,--之后没有完整的存档
    ,因此它不会错误地将此应用于后面的其他库。例如

    g++ -o example.exe -Wl,--whole-archive a.a -Wl,--no-whole-archive
    
  • 第二种方法是在
    a.a
    之前手动包含
    mingw32.a
    ,以便
    WinMain
    在处理
    a.a
    时成为挂起的未解析符号:

    g++ -o example.exe -lmingw32 a.a
    


  • 但是您可能需要完全限定libmingw32.a的路径,否则链接器将找不到它。

    我使用的是code::Blocks。今天,我在静态库中遇到了与WinMain相同的问题。在我的例子中,更改库的顺序不起作用。我最终解决了这个问题,将
    -lmingw32
    添加到项目/构建选项/链接器设置/其他链接器选项中。

    因此,使用WinMain.a编译一个可执行文件是不可能的?我已经以一种可能的方式进行了编辑,尽管我不知道这其中的全部意义。所有的.a归档文件通常都是库,将实际的程序放在这些库中是不寻常的,也是令人困惑的,包括主函数。
    g++-uWinMain@16a.a
    不起作用。我在项目中使用.a文件来模块化代码。比如说,我有子目录“core”、“graphics”、“input”,每个目录都是独立构建的,都有自己的目标文件存档,那么最终的项目应该能够将存档文件链接在一起。@user1641398可以使用。a对于模块,不要将入口点放在这些目录中。将
    main
    (或
    WinMain
    ,在您的情况下)函数从静态库中取出,只包含一个对象文件。
    g++ -o example.exe -lmingw32 a.a
    
    g++ -o example.exe libmingw32.a a.a