生成小的 Windows 二进制文件

Yan*_*ang 1 windows winsxs

在开发和部署本机 Windows 应用程序时,我经常需要先安装运行时才能运行我的二进制文件,或者将库与我的二进制文件静态链接。例如,在使用 Visual Studio 2008 构建“Win32 控制台”项目后,尝试在新的 Windows 7 映像上运行该程序会导致:

应用程序无法启动,因为其并行配置不正确。请查看应用程序事件日志或使用命令行 sxstrace.exe 工具获取更多详细信息。

在 StackOverflow上的其他帖子中已经提出了这样的问题。

如何开发不需要目标操作系统上尚不存在的运行时的应用程序(即不需要安装可再发行包或私有/共享并行程序集)?如何避免使用 msvc[mpr]90.dll 而只使用 \windows\system32*.{dll,sys} 中的 Windows API?

我正在考虑来自演示场景的代码行,但这通常不可用。

Pav*_*aev 6

其他人已经就静态链接 CRT 做出了回应。如果您同时还想要一个小的二进制文件,那么您最好的选择是完全放弃 CRT,并尽可能只使用 Win32 API 函数。您仍然会得到一些 CRT 代码,最显着的是与启动(即调用main)和关闭(atexit处理等)相关的代码,但否则链接器将不会链接您不使用的 CRT 函数。

您可以通过使用/Zl编译器开关来避免完全链接 CRT 。但是,这意味着这main将不再起作用-您需要定义WinMain(名称无关紧要,但签名必须匹配,并且必须是__stdcall),并且您必须将WinMain类似函数的名称指定为条目通过链接器/entry:开关指向。这将为您节省大约 30Kb 的 CRT 代码(在带有空的 .cpp 上测试main)。

如果你走后一条路线,你可能还需要处理编译器内在函数的问题。但是也有一些名义上由CRT所定义(且在其标头中声明),而是它们由编译器经过特殊处理的某些功能,以便它插入在尽可能的调用点优化的汇编指令-的实例是memsetstrlen和一个中的大量功能<math.h>;可以在此处找到完整列表。由于您没有 CRT,如果您需要这些函数,或者可以避免它但由于性能提高而更喜欢内在函数(memset例如,很难做得更好),那么您必须自己声明它们,并使用#pragma intrinsic. 例如:

// Contains macros and typedef only, so safe to include without CRT.
// We need it here for size_t.
#include <stddef.h> 

extern "C"
{
    int abs(int);
    void* memset(void*, int, size_t); 
}

#pragma intrinsic(abs, memset)

int __stdcall main(void*, void*, char*, int)
{
    char tmp[10];
    memset(tmp, abs(-123), 10);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

以上可以编译为:

cl /c /Zl foo.cpp
link /entry:main foo.obj
Run Code Online (Sandbox Code Playgroud)