記一次編譯GCC的經歷

蓝溪落千涧發表於2024-06-10

背景

因為有在Linux環境編譯C++程式的需求,故我於近日在電腦上安裝了WSL。鑑於APT(Ubuntu的包管理器)提供的GCC版本較老(確切來說,APT會根據Ubuntu版本來下載並安裝某個版本的GCC,不一定為最新,例如對Ubuntu 22.04而言,從APT獲取的最新版本GCC為11.2.0),我便嘗試自己編譯一套GCC工具鏈。
在編譯之前,我發現GNU提供的GCC安裝教程內容組織較為混亂,新手容易踩坑(羊頭你這是生怕新手能順利編譯好GCC啊,你不會寫教程就別寫😠)。於是,在查閱了其他人編寫的GCC編譯教程後,我結合了我自己的(踩坑)經驗,編寫了這篇文章。

準備

  • Linux環境(我用的是WSL Ubuntu 22.04,因為這是WSL目前所提供的最新版本的Ubuntu)
  • 暢通無阻的網路環境
  • 先前的GCC編譯器
  • 一些其他的軟體包

步驟

開啟終端,先將本機上現有的軟體包更新至最新:

sudo apt update && sudo apt upgrade

若遇到網路問題,則需要更改映象源。本人推薦中科大映象源清華映象源。具體修改方法參見映象源提供的幫助資訊,此處不再贅述。

更新完成後,根據此頁面,我們需要安裝編譯GCC所需的軟體包:

sudo apt install build-essential python3 gnat gdc gm2 gawk binutils gzip bzip2 make tar perl libgmp-dev libmpfr-dev libmpc-dev libisl-dev zstd gettext autoconf m4 automake gperf dejagnu expect tcl autogen guile-3.0 flex texinfo texlive sphinx-common git ssh diffutils patch libtool

隨後,我們將GCC原始碼clone至本地:

git clone git://gcc.gnu.org/git/gcc.git

讀者可以自己修改存放原始碼的資料夾名稱,只需在連結後面加上資料夾名稱即可,例如gcc_src。這裡我就用預設的gcc資料夾來指代GCC原始碼目錄了,以下同理。

若遇到網路問題,則同樣可以從映象源clone。只需把連結換成https://mirrors.tuna.tsinghua.edu.cn/git/gcc.git即可(此處以清華映象源舉例)。

在進入GCC原始碼目錄之前,我們可以先建立一個名為gcc_build的資料夾(即存放GCC臨時編譯檔案及GCC本體的資料夾),與GCC原始碼目錄同級:

mkdir gcc_build

此時執行ls,終端輸出如下:

gcc gcc_build

隨後透過cd gcc進入GCC原始碼目錄。

在配置GCC編譯配置前,我們需要切換tag至某個release版本,否則編譯產物將為當前最新的GCC開發版。當前最新的發行版GCC的版本號為14.1.0,因此我們執行此命令:

git checkout releases/gcc-14.1.0

這樣就可以了。

  • 可能讀者知道GCC原始碼裡已經包含了自動安裝依賴的指令碼,即./contrib/download_prerequisites。我們還需要執行它嗎?答案是不需要。我大致分析了指令碼內容,發現這個指令碼下載並安裝的是這五個軟體包:gmpmpfrmpcislgettext,相關原始碼可見此。而這些軟體包,我們已經在前面安裝過了,所以我們無需再安裝一遍它們。

接下來,我們進入到我們剛剛建立的新資料夾:

cd ..
cd gcc_build

根據此頁面,我們需要先配置好GCC編譯配置。這裡給出我的編譯配置,讀者可以按需修改:

../gcc/configure --prefix=/usr/local/gcc-14.1.0 --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --enable-languages=c,c++,go,jit,lto,rust --enable-host-shared --enable-shared --enable-static --enable-libatomic --enable-graphite --enable-fully-dynamic-string --enable-libstdcxx-filesystem-ts --enable-lto --enable-libgomp --enable-linker-build-id --enable-threads=posix --enable-nls --enable-bootstrap --enable-locale=gnu --enable-cxx-locale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time --enable-gnu-unique-object --enable-plugin --enable-default-pie --enable-cet --enable-checking=release --enable-link-serialization=2 --disable-multilib --with-build-config=bootstrap-lto --with-boot-ldflags=-static-libstdc++ --with-stage1-ldflags=-static-libstdc++ --with-libiconv --with-default-libstdcxx-abi=new --with-system-zlib --with-target-system-zlib=auto --with-tune=generic --without-included-gettext --without-cuda-driver
  • 由於本人也有Rust相關需求,故--enable-languages一項新增了rust。新增rust時,讀者應確保本機已安裝Rust。若不安裝Rust就執行此命令,則此命令會報錯,提示“找不到Cargo”。安裝Rust的步驟見此

接下來就可以愉快的make了!(然後編譯失敗時就愉快不起來了XD)

編譯完成後,執行sudo make install,編譯好的GCC便會安裝至/usr/local/gcc-14.1.0

接下來,我們可以選擇替換掉系統原來的GCC:

sudo update-alternatives --install /usr/bin/gcc gcc /usr/local/gcc-14.1.0/bin/gcc 60
sudo update-alternatives --install /usr/bin/g++ g++ /usr/local/gcc-14.1.0/bin/g++ 60

替換掉原來的GCC的好處是,你可以直接執行gcc命令而無需新增目錄字首,使用起來會更方便。

我們再執行命令gcc -v,就會得到如截圖所示的輸出:

image

這就表示我們的替換已經生效了!

總結

編譯GCC會鍛鍊耐力,原因有二:

  1. GCC配置非常多,這便是在鍛鍊耐力與英語閱讀理解能力(當然逃課辦法是用CharGPT,不過它可能會給你錯誤答案)。

  2. GCC編譯過程非常慢,短則半小時,長則好幾個小時,期間還有可能發生意外(我遇到的意外有“找不到xxx.cc”,以及因記憶體不足,從而編譯器程序被系統殺死等)導致編譯失敗,這便也是在鍛鍊耐力,即:有條不紊、鎮定自若地處理錯誤,然後從頭開始編譯/配置(痛苦面具.jpg)之耐力。

不說了,好累!我要去休息一下!

相關文章