C/C++ 编译器选项 subsystem 和 entry
前段时间需要写一个打开后不显示窗口的程序,于是在网上大量搜索资料后,找到了一个可用的预处理代码
#pragma comment(linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
意思就是给Linker传两个参数 /subsystem:windows 和 /entry:mainCRTStartup
在后面的使用中 我还发现上述命令只可以在MSVC中使用,在Mingw的gcc编译器中无法使用
本着知其然 知其所以然的态度 于是去找了MSVC编译器的文档
https://docs.microsoft.com/zh-cn/cpp/build/reference/subsystem-specify-subsystem?view=msvc-170
/SUBSYSTEM (指定子系统)
指定可执行文件的目标 Windows 子系统。
语法
/SUBSYSTEM: { BOOT_APPLICATION | CONSOLE | EFI_APPLICATION |
EFI_BOOT_SERVICE_DRIVER | EFI_ROM | EFI_RUNTIME_DRIVER | NATIVE |
POSIX | WINDOWS }
[ ,major [ .minor ]]
参数
BOOT_APPLICATION
在 Windows 启动环境中运行的应用程序。 有关启动应用程序的详细信息,请参阅 关于 BCD。
CONSOLE
Win32 字符模式应用程序。 操作系统提供为控制台应用程序提供控制台。 如果 main 为本机代码定义了或, int main(array<String ^> ^) 则为托管代码定义了或 wmain ,或者使用 /clr:safe 完全生成应用程序,控制台是默认值。
EFI_APPLICATION
EFI_BOOT_SERVICE_DRIVER
EFI_ROM
EFI_RUNTIME_DRIVER
可扩展固件接口子系统。 有关详细信息,请参阅 UEFI 规范。 有关示例,请参阅 Intel UEFI 驱动程序和应用程序工具资源。 最低版本和默认版本为1.0。
NATIVE
Windows NT 的内核模式驱动程序。 此选项通常保留给 Windows 系统组件。 如果 /DRIVER:WDM 指定, NATIVE 则为默认值。
POSIX
在 Windows NT 中与 POSIX 子系统一起运行的应用程序。
WINDOWS
应用程序不需要控制台,这可能是因为它创建自己的 windows 以便与用户交互。 如果 WinMain 为本机代码定义了或 wWinMain , WinMain(HINSTANCE *, HINSTANCE *, char *, int)wWinMain(HINSTANCE *, HINSTANCE *, wchar_t *, int) 或者为托管代码定义了或, WINDOWS 则为默认值。
major 和 minor
(可选) 指定子系统所需的最低版本。 参数是介于0到65535之间的十进制数字。 版本号没有上限。
https://docs.microsoft.com/zh-cn/cpp/build/reference/entry-entry-point-symbol?view=msvc-170
/ENTRY(入口点符号)
复制
/ENTRY:function
参数
函数
一个函数,指定用户定义的起始地址.exe或 DLL。
备注
/ENTRY 选项指定入口点函数作为文件或 DLL .exe起始地址。
必须定义 函数,以使用调用 __stdcall 约定。 参数和返回值取决于程序是控制台应用程序、Windows 应用程序还是 DLL。 建议让链接器设置入口点,以便正确初始化 C 运行时库,并执行静态对象的 C++ 构造函数。
默认情况下,起始地址是 C 运行时库中的函数名称。 链接器根据程序的属性选择它,如下表所示。
函数名称 默认为
mainCRTStartup (或 wmainCRTStartup) 使用 /SUBSYSTEM:CONSOLE 的应用程序;调用 main (或 wmain)
WinMainCRTStartup (或 wWinMainCRTStartup) 使用 /SUBSYSTEM:WINDOWS 的应用程序;调用 WinMain (或 wWinMain) ,必须定义为使用 __stdcall
_DllMainCRTStartup A DLL;如果存在 DllMain ,则调用 ,必须定义该调用以使用 __stdcall
如果 未指定 /DLL 或 /SUBSYSTEM 选项,则链接器将根据是否定义了 main 或 WinMain 来选择子系统和入口点。
main函数 、 WinMain和 DllMain 是用户定义的入口点的三种形式。
创建托管映像时,指定给 /ENTRY 的函数必须具有 (LPVOID var1、DWORD var2、LPVOID var3) 。
若要了解如何定义自己的 DllMain 入口点,请参阅 DLL 和Visual C++ 运行时库行为 。
通过上面两个在 MSVC 链接器 文档中引用的内容(应该是机翻,如果想了解详细内容可以点一下上面的链接) 大概可以了解到,我们使用VS创建控制台程序(入口函数为main)时,系统就会默认将Console作为subsystem,于是就会出现我们常见的控制台
CONSOLE
Win32 字符模式应用程序。 操作系统提供为控制台应用程序提供控制台。 如果 main 为本机代码定义了或, int main(array<String ^> ^) 则为托管代码定义了或 wmain ,或者使用 /clr:safe 完全生成应用程序,控制台是默认值。
而上述的预处理语句则强制制定了入口函数(main)和子系统(windows),就达到了不需要控制台的目的
WINDOWS
应用程序不需要控制台,这可能是因为它创建自己的 windows 以便与用户交互。 如果 WinMain 为本机代码定义了或 wWinMain , WinMain(HINSTANCE *, HINSTANCE *, char *, int)wWinMain(HINSTANCE *, HINSTANCE *, wchar_t *, int) 或者为托管代码定义了或, WINDOWS 则为默认值。
而在MSVC上 如果只是用WinMain作为入口函数 默认也会将windows子系统作为默认
而在mingw里 则有另一种形式添加这个参数
https://gcc.gnu.org/legacy-ml/gcc-help/2004-01/msg00223.html
-Wl,--subsystem,windows -mwindows
What exactly do these gcc options do? Are they preprocessor, compiler, or
linker options? Sometimes I only need -windows; sometimes I need both. How
do I know when I will need both or just -mwindows?
I know they are needed when creating MS Windows apps, but I'm not clear on
what they are doing. Up to now, I've included these options rather
mindlessly in my MS Windows apps, but I'd like to know more about them.
The gcc documentation lists several "Hardware Models and Configurations" -m
options, but -mwindows is not listed.
The gcc documentation also states -Wl,option will "Pass option as an option
to the linker. If option contains commas, it is split into multiple options
at the commas," but I can't find any information on what the option
"--subsystem,windows" does.
Thanks for the information.
Glenn Carlson
-Wl,--subsystem,windows
同样也是指定子系统为windows
但和MSVC不同的是 gcc 无论使用winmain作为入口函数 还是使用main 默认都只会指向控制台作为子系统
浙公网安备 33010602011771号