如何使用CMake在Windows上将应用程序入口点设置为main()C++?

How to Set C++ Application Entry Point to main() on Windows using CMake?

本文关键字:main 设置 C++ 入口 CMake 何使用 Windows 应用程序      更新时间:2023-10-16

我最近开始使用CMake,并试图构建一个GUI应用程序,该应用程序在Windows上没有控制台窗口。所以在我的CMakeLists.txt文件中,我做了这个:

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_executable(${EXECUTABLE_NAME} main.cpp)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
add_executable(${EXECUTABLE_NAME} WIN32 main.cpp) #WIN32 So the console window does not open on Windows
endif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" OR "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")

这样,解决方案就起作用了,并且控制台窗口无法在Windows上打开。但是,这是有代价的。当我尝试构建解决方案时,我意识到我必须将函数的签名更改为WinMain,因此我将主代码更改为以下内容:

#ifdef _WIN32
#include <Windows.h>
int WINAPI WinMain(HINSTANCE, HINSTANCE, PSTR, int) //Windows signature since creating WIN32 application without console
#else
int main()
#endif
{
// ... GUI code
}

不幸的是,我绝对讨厌这一点,因为它破坏了使用 CMake 的全部意义。我不想更改基于不同平台的代码中的任何内容。这就引出了我的问题。在制作 GUI 应用程序时,如何将C++应用程序入口点设置为在 Windows 上main(),而无需在 Visual Studio 中手动设置它?我可以使用跨平台方法直接在 CMake 中执行此操作吗?还是我必须使用#if/#else/#endif解决方案?对上述解决方案的唯一改进是使用执行预处理器条件的宏MAIN_FUNCTION。我也想避免这种情况。

另一方面,有没有另一种方法可以在 Windows 上的 GUI 应用程序中摆脱控制台窗口,我不知道在不使用 WIN32 选项的情况下使用 CMake?

解决方案是在add_executable之前添加set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")

它隐藏了控制台,同时仍然允许您将通常的int main()作为入口点。

你在这里混淆了两件事,但它们是密切相关的。

显示的控制台是具有 Win32 标头IMAGE_OPTIONAL_HEADER::Subsystem值为WINDOWS_CUI而不是WINDOWS_GUI的应用程序的结果。这是 Win32 的事情,它适用于所有可执行文件,无论它们是用哪种语言编写的。

入口点签名是特定于编译器的选项。它是语言运行时调用的入口函数,而不是操作系统。OS 调用语言运行时的入口函数,该函数首先初始化该运行时,然后将控制权移交给入口点。

现在,VC++ 编译器使用 CRT 作为运行时。而且该 CRT 运行时确实使用两个不同的签名作为入口点。显然,std::cin的实现必须与WINDOWS_CUI一起使用,这就是命令行用户界面的重点。但同样的 CRT 也适用于WINDOWS_GUI.

这就是事情变得复杂的地方。实际上,您可以将已编译应用程序的Subsystem从 CUI 更改为 GUI。CRT不会介意,它与两个子系统兼容。但是,由于它是对已编译的应用程序完成的,因此从应用程序的一部分(CRT 启动(到另一部分(入口点(的调用不会受到影响。这是 Win32 更改,而不是C++更改。

若要返回到 CMake:此子系统更改可以在 CMake 之后完成,也可以作为自定义的生成后步骤完成。