1

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

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

StackOverflow上的其他帖子中已经提出了类似的问题。

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

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

4

5 回答 5

6

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

/Zl您可以通过使用编译器开关完全避免链接 CRT 。但是,这意味着main它将不再起作用-您需要定义WinMain(名称无关紧要,但签名必须匹配,并且必须是__stdcall),并且您必须将WinMain-like 函数的名称指定为条目通过链接器/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;
}

上面可以编译:

cl /c /Zl foo.cpp
link /entry:main foo.obj
于 2009-09-30T17:21:08.547 回答
3

通过交换机静态链接 CRT /MT(如果您正在使用,也可以使用 MFC)。

静态链接在一定程度上限制了您可以使用 DLL 执行的操作,但对于简单的可执行文件,它就像一个魅力。(而且,如果您要发送 DLL,则始终可以发送私有程序集。)

于 2009-09-29T22:01:51.317 回答
2

使用静态 CRT。这不会创建对 msvc*.dll 的依赖。CRT 直接链接到您的程序中。这不会创建依赖项,但会增加可执行文件的大小。

有关不同 CRT 选项的更多信息,请点击此处

于 2009-09-29T22:01:46.327 回答
0

静态链接运行时。MS Visual C++ 有 /MT 选项(默认为 /MD)

于 2009-09-29T22:02:45.917 回答
0

I think one way to do this is to just not use Visual Studio and instead rely on the command line SDK tools. (You can alternatively figure out how to config VS to do what you want, but that seems harder.) E.g.:

cl /c app.cpp
link app.obj ws2_32.lib
于 2009-09-30T17:41:27.097 回答