网络上相关资料更多都是在制作 Linux x86_64 和 Linux arm64 之间的交叉编译器,我也尝试过,但流程很复杂,每个人的编译环境又不同,很容易编译失败。 因为我平时主要在 Windows 平台上工作,所以尝试在 Linux 上编译一个 Windows 上运行的 GCC,经过数十次编译失败,耗费N个小时后,终于成功了!
首先有些基本概念要了解一下:
有个工具包叫Binutils,它是汇编器、链接器的源码,是必须要编译的,它不依赖 glibc 和 Linux 头文件,比较独立,所以编译一般不会出问题。
如果目标是 Linux 平台,则编译过程比较复杂,gcc、glibc要分阶段编译,比较复杂,容易失败。而目标平台是 Windows 的话则简单很多。
准备
我的编译环境是 Ubuntu 16.04
1 2 3 4 5 6
# lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 16.04.7 LTS Release: 16.04 Codename: xenial
# ldd --version ldd (Ubuntu GLIBC 2.23-0ubuntu11.3) 2.23 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the sourcefor copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Written by Roland McGrath and Ulrich Drepper.
cd /opt tar xf binutils-2.44.tar.xz cd binutils-2.44/ mkdir build && cd build ../configure --prefix=$PREFIX --disable-nls --disable-multilib --build=$BUILD --host=$HOST --target=$TARGET make -j$(nproc) make install-strip
binutils 不依赖内核头文件和 glibc,几乎不会失败。
编译 Stage 1 GCC
编译第一阶段的 GCC,仅编译 C 部分,它的目的是编译后面的 mingw crt.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
cd /opt tar xf gcc-15.1.0.tar.xz cd gcc-15.1.0/ ./contrib/download_prerequisites mkdir build1 && cd build1 ../configure --prefix=$PREFIX \ --with-sysroot=$SYSROOT \ --enable-languages=c \ --disable-shared \ --disable-threads \ --disable-libstdcxx \ --disable-multilib \ --disable-werror \ --disable-checking \ --build=$BUILD \ --host=$HOST \ --target=$TARGET
if [ -d ../prev-gcc ]; then \ cd ../prev-gcc && \ make real-install-headers-tar DESTDIR=`pwd`/../gcc/ \ libsubdir=. ; \ else \ set -e; for ml in `cat fixinc_list`; do \ sysroot_headers_suffix=`echo ${ml} | sed -e 's/;.*$//'`; \ multi_dir=`echo ${ml} | sed -e 's/^[^;]*;//'`; \ fix_dir=include-fixed${multi_dir}; \ if ! false && test ! -d `echo /usr/x86_64-w64-mingw32${sysroot_headers_suffix}/mingw/include | sed -e :a -e 's,[^/]*/\.\.\/,,' -e ta`; then \ echo "The directory (BUILD_SYSTEM_HEADER_DIR) that should contain system headers does not exist:" >&2 ; \ echo " `echo /usr/x86_64-w64-mingw32${sysroot_headers_suffix}/mingw/include | sed -e :a -e 's,[^/]*/\.\.\/,,' -e ta`" >&2 ; \ case linux-gnu in \ darwin*) \ echo "(on Darwin this usually means you need to pass the --with-sysroot= flag to point to a valid MacOS SDK)" >&2; \ ;; \ esac; \ tooldir_sysinc=`echo "/opt/x86_64-w64-mingw32-gcc15/lib/gcc/x86_64-w64-mingw32/15.1.0/../../../../x86_64-w64-mingw32/sys-include" | sed -e :a -e "s,[^/]*/\.\.\/,," -e ta`; \ if test "x`echo /usr/x86_64-w64-mingw32${sysroot_headers_suffix}/mingw/include | sed -e :a -e 's,[^/]*/\.\.\/,,' -e ta`" = "x${tooldir_sysinc}"; \ then sleep 1; else exit 1; fi; \ fi; \ /bin/bash ../../gcc/../mkinstalldirs ${fix_dir}; \ chmod a+rx ${fix_dir} || true; \ (TARGET_MACHINE='x86_64-w64-mingw32'; srcdir=`cd ../../gcc; ${PWDCMD-pwd}`; \ SHELL='/bin/bash'; MACRO_LIST=`${PWDCMD-pwd}`/macro_list ; \ gcc_dir=`${PWDCMD-pwd}` ; \ export TARGET_MACHINE srcdir SHELL MACRO_LIST && \ cd ../build-x86_64-linux-gnu/fixincludes && \ /bin/bash ./fixinc.sh "${gcc_dir}/${fix_dir}" \ `echo /usr/x86_64-w64-mingw32${sysroot_headers_suffix}/mingw/include | sed -e :a -e 's,[^/]*/\.\.\/,,' -e ta` ); \ done; \ fi The directory (BUILD_SYSTEM_HEADER_DIR) that should contain system headers does not exist: /usr/x86_64-w64-mingw32/mingw/include make[2]: *** [Makefile:3643: stmp-fixinc] Error 1 make[2]: *** Waiting for unfinished jobs.... rm gcc.pod make[2]: Leaving directory '/opt/gcc-15.1.0/build/gcc' make[1]: *** [Makefile:4728: all-gcc] Error 2 make[1]: Leaving directory '/opt/gcc-15.1.0/build' make: *** [Makefile:1068: all] Error 2
cd /opt/mingw-w64-v13.0.0/mingw-w64-crt mkdir build && cd build ../configure --prefix=$SYSROOT --build=$BUILD --host=$TARGET make -j$(nproc) make install-strip
编译完整 GCC
这是最后一步,编译完整的 GCC。注意编译时新建一个文件夹,不要在第一次的 build 目录中进行
1 2 3 4 5
cd /opt/gcc-15.1.0/ mkdir build2 && cd build2 ../configure --prefix=$PREFIX --with-sysroot=$SYSROOT --enable-languages=c,c++ --enable-threads=win32 --enable-shared --disable-multilib --disable-werror --disable-checking --build=$BUILD --host=$HOST --target=$TARGET make -j$(nproc) make install-strip