LWN: 使用TuxMake来确保kernel编译结果可重现!-程序员宅基地

技术标签: python  java  linux  编程语言  docker  

关注了就能看到更多这么棒的文章哦~

Portable and reproducible kernel builds with TuxMake

January 5, 2021

This article was contributed by Dan Rue
DeepL assisted translation
https://lwn.net/Articles/841624/

Linaro 公司有一个名为 TuxMake 的开源项目,始于 2020 年 5 月,目标是使构建 Linux 内核的过程变得更容易。它提供了命令行界面以及一个 Python 库,还有一套精心准备的可移植的基于 container image 形式发布的构建环境。通过 TuxMake,开发者可以针对已经支持的 target architecture、toolchain、kernel configuration 和 make target 的任意组合来编译生成目标文件。

构建一个 Linux 内核并不困难。按照文档安装好依赖的 package,并运行几个 make 命令就行。然而,如果一个开发者想要为多个架构、多个 toolchain 来构建内核,就会变得越来越复杂起来。大多数开发者和维护者都有一套自己编写和维护的定制脚本,来完成他们所需的编译工作。TuxMake 提供了一个通用的抽象层,从而可以每个开发者可以减少自己编写的构建脚本。

TuxMake 为 toolchain/architecture 的各种组合发布了不同的 container。这些 container 可以使得开发人员自己不需要在他们的系统上来安装多种不同的 toolchain,甚至安装同一个 toolchain 的不同版本。它也使得这个编译构建的环境是 reproducible 并且 portable 的(可复制且可移植的),毕竟采用这种解决方案之后,构建内核的开发环境就被按照版本来完善地记录管理好的,而且可以在互联网和邮件列表中互相共享。

TuxMake 有两个目标。首先,把那些导致开发者(尤其是新开发者)不愿意针对一些不常见的 toolchain/architecture 组合进行编译测试的那些有阻碍的因素解决掉;第二,让编译过程和其中出现的问题可以更容易地被描述和重现出来。

Features

已经支持的架构有 arc, arm, arm64, i386, mips, parisc, powerpc, riscv, s390, sh, sparc, 和 x86_64。已经获得支持的工具链有 GCC 8、9 和 10 版本,Clang 10、11 和 nightly (最新) 版本。针对这些组合,都支持生成 kernel 的配置(Kconfig)、内核映像文件、modules、device tree binaries (DTBs) ,以及 debug kernel image。TuxMake 团队计划后续能生成更多产物,比如生成 kselftest、cpupower、perf,甚至还有文档。

支持使用符合 Open Container Initiative(OCI)规范的 container 和 container runtime,以实现编译过程的 portability 和 reproducibility。Docker 和 Podman runtime 都支持,并且可以互相交换支持,完全取决于每个用户自己的偏好。Podman 是 Docker 的一个比较流行的替代品,因为它不不需要守护进程,不需要 root 权限。今后还可以根据需要添加额外的 container runtime。

How does it work?

在使用 TuxMake 的 Linux 系统终端中,你可以先来到一个你通常会直接运行 make 的 Linux 内核源代码目录,然后运行 tuxmake 。没有任何参数的话,tuxmake 会对所有选项使用默认值来执行编译。看起来会像下面这样:

$ tuxmake
    # to reproduce this build locally: tuxmake --target-arch=x86_64 \
    #    --kconfig=defconfig --toolchain=gcc --wrapper=none --runtime=null \
    #             config kernel xipkernel debugkernel modules dtbs

首先,会打印出 tuxmake 生成的命令,包括所有提供的参数。这些信息对于后续重新复现这个编译过程以及跟同事讨论的时候很有用处。

make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/676/tmp defconfig

这里就会使用 defconfig 来建立一个 .config。请注意,默认情况下,会保存在 ~/.cache/tuxmake 下自动创建的一个目录中。所有的中间文件和编译产物都会保存在那里。

make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/676/tmp
make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/676/tmp bzImage

这样就会生成缺省内核以及 bzImage。由于第一个 make 调用已经完成了生成 bzImage 的工作,因此为 x86_64 明确再指定要生成 bzImage 似乎是多余的步骤。事实上,并不是所有的架构都能同样这样处理的,因此 tuxmake 并没有对这些架构进行特别处理,也没有在内核代码中加入对这些怪癖的支持,而是专门明确地指定最终要生成什么样的映像文件。大多数情况下,这一步其实是不需要的。

make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/676/tmp vmlinux
xz -T0 --keep /home/drue/.cache/tuxmake/builds/676/tmp/vmlinux

这两个命令会生成用于调试的 kernel image,保存到 output 目录使用 xz 压缩一下。就像之前一步一样,make vmlinux 可能看起来是多余的,因为 vmlinux 已经由 make 生成了。然而,debug kernel image 也可以单独生成。在一个完整的编译过程中,make vmlinux 将是一个不需要的操作,但如果只希望编译生成 debug kernel,那么它就会是主要的编译步骤。

grep -q CONFIG_MODULES=y /home/drue/.cache/tuxmake/builds/676/tmp/.config
make --silent --keep-going --jobs=16 \
     O=/home/drue/.cache/tuxmake/builds/676/tmp modules_install INSTALL_MOD_STRIP=1 \
     INSTALL_MOD_PATH=/home/drue/.cache/tuxmake/builds/676/tmp/modinstall
tar -caf /home/drue/.cache/tuxmake/builds/676/tmp/modules.tar.xz \
    -C /home/drue/.cache/tuxmake/builds/676/tmp/modinstall lib

如果在 build config 中启用了 kernel module,那么就会需要编译生成 module 文件,并使用 modules_install 来收集在一起,存放在 output 目录的 tar.xz 文件中。

I: config: PASS in 0:00:01.305649
I: kernel: PASS in 0:01:31.887716
I: debugkernel: PASS in 0:00:08.207033
I: modules: PASS in 0:00:00.869124
I: build output in /home/drue/.cache/tuxmake/builds/676

最后,显示每个 target 的构建状态(PASS/FAIL/SKIP)和构建时间,以及 output 目录的路径。

container 并不是必需的,缺省情况下也就没有使用。在没有使用 container runtime 的情况下,TuxMake 运行时会使用本地可用的 toolchain。而如果指定了 container runtime 的话,TuxMake 将在构建时先下载 container image(如果之前没有下载过的话),并在 container 之内来进行构建。它会将 Linux 源代码目录和 output 目录都 mount 到 container 之内,并在一个临时的 container 中逐步执行构建工作。这个 container 只在构建期间运行,完成后就会退出。

下面是一个更详细的例子,包括了上面说的这些所有步骤。这里会利用 Podman 来采用 Clang 编译生成一个 arm64 kernel,并打开 KASAN:

$ tuxmake -r podman -a arm64 -t clang-11 -k defconfig -K CONFIG_KASAN=y -w ccache
          # to reproduce this build locally: tuxmake --target-arch=arm64 --kconfig=defconfig \
          #   --kconfig-add=CONFIG_KASAN=y --toolchain=clang-11 --wrapper=ccache \
          #                --runtime=podman --image=tuxmake/arm64_clang-11 \
          #                config kernel xipkernel debugkernel modules dtbs

这里指定了使用 podman 作为 runtime,因此 TuxMake 将使用 Podman 来执行构建。内核将采用 Clang 11 版本 (-t clang-11) 来编译生成 aarch64 (-a arm64) 的目标。内核的配置是使用 defconfig target 来生成的,然后显式地打开 KASAN。并且,启用了 ccache (-w ccache) 来减少构建时间。

Trying to pull docker.io/tuxmake/arm64_clang-11...

此前如果没有下载过的话,这里会从 TuxMake 的公共 container registry 也就是 hub.docker.com/u/tuxmake 中来 pull arm64_clang-11 的 container。

# CONFIG_KASAN=y -> /home/drue/.cache/tuxmake/builds/685/tmp/0.config
make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/685/tmp \
     ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
     'HOSTCC=ccache clang' 'CC=ccache clang' defconfig
scripts/kconfig/merge_config.sh -m -O /home/drue/.cache/tuxmake/builds/685/tmp \
       /home/drue/.cache/tuxmake/builds/685/tmp/.config \
       /home/drue/.cache/tuxmake/builds/685/tmp/0.config
Using /home/drue/.cache/tuxmake/builds/685/tmp/.config as base
Merging /home/drue/.cache/tuxmake/builds/685/tmp/0.config
#
# merged configuration written to /home/drue/.cache/tuxmake/builds/685/tmp/.config (needs make)
#
make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/685/tmp \
     ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
     'HOSTCC=ccache clang' 'CC=ccache clang' olddefconfig

这里的 .config 也是通过构建 defconfig 来生成的,然后使用 merge_config.sh 来合并开发者想指定的 config 选项。剩余的构建工作将按照预期进行。与第一个例子的唯一区别是增加了构建 DTB 的功能,因为这是一个 arm64 内核。

make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/685/tmp \
     ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
     'HOSTCC=ccache clang' 'CC=ccache clang' dtbs
mkdir -p /home/drue/.cache/tuxmake/builds/685/tmp/dtbsinstall/dtbs
make --silent --keep-going --jobs=16 O=/home/drue/.cache/tuxmake/builds/685/tmp \
     ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- \
     'HOSTCC=ccache clang' 'CC=ccache clang' dtbs_install \
     INSTALL_DTBS_PATH=/home/drue/.cache/tuxmake/builds/685/tmp/dtbsinstall/dtbs
tar caf /home/drue/.cache/tuxmake/builds/685/tmp/dtbs.tar.xz \
    -C /home/drue/.cache/tuxmake/builds/685/tmp/dtbsinstall dtbs

DTBs build 的输出文件就是 output 目录下的 dtbs.tar.xz 文件,其中包含了所有的 DTB。

指定并管理 Linux 内核 config 选项一直是一个难题。TuxMake 提供了一个 --kconfig 参数,默认就是 defconfig 文件。如果选择了不同的文件,那么就会针对相应的 config target(如 tinyconfig、allmodconfig 或 allnoconfig)来进行编译。也支持使用那些不属于预设配置文件的路径或 URL。

此外还可以额外指定一些 Kconfig 选项,这是通过使用一个或多个 --kconfig-add 参数来指定的。 --kconfig-add 参数可以是一个配置文件代码片段的路径或 URL,也可以是一个 Kconfig 字符串,例如 CONFIG_KASAN=y。如果提供的是 URL,就会先下载下来。这里所额外指定的所有 config 选项都会用 scripts/kconfig/merge_config.sh 和 make olddefconfig 来合并起来。

在编译完成之后,目录中将包含一个 build log、压缩后的内核映像文件、kernel config、一个描述了 build 过程以及环境设置等各个方面的 JSON metadata 文件、system map 文件、压缩过的 debug kernel、压缩过的包含所有 module 文件的 tar 包、和压缩过的 DTB tar 文件。随着后续实现更多的 target,将会有更多的生成产物。

Portability and reproducibility

因为 TuxMake 使用的构建环境是可以共享的,而且比如 Kconfig 之类的配置都可以用 URL 来指定,所以 TuxMake 的构建命令可以简单发送给其他人。在向邮件列表报告构建问题的时候,一行 TuxMake 命令就包含了能复现这个构建问题的精确指令。随便哪个用户对着同一个 Linux 源代码目录来执行相同的 TuxMake 命令,都会看到相同的编译结果。

此外也可以支持每个 bit 都精确可重复生成的编译方式,但这需要额外的构建参数。首先,必须使用完全相同的 container。这可以通过 –image 参数来实现,该参数可以是指向某个 container 的完整路径,同时包括 sha256 digest 摘要数据。其次,环境变量 KBUILD_BUILD_TIMESTAMP, KBUILD_BUILD_USER, 和 KBUILD_BUILD_HOST 都必须要先用 -e 来设置好,因为它们会影响到最终生成的内核镜像文件。在正常情况下,只要上述这些数据都是采用同样的设置,那么编译出来的二进制文件就一定是与之相匹配的(除了在 kernel.org 上已经明确介绍了的那些 reproducible build 中的例外事项)。

例如,下面的命令会在 x86_64 host 上针对标签为 v5.10 的 Linux 源代码进行编译,产生一个以 8d066f679eac 开头的 bzImage sha256。无论使用 -r podman 还是 -r docker 都可以。

$ tuxmake --image \
  docker.io/tuxmake/x86_64_gcc@sha256:f8218cbfad8ecf6628fc44db864a402070feb87ff43a880e1409649172d4bc8c \
  -r podman -k tinyconfig \
  -e "KBUILD_BUILD_TIMESTAMP='Tue May 26 16:16:14 2020 -0500'" \
  -e "KBUILD_BUILD_USER=tuxmake" \
  -e "KBUILD_BUILD_HOST=tuxmake"

请注意,这个例子是用 TuxMake 0.11.0 来执行的,在可预见的未来应该都是没问题的。然而,TuxMake 未来的版本可能会在构建环境中引入额外的默认变量,从而导致这个例子不再能兼容。

Quality

TuxMake 的行为是否足够显而易见、足够透明、足够可靠,这是最重要的。如果无法拥有基本的信任以及质量,那么开发这个工具就得不偿失的。TuxMake 确保了 100% 的单元测试覆盖率,这意味着每一行代码都有至少一个基本测试能覆盖到。此外,它还包含了全面的集成测试,会使用一个内嵌的(包含在它自己的 Git 仓库之内)"fakelinux" 代码库,这样就可以用来针对每种支持的 runtime 环境来模拟大量的伪内核构建以及边边角角的情况。

遍历测试(Mutation testing)在 TuxMake 代码库中经常使用到,通过针对运行的代码来专门生成一些变化并且,并确保每种变化都有相应的 failing test case(专门确保出错的 test case),来发现那些不容易覆盖到的边角情况。。

该项目还采用了对所提供的 container image 内容的自动测试,以避免出现 regression。这些测试包括去检查需要的工具和编译器是否在默认的 $PATH 中可以直接用到,以及在实际构建中使用 container image 的集成测试。

针对每一个 merge request,以及针对每一个真正合入 TuxMake 的改动,都会使用 GitLab pipeline 来自动进行所有这些测试。

Getting Started

TuxMake 可以从源码来安装,也可以用 pip 安装。如果要想使用 container runtime,那么还要安装 Docker 或 Podman,并且确保用户有权限运行 container。其他的安装选项以及完整的文档在在 docs.tuxmake.org。新功能的提出,以及 bug fix 等会作为 GitLab issue 来跟踪。

除了命令行接口之外,TuxMake 还提供了一个 Python 接口,可以用来从 Python 代码发起 Linux 内核构建。大多数在命令行中可用的参数也可以用于 Build() 这个构造函数,下面是一个最小的例子:

import tuxmake.build

build = tuxmake.build.Build("/home/drue/src/linux-mainline")
build.run()

TuxMake 由 Linaro 和 TuxBuild 这个商业化的构建服务来赞助。TuxMake 在本地运行,来执行单个内核的构建,而 TuxBuild 则是一个集成到了持续集成(CI)系统中的 API,可以根据需要来并行执行大量 Linux 内核构建工作。

开发 TuxMake 是为了能解决不受限于具体 target、架构、toolchain、内核配置以及构建主机的环境的自动 Linux 内核构建问题。Git 解决了 Linux 源代码这一边的问题,使得人们可以轻松地确定某任何一个版本的内核代码,交流中不受时间和空间的限制。我们希望 TuxMake 能够提供一个通用的接口,来执行 Linux 内核构建、解决 reproducibility 问题,也可以清晰地交流清楚任何 Linux kernel build 的问题,从而帮助解决 Linux 的编译难题。

[I would like to thank Antonio Terceiro, TuxMake's author and maintainer, for his help with this article.]

全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。

欢迎分享、转载及基于现有协议再创作~

长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Linux_Everything/article/details/112855663

智能推荐

分布式光纤传感器的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告_预计2026年中国分布式传感器市场规模有多大-程序员宅基地

文章浏览阅读3.2k次。本文研究全球与中国市场分布式光纤传感器的发展现状及未来发展趋势,分别从生产和消费的角度分析分布式光纤传感器的主要生产地区、主要消费地区以及主要的生产商。重点分析全球与中国市场的主要厂商产品特点、产品规格、不同规格产品的价格、产量、产值及全球和中国市场主要生产商的市场份额。主要生产商包括:FISO TechnologiesBrugg KabelSensor HighwayOmnisensAFL GlobalQinetiQ GroupLockheed MartinOSENSA Innovati_预计2026年中国分布式传感器市场规模有多大

07_08 常用组合逻辑电路结构——为IC设计的延时估计铺垫_基4布斯算法代码-程序员宅基地

文章浏览阅读1.1k次,点赞2次,收藏12次。常用组合逻辑电路结构——为IC设计的延时估计铺垫学习目的:估计模块间的delay,确保写的代码的timing 综合能给到多少HZ,以满足需求!_基4布斯算法代码

OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏5次。OpenAI Manager助手(基于SpringBoot和Vue)_chatgpt网页版

关于美国计算机奥赛USACO,你想知道的都在这_usaco可以多次提交吗-程序员宅基地

文章浏览阅读2.2k次。USACO自1992年举办,到目前为止已经举办了27届,目的是为了帮助美国信息学国家队选拔IOI的队员,目前逐渐发展为全球热门的线上赛事,成为美国大学申请条件下,含金量相当高的官方竞赛。USACO的比赛成绩可以助力计算机专业留学,越来越多的学生进入了康奈尔,麻省理工,普林斯顿,哈佛和耶鲁等大学,这些同学的共同点是他们都参加了美国计算机科学竞赛(USACO),并且取得过非常好的成绩。适合参赛人群USACO适合国内在读学生有意向申请美国大学的或者想锻炼自己编程能力的同学,高三学生也可以参加12月的第_usaco可以多次提交吗

MySQL存储过程和自定义函数_mysql自定义函数和存储过程-程序员宅基地

文章浏览阅读394次。1.1 存储程序1.2 创建存储过程1.3 创建自定义函数1.3.1 示例1.4 自定义函数和存储过程的区别1.5 变量的使用1.6 定义条件和处理程序1.6.1 定义条件1.6.1.1 示例1.6.2 定义处理程序1.6.2.1 示例1.7 光标的使用1.7.1 声明光标1.7.2 打开光标1.7.3 使用光标1.7.4 关闭光标1.8 流程控制的使用1.8.1 IF语句1.8.2 CASE语句1.8.3 LOOP语句1.8.4 LEAVE语句1.8.5 ITERATE语句1.8.6 REPEAT语句。_mysql自定义函数和存储过程

半导体基础知识与PN结_本征半导体电流为0-程序员宅基地

文章浏览阅读188次。半导体二极管——集成电路最小组成单元。_本征半导体电流为0

随便推点

【Unity3d Shader】水面和岩浆效果_unity 岩浆shader-程序员宅基地

文章浏览阅读2.8k次,点赞3次,收藏18次。游戏水面特效实现方式太多。咱们这边介绍的是一最简单的UV动画(无顶点位移),整个mesh由4个顶点构成。实现了水面效果(左图),不动代码稍微修改下参数和贴图可以实现岩浆效果(右图)。有要思路是1,uv按时间去做正弦波移动2,在1的基础上加个凹凸图混合uv3,在1、2的基础上加个水流方向4,加上对雾效的支持,如没必要请自行删除雾效代码(把包含fog的几行代码删除)S..._unity 岩浆shader

广义线性模型——Logistic回归模型(1)_广义线性回归模型-程序员宅基地

文章浏览阅读5k次。广义线性模型是线性模型的扩展,它通过连接函数建立响应变量的数学期望值与线性组合的预测变量之间的关系。广义线性模型拟合的形式为:其中g(μY)是条件均值的函数(称为连接函数)。另外,你可放松Y为正态分布的假设,改为Y 服从指数分布族中的一种分布即可。设定好连接函数和概率分布后,便可以通过最大似然估计的多次迭代推导出各参数值。在大部分情况下,线性模型就可以通过一系列连续型或类别型预测变量来预测正态分布的响应变量的工作。但是,有时候我们要进行非正态因变量的分析,例如:(1)类别型.._广义线性回归模型

HTML+CSS大作业 环境网页设计与实现(垃圾分类) web前端开发技术 web课程设计 网页规划与设计_垃圾分类网页设计目标怎么写-程序员宅基地

文章浏览阅读69次。环境保护、 保护地球、 校园环保、垃圾分类、绿色家园、等网站的设计与制作。 总结了一些学生网页制作的经验:一般的网页需要融入以下知识点:div+css布局、浮动、定位、高级css、表格、表单及验证、js轮播图、音频 视频 Flash的应用、ul li、下拉导航栏、鼠标划过效果等知识点,网页的风格主题也很全面:如爱好、风景、校园、美食、动漫、游戏、咖啡、音乐、家乡、电影、名人、商城以及个人主页等主题,学生、新手可参考下方页面的布局和设计和HTML源码(有用点赞△) 一套A+的网_垃圾分类网页设计目标怎么写

C# .Net 发布后,把dll全部放在一个文件夹中,让软件目录更整洁_.net dll 全局目录-程序员宅基地

文章浏览阅读614次,点赞7次,收藏11次。之前找到一个修改 exe 中 DLL地址 的方法, 不太好使,虽然能正确启动, 但无法改变 exe 的工作目录,这就影响了.Net 中很多获取 exe 执行目录来拼接的地址 ( 相对路径 ),比如 wwwroot 和 代码中相对目录还有一些复制到目录的普通文件 等等,它们的地址都会指向原来 exe 的目录, 而不是自定义的 “lib” 目录,根本原因就是没有修改 exe 的工作目录这次来搞一个启动程序,把 .net 的所有东西都放在一个文件夹,在文件夹同级的目录制作一个 exe._.net dll 全局目录

BRIEF特征点描述算法_breif description calculation 特征点-程序员宅基地

文章浏览阅读1.5k次。本文为转载,原博客地址:http://blog.csdn.net/hujingshuang/article/details/46910259简介 BRIEF是2010年的一篇名为《BRIEF:Binary Robust Independent Elementary Features》的文章中提出,BRIEF是对已检测到的特征点进行描述,它是一种二进制编码的描述子,摈弃了利用区域灰度..._breif description calculation 特征点

房屋租赁管理系统的设计和实现,SpringBoot计算机毕业设计论文_基于spring boot的房屋租赁系统论文-程序员宅基地

文章浏览阅读4.1k次,点赞21次,收藏79次。本文是《基于SpringBoot的房屋租赁管理系统》的配套原创说明文档,可以给应届毕业生提供格式撰写参考,也可以给开发类似系统的朋友们提供功能业务设计思路。_基于spring boot的房屋租赁系统论文