LLVM 构建 Dockerfile 指南¶
简介¶
您可以在 llvm/utils/docker
中找到许多用于构建包含 LLVM 组件的 Docker 镜像的源代码。任何想要为自身构建 Docker 镜像的人,或者想要编写自己的 Dockerfile 的人,都可以使用这些源代码。 它们也可以作为起点。
我们目前提供了基于 debian10
和 nvidia-cuda
基础镜像的 Dockerfile。我们还提供了一个 example
镜像,其中包含了创建新 Docker 镜像的 Dockerfile 所需的占位符。
为什么?¶
Docker 镜像提供了一种在受控环境中生成软件二进制发行版的方式。在 LLVM 代码库中提供构建 Docker 镜像的 Dockerfile,使得它们比放在其他任何地方都更容易被发现。
Docker 基础知识¶
如果您以前从未听说过 Docker,那么本节可能会对您有所帮助,它提供了 Docker 的基本解释。Docker 是一种流行的解决方案,用于在隔离且可重现的环境中运行程序,尤其是在维护部署到大型分布式集群的软件版本时。它使用 Linux 内核命名空间和控制组,在当前运行的 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 参数列表。
以下是一个使用系统编译器在 debian10 镜像中编译 clang 二进制文件的 Docker 镜像的简单示例:
./llvm/utils/docker/build_docker_image.sh \
--source debian10 \
--docker-repository clang-debian10 --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 debian10 \
--docker-repository clang-debian10 --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-debian10:staging
。构建镜像后,您可以像这样在基于您的镜像的容器中运行 bash:
docker run -ti clang-debian10:staging bash
现在您可以像往常一样运行 bash 命令了。
root@80f351b51825:/# clang -v
clang version 5.0.0 (trunk 305064)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /bin
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.8.4
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
Found candidate GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9.2
Selected GCC installation: /usr/lib/gcc/x86_64-linux-gnu/4.9
Candidate multilib: .;@m64
Selected multilib: .;@m64
我应该选择哪个镜像?¶
我们目前提供了两个镜像:基于 Debian10 和基于 nvidia-cuda 的镜像。它们的区别在于它们使用的基础镜像,即它们具有不同的预安装二进制文件集。Debian10 非常精简,nvidia-cuda 较大,但预安装了 CUDA 库,并允许访问您机器上安装的 GPU。
如果您需要一个仅包含 clang 和 libstdc++ 的最小 Linux 发行版,则应尝试基于 Debian10 的镜像。
如果您想使用 CUDA 库并访问您机器上的 GPU,则应选择基于 nvidia-cuda 的镜像并使用 nvidia-docker 运行 Docker 容器。请注意,您不需要 nvidia-docker 来构建镜像,但需要它才能从运行已构建镜像的 Docker 容器访问 GPU。
如果您有不同的用例,您可以根据 example/
文件夹创建自己的镜像。
任何 Docker 镜像都可以仅使用 Docker 二进制文件构建和运行,即您可以在 Fedora 或任何其他 Linux 发行版上运行 debian10 构建。您无需安装 CMake、编译器或任何其他 clang 依赖项。所有这些都在 Docker 隔离环境中的构建过程中处理。
稳定构建¶
如果您想要一个相对较新且稳定的构建,请使用 branches/google/stable
分支,即以下命令将为您生成一个基于 Debian10 的镜像,使用最新的 google/stable
源代码:
./llvm/utils/docker/build_docker_image.sh \
-s debian10 --d clang-debian10 -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 标志指定)。