本文主要是对MinGW和Cygwin相关的一些名词的研究和推测,以求澄清一些似乎而非的概念,并记录当前已经弄清楚的一些问题,以及还需要进一步调研的一些细节。所有调研都基于Windows平台。
关于MinGW和Cygwin的关系
网上大部分博文复制粘贴的文章都是讨论MinGW和Cygwin的区别和优劣。而我主要是分析两者的联系,以及一些需要同时用到MinGW和Cygwin的交叉编译场景。
从MinGW的维基百科上看,Cygwin是提供一个模拟的POSIX层(cygwin1.dll)。我推测Cygwin也提供了一系列基于Cygwin的编译工具,在将需要移植的Linux代码在Cygwin上重新编译后,可以获得可以在Windows上直接运行的exe,而这个exe调用的还是POSIX风格的API,只不过这些API由cygwin1.dll提供模拟实现。而MinGW也提供了一系列编译工具,但MinGW-GCC是在编译时将代码中的POSIX API调用直接修改为对应的Windows API调用,从而不需要一个额外的dll转换层。需要额外提到的是,gcc的这种在编译时直接修改调用的API的行为不仅不少见,而且非常常见,在64位Linux上编译C++程序时,例如调用open这个函数,实际上在gcc编译后,调用的是libc中的open64函数,这个可以通过objdump导出外部依赖符号表来确认。另外就是,MinGW并不提供某些难以用Windows API实现的POSIX API,例如fork(),mmap()和ioctl()。
MinGW和MinGW-w64
MinGW(mingw32)据说更新太慢代码太老,因此另一帮人就新搞了一个MinGW-w64,据说老的MinGW不支持编译64位程序。不知道是不是这就意味着可以完全放弃掉MinGW而直接采用MinGW-x64?
在安装MinGW时需要选择线程模型:posix或win32。从mingw-w64 threads: posix vs win32看来,win32是在C++11之前MinGW-GCC搞的一套基于win32 threads模型的多线程库,而posix则是基于libwinpthreads,支持C++11的一些新的头文件。有另外一个单独的GitHub项目mingw-std-threads可以让win32模型也支持这些C++11头文件。
MinGW-w64可以安装在Windows上,可以安装在Linux上,甚至可以安装在Cygwin里(而CygWin看起来只能安装在Windows中)。MinGW(mingw32)好像有另外一个相关项目MinGW cross compiling environment提供Linux安装,但感觉项目不是很活跃。并且从这篇更新日志来看,似乎作者已经放弃更新并转向MinGW-w64。
MSYS
根据MinGW官网对于MSYS的描述,MSYS是对MinGW的补充,提供了bash,make, gawk和grep等GNU工具来辅助编译。从网上可以找到的一些MinGW编译入门文章来看,完全可以在Windows cmd环境中调用MinGW的gcc命令行去编译基于MinGW的Windows程序,并不是一定需要在bash环境中进行,但是像bash脚本这种应该还是需要bash环境的。另外据说MSYS是从Cygwin派生出来的分支,本来我推测像MSYS中的gcc应该是运行在cygwin1.dll或者类似名字的dll模拟层上。但是检查了gcc的dll依赖关系:
发现MinGW上的gcc最终似乎是直接依赖于Windows的dlls,并没有类似cygwin1.dll的东西。这种有点奇怪了,难道这个gcc是通过Cygwin上的MinGW-GCC用自举(bootstrapping)的方式创建出来的?找到关于MinGW-x64有关自举编译的一篇文章Creating a native Win64 compiler,我怀疑MinGW是不是也是用的类似的自举编译gcc。
但是再看bash的话,bash.exe却还是依赖于msys1.0.dll以及其它一些msys开头的dlls。猜测这些dlls应该就是类似于cygwin1.dll的模拟层。MinGW和MSYS是通过同一个安装程序来安装,推测由于gcc.exe属于MinGW,而bash.exe属于MSYS,而只有MSYS的工具才需要依赖msys相关的dlls。检查安装路径后果然发现,gcc.exe是在C:\MinGW\bin
下面,而bash.exe是在C:\MinGW\msys\1.0\bin
下面,印证了我的想法。
此外结合MinGW的中文维基百科和我自己的MinGW-w64安装经历,选择i686工具链时可以从DWARF和SJLJ这两种异常实现机制中二选一,而选择x86_64时需要从SEH和SJLJ中二选一。
MSYS2
回过头来再看看MSYS2。MSYS2似乎是配套MinGW-w64出现的,提供三种配置的模式:msys2,mingw64(使用mingw-w64 x86_64 toolchain工具链)和mingw32(使用mingw-w64 i686 toolchain工具链)。个人推测msys2模式编译出来的程序需要依赖msys2.0.dll,就像Cygwin下编译出来的程序一样。据说MSYS2相对于Cygwin的最大区别是移植了包管理工具Pacman。据说三种模式的主要区别是在$PATH中的搜索优先顺序不同,msys2只使用/usr/local/bin
和/usr/bin
下的工具,mingw64优先使用/mingw64/bin
下的工具,mingw32优先使用/mingw32/bin
下的工具。
类似于MinGW和MSYS,安装MSYS2的时候也会自动安装MinGW-w64。而且看起来在x64平台上是mingw64和mingw32会同时被安装。
我首先单独安装了MinGW-w64,看起来其中的gcc等工具也是直接依赖于Windows的dlls,并没有一个中间层dll。并且在安装的时候需要选择是用x86_64工具链还是i686工具链,以及异常的处理方式。这么看来安装MSYS2的话就可以同时拥有两种工具链了。安装MSYS2时并没有要求选择异常处理机制和所使用的线程库,根据What’s the difference between Mingw-builds and Mingw packages in Msys2这个帖子中的讨论,看起来
MSYS2 only provides posix thread model, dwarf for i686, seh for x86_64
使用Pacman直接安装的gcc依赖于msys2系列的dlls。我估计这就类似于在Cygwin上直接安装gcc,会依赖于cygwin1.dll。如果要安装只依赖于Windows native dlls的gcc,应该安装mingw版本的gcc。
安装mingw-w64-i686-toolchain和mingw-w64-x86_64-toolchain则分别会在mingw32\bin
和mingw64\bin
目录下产生gcc.exe,并且只依赖于Windows dlls和libwinpthread-1.dll,看来这个就是MinGW-w64版本的gcc,可以生成不依赖于任何dll的Windows程序。