编译一个不依赖任何msvcrXX.dll的Windows程序

智数寻幽使
• 阅读 16113

前提

本文面向Windows任意NT平台可移植方案的讨论,也就是绿色化,最小化,无需捆绑太多运行时

如果你:

  • 不在乎运行时大小
  • 面向的是商业用户

那么可以不看。

标准C:C标准库也称为ISO C库,是用于完成诸如输入/输出处理、字符串处理、内存管理、数学计算和许多其他操作系统服务等任务的宏、类型和函数的集合。它是在C标准中(例如C11标准)中定义的。其内容分布在不同的头文件中,比如 glibc

Visual C++

Visual C++ 6以后(不包含VC6),通过Visual Studio编译的VC程序,默认都会linkmsvcrXX.dll,这个DLL就是VC运行时,如果使用了MFC,还会LinkmfcXX.dll
(XX 代表VS的版本号,比如VS 2008msvcr90.dll

VC 2015之后,更是多了一堆 api-ms-win-core api-ms-win-crt的补丁

而绝大多数系统默认不会包含这些VC运行时

比如:QQTIM用的是VC2010,发布QQ的时候,需要打包一个msvcrXX.dll到目录,或者是在打包程序中安装vcredist,这样对于发布一个小型应用来说,运行时就占用了大量包体空间。

而像DelphiGo这类语言开发出来的exe,虽然不带运行时(运行时打包在exe中了),但是Delphi生态圈早已经没落了,而GoWindows的生态圈才刚刚起步

Windows上面的程序主流只能是VC

别和我提什么.Net、Java程序,又不是大型商业软件,可以将运行时打包发布,或者是强制用户安装运行时。

解决方案

所以,这里提出如下方法避免程序连接到这些运行时,让你的程序可移植到任意Windows NT平台而无需捆绑运行时。

0x1. Visual C++ 6

为什么Visual C++ 6到现在都没死?

因为Visual C++ 6编译的程序,默认Linkmsvcrt.dll, 这个dll包含在Windows 2000和以上的Windows中,也就是说,程序可以不捆绑任何运行时,都能运行(当然,你没有用MFC或第三方dll)。

下图可以看到一个VC++ 6编译的 DLL 的依赖,都是系统自带DLL

编译一个不依赖任何msvcrXX.dll的Windows程序

msvcrt.dll这个DLL很特殊,这个DLLWindows XP和之后的系统中提升为了系统dll,只允许内核程序调用,但是VC 6的程序仍然可以调用它。

注意:msvcrt.dll并不是一个标准C的DLL,

0x2. 编译为MT

在国内的搜索得到的解决方案,大部分都是如下操作:
项目 点击右键 -> 属性 Properties -> C/C++ -> Code Generation -> Runtime Library,选择/MT 即可

编译一个不依赖任何msvcrXX.dll的Windows程序

当然这前提是在Release模式下,Debug选这个没意义,毕竟大家也不会发布Debug的程序对吧。

这样做的目的是将VC的一些C Lib打包到目标exe中,这样程序在发布的时候,就可以不用到运行时了。

  • 程序会变大
  • 如果项目还包含DLL或其他程序,那么每个文件都需要打包一份C Lib,这样每个文件都会膨胀很大。

0x03. 使用minGW的GCC编译

前提是没使用MFC

正常安装minGW

可以在mingw64\bin目录下看到如下文件

编译一个不依赖任何msvcrXX.dll的Windows程序

使用如下的语句编译

g++ main.c -Wall -O2 -o "bin\Debug\Hello.exe"
strip "bin\Debug\Hello.exe"
使用gcc编译程序,最好编写Makefile文件制定编译顺序和方法

使用MinGW gcc编译的exe,会LINKmsvcrt.dll
如果使用标准C,还需要附带libstdc++-6.dlllibgcc_s_seh-1.dll。这2个DLLmingw64\bin目录下,复制到exe目录下可以正常运行。

编译一个不依赖任何msvcrXX.dll的Windows程序

这中间方式编译出来的文件不会太大,比使用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"

这种方式编译出来的文件和MT一样,会打包相应的C Lib,所以文件会很大。

对于一些标准C的程序

  • 不建议使用cygWin来编译,它是模拟linux程序在windows上面运行,运行必须带一个cygwin.dll
  • MinGW则是将程序当做原生程序运行,只调用系统自带的msvcrt.dll,如果不使用标准C,可以使用boost来替代,那么,libstdc++-6.dll都不用附带

0x04. /NODEFAULTLIB 压轴

这方法是在VS中,创建一个不使用任何运行时的exe,所以,连标准C都不能使用。

比如创建一个控制台程序

编译一个不依赖任何msvcrXX.dll的Windows程序

然后我们在打开项目属性
Debug模式下大家不要实验了,因为需要Debug,所以会强制附带msvcrXX.dll

不依赖任何默认库

  • 关闭依赖msvcrXX.dll
  • 指定入口为main

编译一个不依赖任何msvcrXX.dll的Windows程序

这样编译,会报错,因为没有关闭安全检查

编译一个不依赖任何msvcrXX.dll的Windows程序

编译出来的程序,就什么库都没使用了,并且可以使用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

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Peter20 Peter20
4年前
mysql中like用法
like的通配符有两种%(百分号):代表零个、一个或者多个字符。\(下划线):代表一个数字或者字符。1\.name以"李"开头wherenamelike'李%'2\.name中包含"云",“云”可以在任何位置wherenamelike'%云%'3\.第二个和第三个字符是0的值wheresalarylike'\00%'4\
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
4年前
PHP创建多级树型结构
<!lang:php<?php$areaarray(array('id'1,'pid'0,'name''中国'),array('id'5,'pid'0,'name''美国'),array('id'2,'pid'1,'name''吉林'),array('id'4,'pid'2,'n
Wesley13 Wesley13
4年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Stella981 Stella981
4年前
JavaScript常用函数
1\.字符串长度截取functioncutstr(str,len){vartemp,icount0,patrn/^\x00\xff/,strre"";for(vari
Wesley13 Wesley13
4年前
MBR笔记
<bochs:100000000000e\WGUI\Simclientsize(0,0)!stretchedsize(640,480)!<bochs:2b0x7c00<bochs:3c00000003740i\BIOS\$Revision:1.166$$Date:2006/08/1117
Python进阶者 Python进阶者
2年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这