生成小型Windows二进制文件
在开发和部署本机Windows应用程序时,我通常需要先安装运行时,然后才能运行二进制文件,或者将库与二进制文件静态链接。例如,在使用Visual Studio 2008构建“Win32 Console”项目后,尝试在新的Windows 7映像上运行该程序会导致: 应用程序无法启动,因为其并行配置不正确。有关详细信息,请参阅应用程序事件日志或使用命令行sxstrace.exe工具 像这样的问题已经在StackOverflow上提出来了 如何开发不需要目标操作系统上没有的运行时的应用程序(即不需要安装可再发行的软件包或私有/共享并行程序集)?如何避免使用msvc[mpr]90.dll而只使用\Windows\system32*{dll,sys}中的Windows API生成小型Windows二进制文件,windows,winsxs,Windows,Winsxs,在开发和部署本机Windows应用程序时,我通常需要先安装运行时,然后才能运行二进制文件,或者将库与二进制文件静态链接。例如,在使用Visual Studio 2008构建“Win32 Console”项目后,尝试在新的Windows 7映像上运行该程序会导致: 应用程序无法启动,因为其并行配置不正确。有关详细信息,请参阅应用程序事件日志或使用命令行sxstrace.exe工具 像这样的问题已经在StackOverflow上提出来了 如何开发不需要目标操作系统上没有的运行时的应用程序(即不需要安
我在考虑demoscene中的代码,但这通常不可用。使用静态CRT。这不会创建对msvc*.dll的依赖关系。CRT直接链接到您的程序中。这不会创建依赖项,但会增加可执行文件的大小
有关不同CRT选项的更多信息。使用静态CRT。这不会创建对msvc*.dll的依赖关系。CRT直接链接到您的程序中。这不会创建依赖项,但会增加可执行文件的大小
有关不同CRT选项的更多信息。通过
/MT
开关静态链接CRT(如果您正在使用MFC,也可以使用MFC)
静态链接在某种程度上限制了您对DLL的使用,但对于简单的可执行文件,它就像一个魅力。(如果您正在运送DLL,您始终可以运送专用程序集。)通过
/MT
开关静态链接CRT(同样,如果您正在使用MFC)
静态链接在某种程度上限制了您对DLL的使用,但对于简单的可执行文件,它就像一个魅力。(如果您正在运送DLL,您始终可以运送专用程序集。)静态链接运行时。MS Visual C++具有选项/MT(默认为/MD)< P>静态链接运行时。MS Visual C++具有选项/MT(默认为/MD)< P>其他已对CRT静态链接进行了响应。如果同时还需要一个小的二进制文件,那么最好完全放弃CRT,并且尽可能只使用Win32 API函数。您仍然会得到一些CRT代码,最明显的是与启动(即调用
main
)和关闭(atexit
处理等)相关的代码,但否则链接器不会链接您不使用的CRT函数
通过使用/Zl
编译器开关,可以避免完全链接CRT。这意味着main
将不再工作,但是-您需要定义WinMain
(名称不重要,但签名必须匹配,并且必须是\uu stdcall
),并且必须通过链接器/entry:
开关将类似WinMain
的函数的名称指定为入口点。这将为您节省约30Kb的CRT代码(在带有空main
的.cpp上测试)
如果您选择后一种方法,您可能还必须处理编译器内部函数的问题。有些函数名义上由CRT定义(并在其标题中声明),但编译器会对其进行特殊处理,以便尽可能在调用点插入优化的汇编指令-例如memset
,strlen
,以及
中的大量函数;可以找到完整的列表。由于您没有CRT,如果您需要这些函数,或者可以避免这些函数,但由于性能的提高(例如,很难比memset
做得更好)而选择内部函数,那么您必须自己声明它们,并使用#pragma-instructive
。例如:
// 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;
}
其他人已经对静态链接CRT做出了回应。如果同时还需要一个小的二进制文件,那么最好完全放弃CRT,并且尽可能只使用Win32 API函数。您仍然会得到一些CRT代码,最明显的是与启动(即调用
main
)和关闭(atexit
处理等)相关的代码,但否则链接器不会链接您不使用的CRT函数
通过使用/Zl
编译器开关,可以避免完全链接CRT。这意味着main
将不再工作,但是-您需要定义WinMain
(名称不重要,但签名必须匹配,并且必须是\uu stdcall
),并且必须通过链接器/entry:
开关将类似WinMain
的函数的名称指定为入口点。这将为您节省约30Kb的CRT代码(在带有空main
的.cpp上测试)
如果您选择后一种方法,您可能还必须处理编译器内部函数的问题。有些函数名义上由CRT定义(并在其标题中声明),但编译器会对其进行特殊处理,以便尽可能在调用点插入优化的汇编指令-例如memset
,strlen
,以及
中的大量函数;可以找到完整的列表。由于您没有CRT,如果您需要这些函数,或者可以避免这些函数,但由于性能的提高(例如,很难比memset
做得更好)而选择内部函数,那么您必须自己声明它们,并使用#pragma-instructive
。例如:
// 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;
}
我认为一种方法是不使用VisualStudio,而是依赖命令行SDK工具。(你也可以考虑如何配置VS来做你想做的事情,但这似乎很难。)例如:
我认为这样做的一个方法就是不使用V
cl /c app.cpp
link app.obj ws2_32.lib