LLVM 建置 Dockerfile 指南

簡介

您可以在 llvm/utils/docker 中找到許多來源,用於建置包含 LLVM 組件的 Docker 映像檔。 任何想要建置 Docker 映像檔供自己使用的人,或者想要撰寫自己的 Dockerfile 的人,都可以使用這些來源作為起點。

我們目前提供以 debian12nvidia-cuda 基礎映像檔為基礎的 Dockerfile。 我們也提供一個 example 映像檔,其中包含佔位符,您需要填寫這些佔位符,才能為新的 Docker 映像檔產生 Dockerfile。

為什麼?

Docker 映像檔提供了一種在受控環境中產生軟體二進位發行版本的方法。 在 LLVM 儲存庫中擁有用於建置 Docker 映像檔的 Dockerfile,使得它們比放在任何其他地方更容易被發現。

Docker 基礎知識

如果您以前從未聽說過 Docker,您可能會覺得本節有助於您對它進行非常基本的了解。 Docker 是一種流行的解決方案,用於在隔離且可重現的環境中執行程式,特別是為了維護部署到大型分散式叢集的軟體版本。 它使用 Linux 核心命名空間和 cgroup,在目前執行的 Linux 核心內提供輕量級隔離。 Docker 化環境的單個活動實例稱為 Docker 容器。 Docker 容器檔案系統的快照稱為 Docker 映像檔。 可以從預先建置的 Docker 映像檔啟動容器。

Docker 映像檔是從所謂的 Dockerfile 建置的,Dockerfile 是一種用專門語言編寫的原始檔,它定義了在建置 Docker 映像檔時要使用的指令 (詳情請參閱 官方文件)。 最簡化的 Dockerfile 通常包含一個基礎映像檔和許多必須執行的 RUN 指令才能建置映像檔。 建置新映像檔時,Docker 將首先下載您的基礎映像檔,將其檔案系統掛載為唯讀,然後在其頂部新增一個可寫覆蓋層,以追蹤在建置映像檔時執行的所有檔案系統修改。 建置過程完成後,您的映像檔最終檔案系統狀態與基礎映像檔檔案系統之間的差異將儲存在產生的映像檔中。

概述

llvm/utils/docker 資料夾包含 Dockerfile 和簡單的 bash 腳本,可作為任何想要使用從原始碼編譯的 LLVM 組件建立自己的 Docker 映像檔的人的基礎。 來源在建置映像檔時從上游 git 儲存庫檢出。

產生的映像檔僅包含請求的 LLVM 組件和一些額外的套件,以使映像檔對於 C++ 開發至少有用,例如 libstdc++ 和 binutils。

執行建置的介面是 build_docker_image.sh 腳本。 它接受要檢出的 LLVM 儲存庫列表和 CMake 調用的參數。

如果您想撰寫自己的 Docker 映像檔,請從 example/ 子資料夾開始。 它提供了一個不完整的 Dockerfile,其中包含 (非常少的) FIXME,解釋了您需要採取的步驟才能使您的 Dockerfile 正常運作。

用法

llvm/utils/build_docker_image.sh 腳本提供了相當高程度的控制,可以控制如何執行建置。 它允許您指定要從 git 檢出的專案,並提供在 Docker 容器內建置 LLVM 時要使用的 CMake 參數列表。

這是一個非常簡單的範例,說明如何取得包含 clang 二進位檔的 Docker 映像檔,該二進位檔由 debian12 映像檔中的系統編譯器編譯

./llvm/utils/docker/build_docker_image.sh \
    --source debian12 \
    --docker-repository clang-debian12 --docker-tag "staging" \
    -p clang -i install-clang -i install-clang-resource-headers \
    -- \
    -DCMAKE_BUILD_TYPE=Release

請注意,像這樣的建置不會使用您可能想要用於 clang 的 2 階段建置過程。 執行 2 階段建置稍微複雜一些,此命令將執行此操作

# Run a 2-stage build.
#   LLVM_TARGETS_TO_BUILD=Native is to reduce stage1 compile time.
#   Options, starting with BOOTSTRAP_* are passed to stage2 cmake invocation.
./build_docker_image.sh \
    --source debian12 \
    --docker-repository clang-debian12 --docker-tag "staging" \
    -p clang -i stage2-install-clang -i stage2-install-clang-resource-headers \
    -- \
    -DLLVM_TARGETS_TO_BUILD=Native -DCMAKE_BUILD_TYPE=Release \
    -DBOOTSTRAP_CMAKE_BUILD_TYPE=Release \
    -DCLANG_ENABLE_BOOTSTRAP=ON -DCLANG_BOOTSTRAP_TARGETS="install-clang;install-clang-resource-headers"

這將從最新的上游修訂版產生一個新的映像檔 clang-debian12:staging。 映像檔建置完成後,您可以像這樣在基於您的映像檔的容器內執行 bash

docker run -ti clang-debian12:staging bash

現在您可以像平常一樣執行 bash 命令

root@80f351b51825:/# clang -v
clang version 19.1.7 (trunk 524462)
Target: x86_64-unknown-linux-gnu
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /bin

我應該選擇哪個映像檔?

我們目前提供兩個映像檔:基於 Debian12 和基於 nvidia-cuda。 它們的差異在於它們使用的基礎映像檔,也就是說,它們具有不同的預先安裝的二進位檔集。 Debian8 非常簡潔,nvidia-cuda 較大,但具有預先安裝的 CUDA 程式庫,並允許存取安裝在您機器上的 GPU。

如果您需要一個僅包含 clang 和 libstdc++ 的最簡化 Linux 發行版,您應該嘗試基於 Debian12 的映像檔。

如果您想使用 CUDA 程式庫並存取您機器上的 GPU,您應該選擇基於 nvidia-cuda 的映像檔,並使用 nvidia-docker 來執行您的 Docker 容器。 請注意,您不需要 nvidia-docker 來建置映像檔,但您需要它才能從執行已建置映像檔的 Docker 容器存取 GPU。

如果您有不同的使用案例,您可以根據 example/ 資料夾建立自己的映像檔。

任何 Docker 映像檔都可以僅使用 Docker 二進位檔來建置和執行,也就是說,您可以在 Fedora 或任何其他 Linux 發行版上執行 debian12 建置。 您不需要安裝 CMake、編譯器或任何其他 clang 相依性。 這一切都在 Docker 隔離環境中的建置過程中處理。

穩定建置

如果您想要一個在某種程度上最新且在某種程度上穩定的建置版本,請使用 branches/google/stable 分支,也就是說,以下命令將為您產生一個基於 Debian12 的映像檔,該映像檔使用最新的 google/stable 來源

./llvm/utils/docker/build_docker_image.sh \
    -s debian12 --d clang-debian12 -t "staging" \
    --branch branches/google/stable \
    -p clang -i install-clang -i install-clang-resource-headers \
    -- \
    -DCMAKE_BUILD_TYPE=Release

最小化 Docker 映像檔大小

由於 Docker 檔案系統的工作方式,所有中間寫入都會保留在產生的映像檔中,即使它們在後續命令中被移除。 為了最小化產生的映像檔大小,我們使用 多階段 Docker 建置。 在內部,Docker 建置兩個映像檔。 第一個映像檔完成所有工作:安裝建置相依性、檢出 LLVM 原始碼、編譯 LLVM 等。 第一個映像檔僅在建置期間使用,並且沒有描述性名稱,也就是說,它只能在建置完成後透過雜湊值存取。 第二個映像檔是我們的產生的映像檔。 它僅包含已建置的二進位檔,而不包含任何建置相依性。 它也可以透過描述性名稱存取 (由 -d 和 -t 標誌指定)。