编译一个不依赖任何msvcrXX.dll的Windows程序
前提
本文面向Windows任意NT平台可移植方案的讨论,
如果你:
- 不在乎运行时大小
- 面向的是商业用户
那么可以不看。
Visual C++
从Visual C++ 6以后(不包含VC6),通过Visual Studio编译的VC程序,默认都会link到msvcrXX.dll,这个DLL就是VC运行时,如果使用了MFC,还会Link到mfcXX.dll
(XX 代表VS的版本号,比如VS 2008是msvcr90.dll)
在
VC 2015之后,更是多了一堆api-ms-win-coreapi-ms-win-crt的补丁
而绝大多数系统默认不会包含这些VC运行时,
比如:QQ、TIM用的是VC2010,发布QQ的时候,需要打包一个msvcrXX.dll到目录,或者是在打包程序中安装vcredist,这样对于发布一个小型应用来说,运行时就占用了大量包体空间。
而像Delphi、Go这类语言开发出来的exe,虽然不带运行时(运行时打包在exe中了),但是Delphi生态圈早已经没落了,而Go的Windows的生态圈才刚刚起步
Windows上面的程序主流只能是VC。
别和我提什么.Net、Java程序,又不是大型商业软件,可以将运行时打包发布,或者是强制用户安装运行时。
解决方案
所以,这里提出如下方法避免程序连接到这些运行时,让你的程序可移植到任意Windows NT平台而无需捆绑运行时。
0x1. Visual C++ 6
为什么Visual C++ 6到现在都没死?
因为Visual C++ 6编译的程序,默认Link到msvcrt.dll, 这个dll包含在Windows 2000和以上的Windows中,也就是说,程序可以不捆绑任何运行时,都能运行(当然,新视觉影院你没有用MFC或第三方dll)。
下图可以看到一个VC++ 6编译的 DLL 的依赖,都是系统自带DLL
而msvcrt.dll这个DLL很特殊,在个DLL在Windows XP和之后的系统中提升为了系统dll,只允许内核程序调用,但是VC 6的程序仍然可以调用它。
注意:
msvcrt.dll并不是一个标准C的DLL,
0x2. 编译为MT
在国内的搜索得到的解决方案,大部分都是如下操作:
项目 点击右键 -> 属性 Properties -> C/C++ -> Code Generation -> Runtime Library,选择/MT 即可
当然这前提是在Release模式下,Debug选这个没意义,毕竟大家也不会发布Debug的程序对吧。
这样做的目的是将VC的一些C Lib打包到目标exe中,这样程序在发布的时候,就可以不用到运行时了。
- 程序会变大
- 如果项目还包含
DLL或其他程序,那么每个文件都需要打包一份C Lib,这样每个文件都会膨胀很大。
0x03. 使用minGW的GCC编译
前提是没使用MFC。
正常安装minGW
可以在mingw64\bin目录下看到如下文件
使用如下的语句编译
g++ main.c -Wall -O2 -o "bin\Debug\Hello.exe"
strip "bin\Debug\Hello.exe"
使用
gcc编译程序,最好编写Makefile文件制定编译顺序和方法
使用MinGW gcc编译的exe,会LINK到msvcrt.dll
如果使用标准C,还需要附带libstdc++-6.dll、libgcc_s_seh-1.dll。这2个DLL在mingw64\bin目录下,复制到exe目录下可以正常运行。
这中间方式编译出来的文件不会太大,比使用MT要小。
如果希望编译出不带libstdc++-6.dll的文件,
可以使用如下方法:
// 主要是下面 -c 这个参数,先将cpp输出为中间文件
g++.exe -Wall -c -g main.cpp -o obj\Debug\main.o
// 然后静态连接 libstdc++
g++.exe -static -static-libgcc -static-libstdc++ -o "bin\Debug\Hello.exe" obj\Debug\main.o
strip "bin\Debug\Hello.exe"www.xsjdy.org
这种方式编译出来的文件和MT一样,会打包相应的C Lib,所以文件会很大。
对于一些标准C的程序
- 不建议使用
cygWin来编译,它是模拟linux程序在windows上面运行,运行必须带一个cygwin.dll MinGW则是将程序当做原生程序运行,只调用系统自带的msvcrt.dll,如果不使用标准C,可以使用boost,那么,libstdc++-6.dll都不用附带
0x04. /NODEFAULTLIB 压轴
这方法是在VS中,创建一个不使用任何运行时的exe,所以,连标准C都不能使用。
比如创建一个控制台程序
然后我们在打开项目属性Debug模式下大家不要实验了,因为需要Debug,所以会强制附带msvcrXX.dll
不依赖任何默认库
- 关闭依赖
msvcrXX.dll - 指定入口为main
这样编译,会报错,因为没有关闭安全检查
编译出来的程序,就什么库都没使用了,并且可以使用C++14等高级语法,但是需要自己去解决C库的问题,比如boost。
并且,这个exe的安全检查和exception也被关闭了,你需要自己注意内存安全。
0x05. 变相调用msvcrt.dll
这是某德国人写的一个曲线解决方案,前提是没有使用标准C,因为上面说过,只要使用标准C,肯定会调用VC的相应DLL,那么需要自己去解决标准C还是boost
posted on 2017-10-31 21:27 xinshijue6080 阅读(837) 评论(0) 收藏 举报
浙公网安备 33010602011771号