前提
本文面向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-core api-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
可以在mingw64bin 目录下看到如下文件
使用如下的语句编译
g++ main.c -Wall -O2 -o "binDebugHello.exe"
strip "binDebugHello.exe"
使用gcc 编译程序,最好编写Makefile 文件制定编译顺序和方法
使用MinGW gcc 编译的exe ,会LINK 到msvcrt.dll 如果使用标准C ,还需要附带libstdc++-6.dll 、libgcc_s_seh-1.dll 。这2个DLL 在mingw64bin 目录下,复制到exe 目录下可以正常运行。
这中间方式编译出来的文件不会太大,比使用MT要小。
如果希望编译出不带libstdc++-6.dll 的文件,
可以使用如下方法:
// 主要是下面 -c 这个参数,先将cpp输出为中间文件
g++.exe -Wall -c -g main.cpp -o objDebugmain.o
// 然后静态连接 libstdc++
g++.exe -static -static-libgcc -static-libstdc++ -o "binDebugHello.exe" objDebugmain.o
strip "binDebugHello.exe"
这种方式编译出来的文件和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
下载地址如下:
https://www-user.tu-chemnitz.de/~heha/viewzip.cgi/hs/msvcrt-light.zip
编译时,连接到msvcrt-light-x64.lib ,待续 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|