You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ubuntu 24.04交叉编译Linux内核每次全量重编译问题排查

Ubuntu 24.04交叉编译Linux内核时全量重编译的原因分析

问题背景

在Ubuntu 20.04和Ubuntu 24.04上使用同一代码仓库交叉编译ARM64 Linux内核,执行命令:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules -j4

两个系统均使用amd64 gcc 9.5及同一交叉编译工具链,但Ubuntu 24.04每次执行编译都会全量重编译所有内容,而Ubuntu 20.04保持正常增量编译,且所有文件时间戳未发生变化,仅系统版本不同。

Ubuntu 24.04编译输出片段:

make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image modules -j4
  CHK     include/config/kernel.release
  CHK     include/generated/uapi/linux/version.h
  CC      scripts/mod/empty.o
  CC      scripts/mod/devicetable-offsets.s
  MKELF   scripts/mod/elfconfig.h
  HOSTCC  scripts/mod/modpost.o
  HOSTCC  scripts/mod/sumversion.o
  GEN     scripts/mod/devicetable-offsets.h
  HOSTCC  scripts/mod/file2alias.o

  CHK     include/generated/utsrelease.h
  CHK     include/generated/timeconst.h
  CC      kernel/bounds.s
  CHK     include/generated/bounds.h
  CC      arch/arm64/kernel/asm-offsets.s
  CHK     include/generated/asm-offsets.h
  CALL    scripts/checksyscalls.sh
  HOSTLD  scripts/mod/modpost
  CC      init/main.o
  ....

排查细节

使用-j1和V=1参数对比两个系统的编译输出,发现Ubuntu 24.04存在以下关键差异:

  1. 编译初期多执行了一系列临时文件生成与清理步骤:
set -e; : '  CHK     include/config/kernel.release'; mkdir -p include/config/;  echo "4.4.71$(/bin/bash ./scripts/setlocalversion .)" < include/config/auto.conf > include/config/kernel.release.tmp; if [ -r include/config/kernel.release ] && cmp -s include/config/kernel.release include/config/kernel.release.tmp; then rm -f include/config/kernel.release.tmp; else : '  UPD     include/config/kernel.release'; mv -f include/config/kernel.release.tmp include/config/kernel.release; fi
make -f ./scripts/Makefile.asm-generic \
            src=asm obj=arch/arm64/include/generated/asm
make -f ./scripts/Makefile.asm-generic \
            src=uapi/asm obj=arch/arm64/include/generated/uapi/asm
set -e; : '  CHK     include/generated/uapi/linux/version.h'; mkdir -p include/generated/uapi/linux/;   (echo \#define LINUX_VERSION_CODE 263239; echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))';) < Makefile > include/generated/uapi/linux/version.h.tmp; if [ -r include/generated/uapi/linux/version.h ] && cmp -s include/generated/uapi/linux/version.h include/generated/uapi/linux/version.h.tmp; then rm -f include/generated/uapi/linux/version.h.tmp; else : '  UPD     include/generated/uapi/linux/version.h'; mv -f include/generated/uapi/linux/version.h.tmp include/generated/uapi/linux/version.h; fi
rm -f include/linux/version.h
set -e; : '  CHK     include/generated/utsrelease.h'; mkdir -p include/generated/;  if [ `echo -n "4.4.71-00005-g2fc62ed91813-dirty" | wc -c ` -gt 64 ]; then echo '"4.4.71-00005-g2fc62ed91813-dirty" exceeds 64 characters' >&2; exit 1; fi; (echo \#define UTS_RELEASE \"4.4.71-00005-g2fc62ed91813-dirty\";) < include/config/kernel.release > include/generated/utsrelease.h.tmp; if [ -r include/generated/utsrelease.h ] && cmp -s include/generated/utsrelease.h include/generated/utsrelease.h.tmp; then rm -f include/generated/utsrelease.h.tmp; else : '  UPD     include/generated/utsrelease.h'; mv -f include/generated/utsrelease.h.tmp include/generated/utsrelease.h; fi
mkdir -p .tmp_versions ; rm -f .tmp_versions/*
make -f ./scripts/Makefile.build obj=scripts/basic
(cat /dev/null; ) > scripts/basic/modules.order
rm -f .tmp_quiet_recordmcount
make -f ./scripts/Makefile.build obj=.
(cat /dev/null; ) > modules.order
mkdir -p kernel/
  1. 仅Ubuntu 24.04会强制重新编译kernel/bounds.s:
aarch64-linux-gnu-gcc -Wp,-MD,kernel/.bounds.s.d -nostdinc -isystem /home/gregoire/tmp-inout/gcc-linaro-5.3.1-2016.05-x86_64_aarch64-linux-gnu/bin/../lib/gcc/aarch64-linux-gnu/5.3.1/include -I./arch/arm64/include -Iarch/arm64/include/generated/uapi -Iarch/arm64/include/generated  -Iinclude -I./arch/arm64/include/uapi -Iarch/arm64/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi -include ./include/linux/kconfig.h -D__KERNEL__ -mlittle-endian -Wall -Wundef -Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common -Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -fno-PIE -mgeneral-regs-only -DCONFIG_AS_LSE=1 -mpc-relative-literal-loads -fno-delete-null-pointer-checks -Wno-maybe-uninitialized -Os --param=allow-store-data-races=0 -Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-but-set-variable -fno-omit-frame-pointer -fno-optimize-sibling-calls -fno-var-tracking-assignments -g -pg -Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow -fconserve-stack -Werror=implicit-int -Werror=strict-prototypes -Werror=date-time -DCC_HAVE_ASM_GOTO    -D"KBUILD_STR(s)=#s" -D"KBUILD_BASENAME=KBUILD_STR(bounds)"  -D"KBUILD_MODNAME=KBUILD_STR(bounds)"  -fverbose-asm -S -o kernel/bounds.s kernel/bounds.c

相关文件与文件系统信息

Ubuntu 24.04下kernel/bounds.c和kernel/bounds.s的属性:

Ubuntu 24.04:
  File: kernel/bounds.c
  Size: 703         Blocks: 8          IO Block: 4096   regular file
Device: 259,2   Inode: 14559530    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/gregoire)   Gid: ( 1000/gregoire)
Access: 2024-05-14 10:05:28.629197631 -0700
Modify: 2017-09-23 09:19:33.558726253 -0700
Change: 2024-05-07 15:44:11.170012538 -0700
 Birth: 2024-04-26 08:54:22.911042385 -0700
 
  File: kernel/bounds.s
  Size: 14617       Blocks: 32         IO Block: 4096   regular file
Device: 259,2   Inode: 14559336    Links: 1
Access: (0664/-rw-rw-r--)  Uid: ( 1000/gregoire)   Gid: ( 1000/gregoire)
Access: 2024-05-14 10:26:03.478134345 -0700
Modify: 2024-05-14 10:26:03.467134218 -0700
Change: 2024-05-14 10:26:03.467134218 -0700
 Birth: 2024-05-04 21:27:59.503527455 -0700

文件系统配置:

Ubuntu 24.04:
/dev/nvme0n1p2 on / type ext4 (rw,relatime,stripe=32)
Ubuntu 20.04:
/dev/sda5 on / type ext4 (rw,relatime,errors=remount-ro)

原因分析

1. bounds.s重编译触发全局依赖连锁反应

kernel/bounds.s是生成include/generated/bounds.h的直接依赖,而bounds.h是内核全局头文件,几乎所有内核代码都会包含它。Ubuntu 24.04中每次编译都会重新生成bounds.s,哪怕内容无变化,仅修改时间戳,都会导致Make认为bounds.h需要更新,进而触发所有依赖bounds.h的目标文件重编译,最终引发全量编译。

2. Make工具与文件系统的时间戳逻辑差异

  • Make版本差异:Ubuntu 24.04默认使用GNU Make 4.3.90,而Ubuntu 20.04使用Make 4.2.1。新版本Make对文件时间戳的对比逻辑更严格,尤其是支持纳秒级精度的时间戳校验,而旧版本生成的bounds.s时间戳精度较低,导致新版本Make误判bounds.c的修改时间晚于bounds.s,触发重编译。
  • 文件系统配置差异:Ubuntu 24.04的ext4启用了stripe=32参数,可能影响文件时间戳的更新行为;同时NVMe盘的ext4默认支持更高精度的时间戳,与Ubuntu 20.04使用的SATA盘ext4时间精度不匹配,加剧了时间戳对比的误判。

3. Shell版本导致的临时文件处理差异

Ubuntu 24.04使用bash 5.2.21,而Ubuntu 20.04使用bash 5.0.17。不同版本Shell在处理临时文件生成、移动时,可能导致文件的修改时间(mtime)被意外更新,间接触发后续依赖链的重编译逻辑。

解决方案建议

  1. 强制使用秒级时间戳对比:编译前执行export POSIXLY_CORRECT=1,让Make忽略纳秒级时间戳差异,避免误判文件更新。
  2. 修改内核Makefile规则:针对kernel/bounds.s的生成规则,添加内容校验逻辑,仅当文件内容实际变化时才更新文件,而非仅依赖时间戳。
  3. 统一文件系统挂载参数:将Ubuntu 24.04的ext4挂载参数调整为与20.04一致(移除stripe=32),测试是否解决时间戳相关问题。
  4. 降级Make版本:在Ubuntu 24.04中安装Make 4.2.1,匹配Ubuntu 20.04的环境配置。

内容的提问来源于stack exchange,提问作者gregoiregentil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 05:40:55