LLVM 构建 Dockerfile 指南¶
简介¶
您可以在 llvm/utils/docker
中找到许多用于构建包含 LLVM 组件的 Docker 镜像的资源。 任何想要构建 Docker 镜像供自己使用的人,或者想要编写自己的 Dockerfile 的人,都可以使用它们作为起点。
我们目前提供基于 debian12
和 nvidia-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 参数列表。
这是一个非常简单的示例,演示如何获取由 debian12 镜像中的系统编译器编译的 clang 二进制文件
./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 的两阶段构建过程。 运行两阶段构建稍微复杂一些,以下命令将执行此操作
# 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 标志指定)。