0%

最近需要在Windows上搭建C/C++的开发环境,首先要安装的就是编译器。微软提供的C/C++编译器是MSVC,不过MSVC和Visual Studio捆绑,过于庞大,所以我们还是选择更轻量级的Mingw-w64。Mingw-w64实际上是Windows版本的GCC,为了能够将GCC移植到Windows上,Mingw-w64通过一组头文件把部分Posix系统调用翻译为Windows API,并且使用Windows平台的CRT来替代Glibc。Mingw-w64可以直接下载安装,但是这里我们选择通过编译源代码来创建Mingw-w64,好处在于可以很方便地控制GCC版本。为了提升工作效率,我们在Linux环境下,通过交叉编译的方式产生Windows本地的Mingw-w64编译器。编译32位工具链和64位工具链的命令稍有不同,在文中有相应说明。

准备工作

搭建开发环境

开发环境可以在任意主流Linux发行版上搭建。以Debian Buster为例,我们通过apt命令安装基本开发环境

sudo apt install g++ autoconf automake make patch autopoint bison flex gawk texinfo libtool

此外,还需要安装交叉编译的Mingw-w64编译器,请按照另一篇教程在Linux系统上创建Mingw-w64交叉编译器提供的步骤安装。

设置环境变量

为了方便,设置环境变量

export TARGET=x86_64-w64-mingw32
export CROSS_BUILDDIR=$HOME/mingw64-cross
export BUILDDIR=$HOME/mingw64
export GCC_VERSION=11.2.0
export MINGW_VERSION=9.0.0
export BINUTILS_VERSION=2.37
export MPFR_VERSION=4.1.0
export MPC_VERSION=1.2.1
export GMP_VERSION=6.2.1
export ISL_VERSION=0.24

其中

  • TARGET表示目标平台
  • CROSS_BUILDDIR表示交叉编译工具链的安装路径
  • BUILDDIR为安装路径
  • GCC_VERSION表示GCC版本号
  • MINGW_VERSION表示Mingw-w64版本号
  • BINUTILS_VERSION表示Binutils版本号
  • MPFR_VERSION表示MPFR版本号
  • MPC_VERSION表示MPC版本号
  • GMP_VERSION表示GMP版本号
  • ISL_VERSION表示isl版本号

如果要编译32位的工具链,应该把TARGETCROSS_BUILDDIRBUILDDIR设置为

export TARGET=i686-w64-mingw32
export BUILDDIR=$HOME/mingw32
export CROSS_BUILDDIR=$HOME/mingw32-cross

下载源代码

使用wget把源代码下载到安装路径下的tmp目录

mkdir $BUILDDIR/tmp -p
cd $BUILDDIR/tmp
wget http://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/gmp/gmp-$GMP_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/mpfr/mpfr-$MPFR_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/mpc/mpc-$MPC_VERSION.tar.gz
wget https://gcc.gnu.org/pub/gcc/infrastructure/isl-$ISL_VERSION.tar.bz2
wget https://jaist.dl.sourceforge.net/project/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v$MINGW_VERSION.tar.bz2

编译Binutils

cd $BUILDDIR/tmp
tar -xf binutils-$BINUTILS_VERSION.tar.xz

编译Binutils 2.37时,需要打补丁

wget https://raw.githubusercontent.com/StephanTLavavej/mingw-distro/main/binutils-fix-uint.patch
patch -p0 < binutils-fix-uint.patch

然后就可以编译安装

cd binutils-$BINUTILS_VERSION
./configure --prefix=$BUILDDIR --host=$TARGET --target=$TARGET --with-sysroot=$BUILDDIR --disable-multilib
make -j$(nproc) && make install

安装Mingw-w64头文件

可以直接把交叉编译器安装目录下的头文件复制过来

cp $CROSS_BUILDDIR/$TARGET/include $BUILDDIR/$TARGET/ -r

编译GCC

cd $BUILDDIR/tmp
tar -xf gcc-$GCC_VERSION.tar.xz
cd gcc-$GCC_VERSION
tar -xf ../mpfr-$MPFR_VERSION.tar.xz
mv -v mpfr-$MPFR_VERSION mpfr
tar -xf ../gmp-$GMP_VERSION.tar.xz
mv -v gmp-$GMP_VERSION gmp
tar -xf ../mpc-$MPC_VERSION.tar.gz
mv -v mpc-$MPC_VERSION mpc
tar -xf ../isl-$ISL_VERSION.tar.bz2
mv -v isl-$ISL_VERSION isl

进入新建的build目录,配置编译选项

mkdir build
cd build
../configure --prefix=$BUILDDIR --host=$TARGET --target=$TARGET --with-sysroot=$BUILDDIR --disable-multilib   --disable-shared --enable-languages=c,c++ --enable-threads=posix --disable-win32-registry --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libgomp --enable-libssp --enable-lto 

其中configure选项--enable-languages=c,c++定义启用的编程语言,--disable-shared的作用是可以让GCC编译出的程序不需要libgcc.dll等动态库就能运行,--enable-threads=posix表示线程模型为posix。当目标平台为Windows时,默认的线程模型为win32,这里为了完整支持C++ std::thread,需要将线程模型手动设置为posix。

因为编译器会在路径$BUILDDIR/mingw下搜索Mingw-w64的头文件,所以需要创建一个符号链接

ln -s $TARGET  $BUILDDIR/mingw

正式编译安装

make -j$(nproc) && make install

安装Mingw-w64的CRT和winpthreads

直接把交叉编译器安装目录下的库文件复制过来

cp $CROSS_BUILDDIR/$TARGET/lib/* $BUILDDIR/$TARGET/lib

打包发布

最后做一些工作来打包发布我们编译的Mingw-w64编译器。首先删除临时文件

cd $BUILDDIR/  
rm -rf $BUILDDIR/tmp/
rm $BUILDDIR/mingw

$TARGET-strip命令来缩减体积可执行文件和库文件的体积

cd $BUILDDIR/
find -name "*.exe" -type f -exec $TARGET-strip -s {} ";" >& /dev/null
find -name "*.a" -type f -exec $TARGET-strip -d {} ";" >& /dev/null
find -name "*.o" -type f -exec $TARGET-strip -d {} ";" >& /dev/null

最后用7-Zip进行压缩打包。安装7-Zip的命令为

sudo apt install p7zip-full

打包命令为

cd $BUILDDIR/..
7z a -mx9 mingw-w64-gcc-posix_${GCC_VERSION}_x64-msvcrt-${MINGW_VERSION}.7z mingw64

本文介绍在Linux系统上通过源码编译安装Mingw-w64交叉编译工具链的步骤。Mingw-w64主要包括Binutils工具集、GCC编译器、CRT以及相应的头文件,可以在Linux环境下通过交叉编译生成Windows平台的可执行文件,其CRT的目标平台也是Windows。在Linux系统上安装Mingw-w64交叉编译工具链之后,不需要有Windows环境,就可以将GNU/Linux系统下的很多软件移植到Windows系统上。编译32位工具链和64位工具链的命令稍有不同,在文中有相应说明。

准备工作

搭建开发环境

开发环境可以在任意主流Linux发行版上搭建。以Debian Buster为例,我们通过apt命令安装基本开发环境

sudo apt install g++ autoconf automake make patch autopoint bison flex gawk texinfo libtool

设置环境变量

为了方便,设置环境变量

export TARGET=x86_64-w64-mingw32
export BUILDDIR=$HOME/mingw64-cross
export GCC_VERSION=11.2.0
export MINGW_VERSION=9.0.0
export BINUTILS_VERSION=2.37
export MPFR_VERSION=4.1.0
export MPC_VERSION=1.2.1
export GMP_VERSION=6.2.1
export ISL_VERSION=0.24

其中

  • TARGET表示目标平台
  • BUILDDIR为安装路径
  • GCC_VERSION表示GCC版本号
  • MINGW_VERSION表示Mingw-w64版本号
  • BINUTILS_VERSION表示Binutils版本号
  • MPFR_VERSION表示MPFR版本号
  • MPC_VERSION表示MPC版本号
  • GMP_VERSION表示GMP版本号
  • ISL_VERSION表示isl版本号

如果要编译32位的工具链,应该把TARGETBUILDDIR设置为

export TARGET=i686-w64-mingw32
export BUILDDIR=$HOME/mingw32-cross

下载源代码

使用wget把源代码下载到安装路径下的tmp目录

mkdir $BUILDDIR/tmp -p
cd $BUILDDIR/tmp
wget http://ftp.gnu.org/gnu/gcc/gcc-$GCC_VERSION/gcc-$GCC_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/binutils/binutils-$BINUTILS_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/gmp/gmp-$GMP_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/mpfr/mpfr-$MPFR_VERSION.tar.xz
wget http://ftp.gnu.org/gnu/mpc/mpc-$MPC_VERSION.tar.gz
wget https://gcc.gnu.org/pub/gcc/infrastructure/isl-$ISL_VERSION.tar.bz2
wget https://jaist.dl.sourceforge.net/project/mingw-w64/mingw-w64/mingw-w64-release/mingw-w64-v$MINGW_VERSION.tar.bz2

编译Binutils

cd $BUILDDIR/tmp
tar -xf binutils-$BINUTILS_VERSION.tar.xz
cd binutils-$BINUTILS_VERSION
./configure --prefix=$BUILDDIR --target=$TARGET --with-sysroot=$BUILDDIR --disable-multilib 
make -j$(nproc) && make install

安装Mingw-w64头文件

cd $BUILDDIR/tmp
tar -xf mingw-w64-v$MINGW_VERSION.tar.bz2
cd mingw-w64-v$MINGW_VERSION/mingw-w64-headers
./configure --prefix=$BUILDDIR/$TARGET --host=$TARGET --enable-sdk=all --enable-idl --enable-secure-api --with-default-msvcrt=msvcrt --with-default-win32-winnt=0x0600
make all && make install

编译gcc-core

cd $BUILDDIR/tmp
tar -xf gcc-$GCC_VERSION.tar.xz
cd gcc-$GCC_VERSION
tar -xf ../mpfr-$MPFR_VERSION.tar.xz
mv -v mpfr-$MPFR_VERSION mpfr
tar -xf ../gmp-$GMP_VERSION.tar.xz
mv -v gmp-$GMP_VERSION gmp
tar -xf ../mpc-$MPC_VERSION.tar.gz
mv -v mpc-$MPC_VERSION mpc
tar -xf ../isl-$ISL_VERSION.tar.bz2
mv -v isl-$ISL_VERSION isl

进入新建的build目录,配置编译选项

mkdir build
cd build
../configure --prefix=$BUILDDIR --target=$TARGET --with-sysroot=$BUILDDIR --disable-multilib  --disable-shared --enable-languages=c,c++ --enable-threads=posix --disable-win32-registry --enable-version-specific-runtime-libs --enable-fully-dynamic-string --enable-libgomp --enable-libssp --enable-lto 

其中configure选项--enable-languages=c,c++定义启用的编程语言,--disable-shared的作用是可以让GCC编译出的程序不需要libgcc.dll等动态库就能运行,--enable-threads=posix表示线程模型为posix。当目标平台为Windows时,默认的线程模型为win32,这里为了完整支持C++ std::thread,需要将线程模型手动设置为posix。

因为编译器会在路径$BUILDDIR/mingw下搜索Mingw-w64的头文件,所以需要创建一个符号链接

ln -s $TARGET $BUILDDIR/mingw

因为还没有可用的CRT,libstdc++等库文件无法编译,目前我们只能编译gcc-core

make -j$(nproc) all-gcc && make install-gcc

至此,用于交叉编译的GCC核心编译器已经安装完成,打印其版本信息

$BUILDDIR/bin/$TARGET-g++ -v

输出信息为

Using built-in specs.
COLLECT_GCC=/home/cat/mingw64-cross/bin/x86_64-w64-mingw32-g++
COLLECT_LTO_WRAPPER=/home/cat/mingw64-cross/libexec/gcc/x86_64-w64-mingw32/11.2.0/lto-wrapper
Target: x86_64-w64-mingw32
Configured with: ../configure –prefix=/home/cat/mingw64-cross –target=x86_64-w64-mingw32 –with-sysroot=/home/cat/mingw64-cross –disable-multilib –disable-shared –enable-languages=c,c++ –enable-threads=posix –disable-win32-registry –enable-version-specific-runtime-libs –enable-fully-dynamic-string –enable-libgomp –enable-libssp –enable-lto
Thread model: posix
Supported LTO compression algorithms: zlib
gcc version 11.2.0 (GCC)

编译Mingw-w64的CRT

现在可以用刚才生成的GCC交叉编译器生成目标平台为Mingw-w64的CRT。先把交叉编译器的路径加入环境变量

export PATH=$BUILDDIR/bin:$PATH

编译安装CRT

cd $BUILDDIR/tmp/mingw-w64-v$MINGW_VERSION/mingw-w64-crt/
./configure --prefix=$BUILDDIR/$TARGET --host=$TARGET --enable-lib64 --enable-lib32=no --with-default-msvcrt=msvcrt --with-default-win32-winnt=0x0600
make -j$(nproc) && make install

其中configure选项--enable-lib64 --enable-lib32=no的含义是只编译64位的CRT。编译32位的工具链时,configure选项应改为

./configure --prefix=$BUILDDIR/$TARGET --host=$TARGET --enable-lib64=no --enable-lib32 --with-default-msvcrt=msvcrt --with-default-win32-winnt=0x0600

编译winpthreads

因为GCC编译器的线程模型为posix,所以还需要编译Mingw-w64提供的winpthreads库。

cd $BUILDDIR/tmp/mingw-w64-v$MINGW_VERSION/mingw-w64-libraries/winpthreads/
./configure --prefix=$BUILDDIR/$TARGET --host=$TARGET --enable-shared=no --enable-static
make -j$(nproc) && make install

继续编译GCC

现在可以编译完整的GCC编译器

cd $BUILDDIR/tmp/gcc-$GCC_VERSION/build
make -j$(nproc) && make install

最后要做的一点事情

删除临时文件

cd $BUILDDIR/
rm -rf $BUILDDIR/tmp/
rm $BUILDDIR/mingw

strip命令减小可执行文件和库文件的体积

cd $BUILDDIR/
find -executable -type f -exec strip -s {} ";" >& /dev/null
find . -name "*.a" -type f -exec $TARGET-strip -d {} ";" >& /dev/null
find . -name "*.o" -type f -exec $TARGET-strip -d {} ";" >& /dev/null

在文件.bashrc中把交叉编译器的路径加入到环境变量,方便以后使用

echo 'export PATH=$PATH:$HOME/mingw64-cross/bin' >> ~/.bashrc

对于32位的工具链,应该执行命令

echo 'export PATH=$PATH:$HOME/mingw32-cross/bin' >> ~/.bashrc

大部分树莓派用户都是把系统安装在SD卡上的,不过SD卡的寿命和可靠性还是远远不如硬盘,因此还是有必要对SD卡上的内容进行备份。树莓派关机以后,通过读卡器把SD卡插到安装Windows系统的计算机上,可以使用Win32DiskManager把SD卡备份到一个.img文件。不过,Win32DiskManager只能备份整个SD卡,包括分区中已用空间和剩余空间。如果SD卡容量比较大,备份过程会很耗时间,生成的.img文件的体积也和SD卡的容量相当,很占空间。相比之下,更合理的备份方法是只对分区中的已用空间进行备份,这样生成的.img文件的体积会小很多。

本文给出了一种树莓派系统备份的方法,可以只对SD卡中的已用空间进行备份,具体方法参考了Manjaro论坛的相关讨论。我的树莓派安装的是Manjaro系统,其他系统的备份方法也是类似的。

在树莓派关机后,把SD卡插到另一台安装有Linux系统的计算机上,后续所有备份步骤将会在这台计算机上完成。

准备工作

需要安装fsarchiver。在Debian系统上,通过apt安装

sudo apt install fsarchiver

创建一个工作文件夹

mkdir raspberrypi-backup
cd raspberrypi-backup

树莓派的SD卡一般包括bootroot两个分区,下面我们分别对它们进行备份。

备份boot分区

boot分区一般是FAT文件系统,直接挂载并且把文件复制出来即可

mkdir boot
mkdir boot-mount
sudo mount /dev/sdb1 boot-mount
cp -R boot-mount/* boot
sudo umount boot-mount

其中boot是备份文件夹,/dev/sdb1对应SD卡上的boot分区。

备份root分区

root分区一般是ext4文件系统,用fsarchiver备份

sudo fsarchiver -v -Z 19 -j 4 savefs root.fsa /dev/sdb2

其中root.fsa是备份文件,/dev/sdb2对应SD卡上的root分区,选项-j后的数字表示线程数。fsarchiver不仅可以备份,还会进行文件压缩。实测树莓派系统占用空间5.2G,备份文件root.fsa仅占用2G空间。

恢复方法

基于备份文件,可以把树莓派上安装的系统恢复到另外一块SD卡或者硬盘上。以Manjaro系统为例,首先在新的SD卡或者硬盘上创建一个150M大小的FAT32分区,添加标志BOOT_MNJRO,然后把boot目录内的文件都复制到该分区。接下来,在剩余空间上创建一个ext4根分区,添加标志ROOT_MNJRO,并且执行下面的命令恢复备份文件root.fsa的内容:

sudo fsarchiver -v -j 4 restfs root.fsa id=0,dest=/dev/sdc2
sudo sync

其中/dev/sdc2对应新的存储设备上的根分区。

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment