RitchieSolo

OMX-Kernel-Build-Script-2.9.3.sh

Oct 5th, 2026 (edited)
56
0
Never
3
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 43.37 KB | Source Code | 0 0
  1. #!/usr/bin/env bash
  2. # omx-kernel v2.9.3
  3. # GNU GPL. NO WARRANTY.
  4. #
  5. # Default: classic XanMod + OM donor .config
  6. # Clang + ld.lld (ICF-safe) + ThinLTO + 250 Hz + native CPU tuning by default
  7. # 2.9 adds selectable LLVM toolchain and distributable x86-64-v3 mode.
  8. # Work tree under /tmp; RPMs under ~/rpmbuild
  9. #
  10. set -Eeuo pipefail
  11.  
  12. readonly PROGNAME="omx-kernel"
  13. readonly VERSION="2.9.3"
  14. readonly WORKDIR="${TMPDIR:-/tmp}/${PROGNAME}-work-${USER:-user}"
  15. readonly LOG_DIR="${WORKDIR}/logs"
  16. readonly DISK_MIN_GIB=30
  17. readonly RPM_NAME="kernel-xanmod-desktop"
  18. readonly RPM_TOPDIR="${HOME}/rpmbuild"
  19. readonly XANMOD_GIT_GITLAB="https://gitlab.com/xanmod/linux.git"
  20. readonly XANMOD_GIT_GITHUB="https://github.com/xanmod/linux.git"
  21.  
  22. XANMOD_GIT="${XANMOD_GIT_GITLAB}"
  23. XANMOD_MAJOR=""
  24. JOBS=2
  25. THINLTO=1
  26. FORCE_FETCH=0
  27. DO_RESUME=0
  28. USE_BFD=0
  29. PLAIN_LLD=0 # default: ld.lld wrapper that pins --no-gc-sections --icf=none (OM lld GCs by default)
  30. X86_LEVEL=""
  31. NO_WRAPPERS=0
  32. CCBIN="${HOME}/bin/clang-omx"
  33. CXXBIN="${HOME}/bin/clang++-omx"
  34. LLVM_ROOT="${LLVM_ROOT:-}"
  35. LLVM_WHY=""
  36. RUN_RPMLINT=0
  37. SUDO_KEEPALIVE_PID=""
  38. LLVM_BIN=""
  39. LLVM_CLANG=""
  40. LLVM_CLANGXX=""
  41. LLVM_LLD=""
  42. XANMOD_CFG=""
  43. WANT_NATIVE=0
  44. AUTOFDO=0
  45. AFDO_PROFILE=""
  46. PROPELLER=0
  47. PROPELLER_PREFIX=""
  48. AFDO_FORCE=0
  49. DRY_RUN=0
  50. NO_INSTALL=0
  51. TREE_MODE=""
  52. ASSUME_YES=0
  53. FORCE_TAG=""
  54. USER_SRPM=""
  55. KEEP_TDA18212=0
  56. NO_NATIVE=0
  57. NO_BOOT_HACKS=1 # the GNU-nm swap is opt-in (--boot-hacks): it flips HAS_LTO_CLANG and rebuilds everything
  58. LINKER=ld.lld
  59. KERNEL_VER=""
  60. KERNEL_VER_RPM=""
  61. SAFE_TAG=""
  62. TAG=""
  63. GNUTAR=""
  64.  
  65. export OMX_KCFLAGS="-march=native -Wno-unknown-warning-option"
  66. export OMX_KCPPFLAGS="-DCONFIG_X86_L1_CACHE_SHIFT=6"
  67.  
  68. readonly C_RESET=$'\033[0m' C_BOLD=$'\033[1m'
  69. readonly C_RED=$'\033[31m' C_GREEN=$'\033[32m' C_YELLOW=$'\033[33m' C_CYAN=$'\033[36m'
  70.  
  71. declare -A OM_PKG_MAP=(
  72. [elfutils-libelf-devel]=lib64elfutils-devel
  73. [openssl-devel]=lib64openssl-devel
  74. [dwarves]=lib64dwarves
  75. [ncurses-devel]=lib64ncurses-devel
  76. )
  77.  
  78. readonly PKGLIST=(
  79. git make binutils clang lld llvm flex bison bc perl rsync
  80. elfutils-libelf-devel openssl-devel dwarves ncurses-devel
  81. rpm-build rpmdevtools tar zstd gnutar dracut cryptsetup xz cpio
  82. )
  83.  
  84. log() {
  85. local level="$1" msg="$2" color
  86. case "$level" in
  87. INFO) color="${C_CYAN}" ;;
  88. WARN) color="${C_YELLOW}" ;;
  89. ERROR) color="${C_RED}" ;;
  90. OK) color="${C_GREEN}" ;;
  91. *) color="${C_RESET}" ;;
  92. esac
  93. printf '%s %b%-5s%b %s\n' "$(date +%H:%M:%S)" "$color" "$level" "$C_RESET" "$msg" >&2
  94. }
  95. info() { log INFO "$1"; }
  96. warn() { log WARN "$1"; }
  97. err() { log ERROR "$1"; }
  98. ok() { log OK "$1"; }
  99. die() { err "$1"; exit 1; }
  100.  
  101. ask() {
  102. local q="$1" def="${2:-n}" a
  103. if (( ASSUME_YES )) || [[ ! -t 0 ]]; then
  104. printf '%s' "$def"
  105. return 0
  106. fi
  107. printf '%b%s%b ' "$C_BOLD" "$q" "$C_RESET" >&2
  108. read -r -t 300 a || a="$def"
  109. printf '%s' "${a:-$def}"
  110. }
  111.  
  112. help_menu() {
  113. cat <<EOF
  114. ${PROGNAME} v${VERSION}
  115.  
  116. Default: classic XanMod (GitLab) + OpenMandriva /boot config as module donor.
  117. Work directory: ${WORKDIR}
  118. RPMs: ${RPM_TOPDIR}/RPMS
  119.  
  120. Modes:
  121. --xanmod-7 | --xanmod | --classic Classic XanMod (default)
  122. --hybrid | --srpm FILE OM kernel SRPM base (optional)
  123. --tag TAG Explicit XanMod tag
  124.  
  125. Toolchain:
  126. --use-bfd ld.bfd instead of ld.lld
  127. --xanmod-config V Base on XanMod's own CONFIGS/xanmod/gcc/config_x86-64-V (V = v1..v4)
  128. instead of the OM donor config. Only LTO, native, localversion and
  129. IKHEADERS are stamped; HZ/preempt/NO_HZ etc. stay as XanMod ships them.
  130. Native is OFF in this mode unless --native is also given.
  131. --v3 | --x86-level N Stamp CONFIG_X86_64_VERSION=N (XanMod CPU level, 1-4) on top of any base config
  132. --x86-64-v3 Distributable x86-64-v3 build (level 3 + no -march=native)
  133. --llvm-root DIR Use the LLVM/Clang toolchain in DIR/bin (default: /opt/llvm-propeller-23 for --propeller
  134. builds if present, otherwise the system LLVM toolchain)
  135. --plain-lld Raw selected LLVM ld.lld, no wrapper. DIAGNOSTIC ONLY: OM lld garbage-collects by
  136. default and the resulting kernel crashes in setup_arch
  137. --lld-wrapper (default) ld.lld wrapper pinning --no-gc-sections --icf=none
  138. --no-wrappers Use the selected LLVM clang/clang++ directly (the ld.lld wrapper stays)
  139. Profile-guided pipeline (kernel docs: build-afdo, train-afdo, build-propeller, train-propeller,
  140. build-optimized). Every stage must use the SAME other flags; the script records and checks them.
  141. stage 1 --autofdo boot it, then: omx-afdo-profile.sh record ...
  142. stage 2 --afdo-profile F.afdo [--propeller] (plain AutoFDO build, or the Propeller "labels" build)
  143. stage 3 --afdo-profile F.afdo --propeller-profile PREFIX final build (AutoFDO + Propeller)
  144. --autofdo CONFIG_AUTOFDO_CLANG=y, no profile. vmlinux saved to ~/rpmbuild/AFDO/. Clang >= 19.
  145. --afdo-profile FILE CLANG_AUTOFDO_PROFILE=FILE (implies --autofdo)
  146. --propeller CONFIG_PROPELLER_CLANG=y (implies --autofdo; needs --afdo-profile and ld.lld >= 19).
  147. Builds the labeled kernel you profile with: omx-afdo-profile.sh record-propeller
  148. --propeller-profile PREFIX
  149. CLANG_PROPELLER_PROFILE_PREFIX=PREFIX (needs PREFIX_cc_profile.txt and
  150. PREFIX_ld_profile.txt; implies --propeller). Use the same --afdo-profile as stage 2.
  151. --afdo-force Continue even if the recorded flags of the previous stage differ
  152. --native With --xanmod-config: also enable CONFIG_X86_NATIVE_CPU
  153. NOTE: -march=native / X86_NATIVE_CPU tune for the machine you BUILD on; the kernel
  154. may not boot on other CPUs.
  155. --force-thinlto ThinLTO on (default)
  156. --no-thinlto ThinLTO off
  157. --jobs N Parallelism (default 2)
  158. --no-native Drop -march=native and CONFIG_X86_NATIVE_CPU
  159. --rpmlint Run rpmlint on the new RPMs AFTER installing (slow: ~5 min; full output goes to a log file)
  160. --boot-hacks Re-enable the old GNU-nm swap for bzImage (NOT with ThinLTO: it silently drops LTO and rebuilds)
  161. --no-boot-hacks (default) llvm-nm everywhere; kept for old command lines
  162. (implies --force-fetch so the tree is re-cloned unpatched)
  163. --bisect --no-thinlto --no-native --no-boot-hacks (boot-debug build)
  164.  
  165. Other:
  166. --force-fetch | --resume | --cleanup | --dry-run | --no-install | -y
  167.  
  168. Examples:
  169. $0 --xanmod-7 --force-thinlto -y
  170. $0 --xanmod-7 --tag 7.1.13 --afdo-profile ~/afdo/xanmod-7.1.13-autofdo-heavy-1h.afdo --propeller --force-thinlto -y
  171. $0 --xanmod-7 --tag 7.1.13 --x86-64-v3 --afdo-profile PROFILE.afdo --propeller-profile PREFIX --force-thinlto -y
  172. EOF
  173. }
  174.  
  175. select_llvm_toolchain() {
  176. local prop="${PROPELLER_LLVM_ROOT:-/opt/llvm-propeller-23}"
  177. LLVM_WHY="--llvm-root"
  178. if [[ -z "$LLVM_ROOT" ]]; then
  179. # Propeller builds use the matching toolchain of the Propeller tools; everything else keeps
  180. # the system LLVM that has actually been boot-tested.
  181. if (( PROPELLER )) && [[ -x "${prop}/bin/clang" && -x "${prop}/bin/ld.lld" ]]; then
  182. LLVM_ROOT="$prop"; LLVM_WHY="Propeller build"
  183. else
  184. LLVM_ROOT=/usr; LLVM_WHY="system default"
  185. fi
  186. fi
  187. LLVM_BIN="${LLVM_ROOT}/bin"
  188. LLVM_CLANG="${LLVM_BIN}/clang"
  189. LLVM_CLANGXX="${LLVM_BIN}/clang++"
  190. LLVM_LLD="${LLVM_BIN}/ld.lld"
  191. [[ -x "$LLVM_CLANG" ]] || die "Clang not found: ${LLVM_CLANG}"
  192. [[ -x "$LLVM_CLANGXX" ]] || die "clang++ not found: ${LLVM_CLANGXX}"
  193. [[ -x "$LLVM_LLD" ]] || die "ld.lld not found: ${LLVM_LLD}"
  194. export PATH="${LLVM_BIN}:${HOME}/bin:${PATH}"
  195. }
  196.  
  197. install_wrappers_all() {
  198. mkdir -p "${HOME}/bin"
  199. export OMX_LLVM_CLANG="$LLVM_CLANG"
  200. export OMX_LLVM_CLANGXX="$LLVM_CLANGXX"
  201. export OMX_LLVM_LLD="$LLVM_LLD"
  202. # Strip Polly / bad -mllvm
  203. cat > "${HOME}/bin/clang-omx" <<'WRAP'
  204. #!/usr/bin/env bash
  205. args=(); prev=""
  206. for a in "$@"; do
  207. if [[ "$prev" == "-mllvm" ]]; then
  208. prev=""
  209. case "$a" in *polly*|*pipeliner*) continue ;; *) args+=("-mllvm" "$a"); continue ;; esac
  210. fi
  211. case "$a" in
  212. -mllvm) prev="-mllvm" ;;
  213. -mllvm=*polly*|-mllvm=*pipeliner*) ;;
  214. *) args+=("$a") ;;
  215. esac
  216. done
  217. [[ -n "$prev" ]] && args+=("$prev")
  218. exec "${OMX_LLVM_CLANG}" "${args[@]}"
  219. WRAP
  220. cat > "${HOME}/bin/clang++-omx" <<'WRAP'
  221. #!/usr/bin/env bash
  222. args=(); prev=""
  223. for a in "$@"; do
  224. if [[ "$prev" == "-mllvm" ]]; then
  225. prev=""
  226. case "$a" in *polly*|*pipeliner*) continue ;; *) args+=("-mllvm" "$a"); continue ;; esac
  227. fi
  228. case "$a" in
  229. -mllvm) prev="-mllvm" ;;
  230. -mllvm=*polly*|-mllvm=*pipeliner*) ;;
  231. *) args+=("$a") ;;
  232. esac
  233. done
  234. [[ -n "$prev" ]] && args+=("$prev")
  235. exec "${OMX_LLVM_CLANGXX}" "${args[@]}"
  236. WRAP
  237. # ld.lld: OpenMandriva's lld 19.1.7 defaults to --gc-sections (and --icf=safe), unlike
  238. # upstream. Under --gc-sections it discards .bss..brk, the x86 CPU-vendor table and
  239. # kernel_info, and the kernel dies in setup_arch (BUG in extend_brk). Pin the safe defaults.
  240. cat > "${HOME}/bin/ld.lld" <<'WRAP'
  241. #!/usr/bin/env bash
  242. args=()
  243. for a in "$@"; do
  244. case "$a" in --icf|--icf=*|--gc-sections|--no-gc-sections) continue ;; esac
  245. args+=("$a")
  246. done
  247. exec "${OMX_LLVM_LLD}" "${args[@]}" --icf=none --no-gc-sections
  248. WRAP
  249. sed -i "s|\${OMX_LLVM_CLANG}|${LLVM_CLANG}|" "${HOME}/bin/clang-omx"
  250. sed -i "s|\${OMX_LLVM_CLANGXX}|${LLVM_CLANGXX}|" "${HOME}/bin/clang++-omx"
  251. sed -i "s|\${OMX_LLVM_LLD}|${LLVM_LLD}|" "${HOME}/bin/ld.lld"
  252. chmod 0755 "${HOME}/bin/clang-omx" "${HOME}/bin/clang++-omx" "${HOME}/bin/ld.lld"
  253. export PATH="${HOME}/bin:${PATH}"
  254. }
  255.  
  256. install_wrappers() {
  257. install_wrappers_all
  258. if (( NO_WRAPPERS )); then
  259. rm -f "${HOME}/bin/clang-omx" "${HOME}/bin/clang++-omx"
  260. fi
  261. if (( PLAIN_LLD )); then
  262. rm -f "${HOME}/bin/ld.lld"
  263. fi
  264. }
  265.  
  266. setup_compiler() {
  267. select_llvm_toolchain
  268. install_wrappers
  269. if (( USE_BFD )); then
  270. LINKER=ld.bfd
  271. command -v ld.bfd >/dev/null || die "ld.bfd missing"
  272. warn "Using ld.bfd"
  273. elif (( PLAIN_LLD )); then
  274. LINKER="$LLVM_LLD"
  275. [[ -x "$LINKER" ]] || die "ld.lld missing: $LINKER"
  276. warn "Using plain ${LINKER} (no wrapper)"
  277. else
  278. LINKER="${HOME}/bin/ld.lld"
  279. fi
  280. if (( NO_WRAPPERS )); then
  281. CCBIN="$LLVM_CLANG"
  282. CXXBIN="$LLVM_CLANGXX"
  283. fi
  284. [[ -x "$CCBIN" ]] || die "Clang compiler missing: $CCBIN"
  285. [[ -x "$CXXBIN" ]] || die "C++ compiler missing: $CXXBIN"
  286. info "LLVM root: ${LLVM_ROOT} (${LLVM_WHY})"
  287. info "LLVM toolchain: $("${LLVM_CLANG}" --version | head -n1)"
  288. info "LLD toolchain: $("${LLVM_LLD}" --version | head -n1)"
  289. }
  290.  
  291. make_k_args() {
  292. MAKE_K=(
  293. ARCH=x86_64 SRCARCH=x86
  294. LLVM=1 LLVM_IAS=1
  295. CC="${CCBIN}"
  296. LD="${LINKER}"
  297. AR=llvm-ar NM=llvm-nm STRIP=llvm-strip
  298. OBJCOPY=llvm-objcopy OBJDUMP=llvm-objdump READELF=llvm-readelf
  299. HOSTCC="${CCBIN}"
  300. HOSTCXX="${CXXBIN}"
  301. HOSTAR=llvm-ar HOSTLD="${LINKER}"
  302. "KCFLAGS=${OMX_KCFLAGS}"
  303. "KCPPFLAGS=${OMX_KCPPFLAGS}"
  304. ${AFDO_PROFILE:+"CLANG_AUTOFDO_PROFILE=${AFDO_PROFILE}"}
  305. ${PROPELLER_PREFIX:+"CLANG_PROPELLER_PROFILE_PREFIX=${PROPELLER_PREFIX}"}
  306. )
  307. }
  308.  
  309. km() {
  310. env -u CC -u CXX -u CFLAGS -u CXXFLAGS -u LDFLAGS -u MAKEFLAGS \
  311. make -j"${JOBS}" "${MAKE_K[@]}" "$@"
  312. }
  313.  
  314. km_ni() {
  315. local rc
  316. set +o pipefail
  317. yes '' 2>/dev/null | km "$@" >/dev/null
  318. rc=${PIPESTATUS[1]}
  319. set -o pipefail
  320. return "$rc"
  321. }
  322.  
  323. preflight() {
  324. local disk_gib
  325. disk_gib="$(df -BG --output=avail "${TMPDIR:-/tmp}" 2>/dev/null | tail -1 | tr -dc '0-9')"
  326. [[ -n "$disk_gib" ]] || disk_gib="$(df -BG --output=avail "${HOME}" | tail -1 | tr -dc '0-9')"
  327. (( disk_gib >= DISK_MIN_GIB )) || die "Need >= ${DISK_MIN_GIB} GiB free (prefer /tmp)"
  328. command -v /usr/bin/nm >/dev/null || die "GNU nm required at /usr/bin/nm"
  329. setup_compiler
  330. make_k_args
  331. info "jobs=${JOBS} ThinLTO=${THINLTO} LD=${LINKER} work=${WORKDIR}"
  332. }
  333.  
  334. check_deps() {
  335. local missing=() pkg resolved=()
  336. for pkg in "${PKGLIST[@]}"; do
  337. rpm -q "$pkg" &>/dev/null || missing+=("$pkg")
  338. done
  339. ((${#missing[@]} == 0)) && return 0
  340. for pkg in "${missing[@]}"; do
  341. resolved+=("${OM_PKG_MAP[$pkg]:-$pkg}")
  342. done
  343. sudo dnf install -y "${resolved[@]}" || die "deps failed"
  344. }
  345.  
  346. ensure_gnutar() {
  347. if command -v gtar >/dev/null; then GNUTAR=$(command -v gtar)
  348. elif command -v gnutar >/dev/null; then GNUTAR=$(command -v gnutar)
  349. else GNUTAR=$(command -v tar)
  350. fi
  351. [[ -n "$GNUTAR" ]] || die "tar missing"
  352. }
  353.  
  354. do_cleanup() {
  355. info "Removing ${WORKDIR} and related rpmbuild kernel trees..."
  356. rm -rf "${WORKDIR}"
  357. rm -rf "${RPM_TOPDIR}/BUILD/"*kernel* "${RPM_TOPDIR}/BUILDROOT/"* 2>/dev/null || true
  358. rm -f "${RPM_TOPDIR}/SPECS/${PROGNAME}.spec" \
  359. "${RPM_TOPDIR}/SOURCES/${RPM_NAME}-"*.tar \
  360. "${RPM_TOPDIR}/SOURCES/config-"* 2>/dev/null || true
  361. ok "Cleaned (next build will re-clone)"
  362. }
  363.  
  364. patch_compressed_makefile() {
  365. local tree="$1" mf="${1}/arch/x86/boot/compressed/Makefile"
  366. [[ -f "$mf" ]] || return 0
  367. # REQUIRED with ld.lld: --gc-sections drops kernel_info from compressed/vmlinux, so
  368. # bzImage fails with "undefined symbol: ZO_kernel_info". Keep it with -u, inserted
  369. # ABOVE the trailing "-T" line (next to the existing -u efi_pe_entry).
  370. sed -i '/^LDFLAGS_vmlinux += -u kernel_info[[:space:]]*$/d' "$mf"
  371. sed -i '/^LDFLAGS_vmlinux += --undefined=kernel_info/d' "$mf"
  372. sed -i '/^LDFLAGS_vmlinux += -T[[:space:]]*$/i LDFLAGS_vmlinux += -u kernel_info' "$mf"
  373. grep -q -- '-u kernel_info' "$mf" || die "kernel_info retention not applied (Makefile layout changed)"
  374. # OPTIONAL hack (disabled by --no-boot-hacks): GNU nm for the offsets
  375. (( NO_BOOT_HACKS )) && return 0
  376. sed -i 's|\$(NM)|/usr/bin/nm|g' "$mf"
  377. }
  378.  
  379. stamp_autofdo() {
  380. local f="$1"
  381. sed -i -e '/^CONFIG_AUTOFDO_CLANG=/d' -e '/^# CONFIG_AUTOFDO_CLANG /d' "$f"
  382. if (( AUTOFDO )); then echo 'CONFIG_AUTOFDO_CLANG=y' >> "$f"; fi
  383. }
  384.  
  385. stamp_propeller() {
  386. local f="$1"
  387. sed -i -e '/^CONFIG_PROPELLER_CLANG=/d' -e '/^# CONFIG_PROPELLER_CLANG /d' "$f"
  388. if (( PROPELLER )); then echo 'CONFIG_PROPELLER_CLANG=y' >> "$f"; fi
  389. }
  390.  
  391. stamp_minimal_config() {
  392. local f="${1}/.config"
  393. [[ -f "$f" ]] || die "No .config"
  394. sed -i \
  395. -e '/^CONFIG_LTO_/d' -e '/^# CONFIG_LTO_/d' \
  396. -e '/^CONFIG_LOCALVERSION_AUTO=/d' -e '/^# CONFIG_LOCALVERSION_AUTO /d' \
  397. -e '/^CONFIG_X86_NATIVE_CPU=/d' -e '/^# CONFIG_X86_NATIVE_CPU /d' \
  398. -e '/^CONFIG_IKHEADERS=/d' -e '/^# CONFIG_IKHEADERS /d' \
  399. -e '/^CONFIG_X86_64_VERSION=/d' \
  400. "$f"
  401. [[ -n "$X86_LEVEL" ]] && echo "CONFIG_X86_64_VERSION=${X86_LEVEL}" >> "$f"
  402. printf '%s\n' '# CONFIG_LOCALVERSION_AUTO is not set' '# CONFIG_IKHEADERS is not set' >> "$f"
  403. if (( NO_NATIVE )); then
  404. echo '# CONFIG_X86_NATIVE_CPU is not set' >> "$f"
  405. else
  406. echo 'CONFIG_X86_NATIVE_CPU=y' >> "$f"
  407. fi
  408. if (( THINLTO )); then
  409. printf '%s\n' '# CONFIG_LTO_NONE is not set' 'CONFIG_LTO_CLANG=y' 'CONFIG_LTO_CLANG_THIN=y' '# CONFIG_LTO_CLANG_FULL is not set' >> "$f"
  410. else
  411. echo 'CONFIG_LTO_NONE=y' >> "$f"
  412. fi
  413. }
  414.  
  415. stamp_critical_config() {
  416. local f="${1}/.config"
  417. [[ -f "$f" ]] || die "No .config"
  418. stamp_autofdo "$f"
  419. stamp_propeller "$f"
  420. if [[ -n "$XANMOD_CFG" ]]; then stamp_minimal_config "$1"; return 0; fi
  421. sed -i \
  422. -e '/^CONFIG_64BIT=/d' -e '/^CONFIG_X86_64=/d' -e '/^CONFIG_X86_32=/d' \
  423. -e '/^CONFIG_X86_L1_CACHE_SHIFT=/d' -e '/^CONFIG_SMP=/d' \
  424. -e '/^CONFIG_MODULES=/d' -e '/^CONFIG_MODVERSIONS=/d' \
  425. -e '/^CONFIG_GENKSYMS=/d' -e '/^CONFIG_GENDWARFKSYMS=/d' \
  426. -e '/^CONFIG_HZ=/d' -e '/^CONFIG_HZ_1000=/d' -e '/^CONFIG_HZ_250=/d' \
  427. -e '/^CONFIG_HZ_PERIODIC=/d' -e '/^CONFIG_NO_HZ=/d' \
  428. -e '/^CONFIG_NO_HZ_IDLE=/d' -e '/^CONFIG_NO_HZ_FULL=/d' \
  429. -e '/^CONFIG_LTO_/d' -e '/^# CONFIG_LTO_/d' \
  430. -e '/^CONFIG_LOCALVERSION_AUTO=/d' -e '/^CONFIG_PREEMPT_DYNAMIC=/d' \
  431. -e '/^CONFIG_X86_NATIVE_CPU=/d' -e '/^# CONFIG_X86_NATIVE_CPU /d' \
  432. -e '/^CONFIG_DEBUG_INFO=/d' -e '/^CONFIG_DEBUG_INFO_NONE=/d' \
  433. -e '/^CONFIG_DEBUG_INFO_DWARF/d' -e '/^CONFIG_DEBUG_INFO_COMPRESSED/d' \
  434. -e '/^CONFIG_DEBUG_INFO_BTF=/d' -e '/^CONFIG_DEBUG_INFO_BTF_MODULES=/d' \
  435. -e '/^CONFIG_MODULE_ALLOW_BTF_MISMATCH=/d' -e '/^CONFIG_GDB_SCRIPTS=/d' \
  436. -e '/^CONFIG_BUILTIN_MODULE_RANGES=/d' \
  437. -e '/^CONFIG_LD_DEAD_CODE_ELIMINATION=/d' \
  438. -e '/^CONFIG_EARLY_PRINTK/d' -e '/^# CONFIG_EARLY_PRINTK/d' \
  439. -e '/^CONFIG_IKHEADERS=/d' -e '/^# CONFIG_IKHEADERS /d' \
  440. -e '/^CONFIG_X86_64_VERSION=/d' \
  441. "$f"
  442. [[ -n "$X86_LEVEL" ]] && echo "CONFIG_X86_64_VERSION=${X86_LEVEL}" >> "$f"
  443. cat >> "$f" <<'EOF'
  444. CONFIG_64BIT=y
  445. CONFIG_X86_64=y
  446. # CONFIG_X86_32 is not set
  447. CONFIG_X86_L1_CACHE_SHIFT=6
  448. CONFIG_SMP=y
  449. CONFIG_MODULES=y
  450. CONFIG_MODVERSIONS=y
  451. CONFIG_GENKSYMS=y
  452. # CONFIG_GENDWARFKSYMS is not set
  453. CONFIG_HZ=250
  454. CONFIG_HZ_250=y
  455. # CONFIG_HZ_1000 is not set
  456. # CONFIG_HZ_PERIODIC is not set
  457. CONFIG_NO_HZ=y
  458. # CONFIG_NO_HZ_IDLE is not set
  459. CONFIG_NO_HZ_FULL=y
  460. CONFIG_PREEMPT_DYNAMIC=y
  461. # CONFIG_LOCALVERSION_AUTO is not set
  462. CONFIG_DEBUG_INFO=y
  463. CONFIG_DEBUG_INFO_DWARF5=y
  464. CONFIG_DEBUG_INFO_COMPRESSED_ZSTD=y
  465. CONFIG_DEBUG_INFO_BTF=y
  466. CONFIG_DEBUG_INFO_BTF_MODULES=y
  467. CONFIG_MODULE_ALLOW_BTF_MISMATCH=y
  468. CONFIG_GDB_SCRIPTS=y
  469. # CONFIG_BUILTIN_MODULE_RANGES is not set
  470. # CONFIG_LD_DEAD_CODE_ELIMINATION is not set
  471. CONFIG_EARLY_PRINTK=y
  472. CONFIG_EARLY_PRINTK_EFI=y
  473. # CONFIG_IKHEADERS is not set
  474. EOF
  475. if (( NO_NATIVE )); then
  476. echo '# CONFIG_X86_NATIVE_CPU is not set' >> "$f"
  477. else
  478. echo 'CONFIG_X86_NATIVE_CPU=y' >> "$f"
  479. fi
  480. if (( THINLTO )); then
  481. cat >> "$f" <<'EOF'
  482. # CONFIG_LTO_NONE is not set
  483. CONFIG_LTO_CLANG=y
  484. CONFIG_LTO_CLANG_THIN=y
  485. # CONFIG_LTO_CLANG_FULL is not set
  486. EOF
  487. else
  488. echo 'CONFIG_LTO_NONE=y' >> "$f"
  489. fi
  490. }
  491.  
  492. settle_config() {
  493. local tree="$1"
  494. stamp_critical_config "$tree"
  495. (cd "$tree" && km_ni olddefconfig) || die "olddefconfig failed"
  496. stamp_critical_config "$tree"
  497. (cd "$tree" && km_ni olddefconfig) || die "olddefconfig pass 2 failed"
  498. stamp_critical_config "$tree"
  499. [[ -n "$XANMOD_CFG" ]] || grep -q '^CONFIG_HZ=250$' "${tree}/.config" || die "HZ!=250"
  500. grep -q '^CONFIG_MODULES=y$' "${tree}/.config" || die "MODULES missing"
  501. grep -q '^CONFIG_X86_L1_CACHE_SHIFT=6$' "${tree}/.config" || \
  502. echo 'CONFIG_X86_L1_CACHE_SHIFT=6' >> "${tree}/.config"
  503. if (( THINLTO )); then
  504. grep -q '^CONFIG_LTO_CLANG_THIN=y$' "${tree}/.config" || die "ThinLTO missing"
  505. fi
  506. if (( NO_NATIVE )); then
  507. grep -q '^CONFIG_X86_NATIVE_CPU=y' "${tree}/.config" && die "NATIVE_CPU still on"
  508. fi
  509. if (( AUTOFDO )); then
  510. grep -q '^CONFIG_AUTOFDO_CLANG=y' "${tree}/.config" || die "CONFIG_AUTOFDO_CLANG did not stick (needs Clang >= 19 and a tree that has the option)"
  511. fi
  512. if (( PROPELLER )); then
  513. grep -q '^CONFIG_PROPELLER_CLANG=y' "${tree}/.config" || die "CONFIG_PROPELLER_CLANG did not stick (needs Clang/ld.lld >= 19, CONFIG_AUTOFDO_CLANG, and a tree that has the option)"
  514. fi
  515. info "Final config (boot-relevant):"
  516. grep -E '^(# )?CONFIG_(X86_NATIVE_CPU|LTO_CLANG_THIN|LTO_NONE|HZ|PREEMPT[A-Z_]*|NO_HZ[A-Z_]*|AUTOFDO_CLANG|PROPELLER_CLANG|EARLY_PRINTK|EFI_STUB|DRM_SIMPLEDRM|SYSFB_SIMPLEFB|DEBUG_INFO_BTF|RD_ZSTD|X86_64_VERSION)[ =]' \
  517. "${tree}/.config" >&2 || true
  518. }
  519.  
  520. find_build_tree() {
  521. find "${RPM_TOPDIR}/BUILD" -type d -name "${RPM_NAME}-*" 2>/dev/null | while read -r p; do
  522. [[ -f "${p}/Makefile" && -d "${p}/arch/x86" ]] && echo "$p"
  523. done | head -n1
  524. }
  525.  
  526. do_resume() {
  527. local tree
  528. setup_compiler; make_k_args
  529. tree="$(find_build_tree)"
  530. [[ -n "$tree" ]] || die "No BUILD tree for --resume"
  531. info "Resume: ${tree}"
  532. patch_compressed_makefile "$tree"
  533. (cd "$tree" && rm -f arch/x86/boot/bzImage arch/x86/boot/setup.elf \
  534. arch/x86/boot/zoffset.h arch/x86/boot/compressed/vmlinux 2>/dev/null
  535. km_ni bzImage) || die "resume bzImage failed"
  536. ok "bzImage ok"
  537. exit 0
  538. }
  539.  
  540. choose_tree_mode() {
  541. case "${TREE_MODE}" in hybrid|classic) return 0 ;; esac
  542. if (( ASSUME_YES )); then
  543. TREE_MODE=classic
  544. XANMOD_MAJOR="${XANMOD_MAJOR:-7}"
  545. return 0
  546. fi
  547. printf '\n%sClassic XanMod (default)%s — XanMod tree + OM /boot config donor\n' "$C_BOLD" "$C_RESET" >&2
  548. printf '%sHybrid (optional)%s — OpenMandriva SRPM sources + stamps\n' "$C_BOLD" "$C_RESET" >&2
  549. local ans
  550. ans="$(ask '1) Classic 2) Hybrid [1]:' 1)"
  551. case "$ans" in 2) TREE_MODE=hybrid ;; *) TREE_MODE=classic; XANMOD_MAJOR="${XANMOD_MAJOR:-7}" ;; esac
  552. }
  553.  
  554. xanmod_tags() {
  555. git ls-remote --tags --refs "${XANMOD_GIT}" 2>/dev/null | awk -F/ '{print $NF}' | sort -rV
  556. }
  557.  
  558. pick_xanmod_tag() {
  559. local tags=() filtered=() t
  560. mapfile -t tags < <(xanmod_tags)
  561. ((${#tags[@]})) || die "No tags from ${XANMOD_GIT}"
  562. if [[ -n "$FORCE_TAG" ]]; then
  563. for t in "${tags[@]}"; do [[ "$t" == "$FORCE_TAG" ]] && { TAG="$FORCE_TAG"; info "Tag ${TAG}"; return 0; }; done
  564. die "Tag '${FORCE_TAG}' not in ${XANMOD_GIT}"
  565. fi
  566. if [[ "$XANMOD_MAJOR" == 7 ]]; then
  567. for t in "${tags[@]}"; do [[ "$t" == 7.* ]] && filtered+=("$t"); done
  568. ((${#filtered[@]})) || die "No 7.x tags"
  569. tags=("${filtered[@]}")
  570. fi
  571. TAG="${tags[0]}"
  572. info "Tag ${TAG}"
  573. }
  574.  
  575. have_usable_tree() {
  576. [[ -f "${WORKDIR}/linux/Makefile" && -d "${WORKDIR}/linux/arch/x86" ]]
  577. }
  578.  
  579. fetch_xanmod_source() {
  580. local dir="${WORKDIR}/linux"
  581. mkdir -p "${WORKDIR}"
  582. if (( ! FORCE_FETCH )) && have_usable_tree; then
  583. TAG="${TAG:-reused}"
  584. ok "Reusing ${dir}"
  585. patch_compressed_makefile "$dir"
  586. return 0
  587. fi
  588. [[ -n "$TAG" ]] || die "No tag"
  589. info "Clone ${TAG} → ${dir}"
  590. rm -rf "$dir"
  591. git clone --depth 1 --branch "$TAG" "$XANMOD_GIT" "$dir" || die "clone failed"
  592. rm -rf "${dir}/.git"
  593. patch_compressed_makefile "$dir"
  594. }
  595.  
  596. unpack_kernel_srpm() {
  597. local srpm="$1" label="$2" tarball major minor patch
  598. rm -rf "${WORKDIR}/om-src" "${WORKDIR}/linux"
  599. mkdir -p "${WORKDIR}/om-src" "${WORKDIR}/linux"
  600. (cd "${WORKDIR}/om-src" && rpm2cpio "$srpm" | cpio -idmu --quiet) || die "srpm unpack failed"
  601. tarball="$(find "${WORKDIR}/om-src" -maxdepth 1 -type f -name 'linux-*.tar.*' | head -n1)"
  602. [[ -n "$tarball" ]] || die "no linux tarball in SRPM"
  603. tar -xf "$tarball" -C "${WORKDIR}/linux" --strip-components=1 || die "extract failed"
  604. major=$(awk '/^VERSION/{print $3}' "${WORKDIR}/linux/Makefile")
  605. minor=$(awk '/^PATCHLEVEL/{print $3}' "${WORKDIR}/linux/Makefile")
  606. patch=$(awk '/^SUBLEVEL/{print $3}' "${WORKDIR}/linux/Makefile")
  607. TAG="${label}-${major}.${minor}.${patch}"
  608. patch_compressed_makefile "${WORKDIR}/linux"
  609. }
  610.  
  611. fetch_om_base() {
  612. local srpm
  613. mkdir -p "${WORKDIR}"
  614. if (( ! FORCE_FETCH )) && have_usable_tree; then
  615. TAG="${TAG:-om-reused}"
  616. ok "Reusing ${WORKDIR}/linux"
  617. patch_compressed_makefile "${WORKDIR}/linux"
  618. return 0
  619. fi
  620. if [[ -n "$USER_SRPM" ]]; then
  621. unpack_kernel_srpm "$USER_SRPM" om-srpm
  622. return 0
  623. fi
  624. (cd "${WORKDIR}" && dnf download --source kernel-rc) || true
  625. srpm="$(find "${WORKDIR}" -maxdepth 1 -name 'kernel-rc-*.src.rpm' | head -n1)"
  626. if [[ -z "$srpm" ]]; then
  627. (cd "${WORKDIR}" && dnf download --source kernel-release-desktop) || die "OM SRPM download failed"
  628. srpm="$(find "${WORKDIR}" -maxdepth 1 -name 'kernel-release-desktop-*.src.rpm' | head -n1)"
  629. fi
  630. [[ -n "$srpm" ]] || die "no OM SRPM"
  631. unpack_kernel_srpm "$srpm" om
  632. }
  633.  
  634. pick_donor_config() {
  635. local f
  636. for f in "/boot/config-$(uname -r)" /boot/config-*-desktop*; do
  637. [[ -r "$f" ]] && { echo "$f"; return 0; }
  638. done
  639. echo "/boot/config-$(uname -r)"
  640. }
  641.  
  642. synthesize_config() {
  643. local tree="${WORKDIR}/linux" donor
  644. [[ -f "${tree}/Makefile" ]] || die "No tree ${tree}"
  645. donor="$(pick_donor_config)"
  646. patch_compressed_makefile "$tree"
  647. if [[ -n "$XANMOD_CFG" ]]; then
  648. local xc="${tree}/CONFIGS/xanmod/gcc/config_x86-64-v${XANMOD_CFG}"
  649. [[ -r "$xc" ]] || die "XanMod config missing: ${xc} (found: $(ls "${tree}"/CONFIGS/xanmod/* 2>/dev/null | tr '\n' ' '))"
  650. info "Base: XanMod ${xc##*/} (no OM donor)"
  651. cp "$xc" "${tree}/.config"
  652. elif [[ -r "$donor" ]]; then
  653. info "Donor: ${donor}"
  654. cp "$donor" "${tree}/.config"
  655. else
  656. (cd "$tree" && km_ni defconfig) || die "defconfig failed"
  657. fi
  658. if (( ! KEEP_TDA18212 )) && [[ -f "${tree}/drivers/media/tuners/tda18212.c" ]]; then
  659. sed -i 's/buf\[2\] = priv->cfg->xtout ? 0x43 : 0x40;/buf[2] = 0x40;/' \
  660. "${tree}/drivers/media/tuners/tda18212.c" || true
  661. fi
  662. rm -f "${tree}/localversion"* "${tree}/.scmversion"
  663. printf '%s\n' '-xanmod1' > "${tree}/localversion"
  664. sed -i '/^CONFIG_LOCALVERSION=/d;/^CONFIG_LOCALVERSION_AUTO=/d' "${tree}/.config"
  665. printf '%s\n' 'CONFIG_LOCALVERSION=""' '# CONFIG_LOCALVERSION_AUTO is not set' >> "${tree}/.config"
  666. settle_config "$tree"
  667. (cd "$tree" && km_ni tools/objtool) || warn "objtool warnings"
  668. (cd "$tree" && km_ni prepare) || die "prepare failed"
  669. mkdir -p "${tree}/include/generated"
  670. grep -q 'CONFIG_X86_L1_CACHE_SHIFT' "${tree}/include/generated/autoconf.h" 2>/dev/null || \
  671. echo '#define CONFIG_X86_L1_CACHE_SHIFT 6' >> "${tree}/include/generated/autoconf.h"
  672. KERNEL_VER="$(cd "$tree" && km -s kernelrelease | tail -n1 | tr -d '[:space:]')"
  673. [[ "$KERNEL_VER" =~ ^[0-9]+\.[0-9]+ ]] || die "bad kernelrelease: ${KERNEL_VER}"
  674. KERNEL_VER_RPM="${KERNEL_VER//-/.}"
  675. ok "Configured ${KERNEL_VER}"
  676. }
  677.  
  678. prepare_sources() {
  679. local dirname="${RPM_NAME}-${SAFE_TAG}" tmpdir="${WORKDIR}/tar-tmp"
  680. mkdir -p "${RPM_TOPDIR}/SOURCES" "$tmpdir"
  681. rm -rf "${tmpdir:?}/${dirname:?}"
  682. cp -a "${WORKDIR}/linux" "${tmpdir}/${dirname}"
  683. rm -rf "${tmpdir}/${dirname}/.git"
  684. (cd "$tmpdir" && "$GNUTAR" -cf "${RPM_TOPDIR}/SOURCES/${dirname}.tar" "$dirname") || die "tar failed"
  685. cp "${WORKDIR}/linux/.config" "${RPM_TOPDIR}/SOURCES/config-${SAFE_TAG}"
  686. ok "Tarball ready"
  687. }
  688.  
  689. afdo_stage() {
  690. if (( ! AUTOFDO )); then echo none
  691. elif [[ -n "$PROPELLER_PREFIX" ]]; then echo final-prop
  692. elif (( PROPELLER )); then echo prop1
  693. elif [[ -n "$AFDO_PROFILE" ]]; then echo final-afdo
  694. else echo afdo1
  695. fi
  696. }
  697.  
  698. afdo_parent_stage() {
  699. case "$1" in
  700. prop1|final-afdo) echo afdo1 ;;
  701. final-prop) echo prop1 ;;
  702. *) echo "" ;;
  703. esac
  704. }
  705.  
  706. # Everything that must not change between the profiling build and the build that consumes
  707. # its profile (AutoFDO/Propeller profiles are tied to the exact source, compiler and config).
  708. afdo_snapshot() {
  709. local commit sha=""
  710. commit="$(git -C "${WORKDIR}/linux" rev-parse HEAD 2>/dev/null || echo unknown)"
  711. if [[ -n "$AFDO_PROFILE" ]]; then sha="$(sha256sum "$AFDO_PROFILE" | cut -d' ' -f1)"; fi
  712. printf '%s=%q\n' \
  713. TAG "${TAG:-unknown}" COMMIT "$commit" THINLTO "$THINLTO" NO_NATIVE "$NO_NATIVE" \
  714. X86_LEVEL "${X86_LEVEL:-}" XANMOD_CFG "${XANMOD_CFG:-}" USE_BFD "$USE_BFD" \
  715. NO_WRAPPERS "$NO_WRAPPERS" \
  716. CLANG "$("$LLVM_CLANG" --version 2>/dev/null | head -n1)" \
  717. LLD "$("$LLVM_LLD" --version 2>/dev/null | head -n1)" \
  718. AFDO_SHA "$sha"
  719. }
  720.  
  721. afdo_record_or_verify() {
  722. (( AUTOFDO )) || return 0
  723. local stage parent dir f pf cur d
  724. stage="$(afdo_stage)"; parent="$(afdo_parent_stage "$stage")"
  725. dir="${RPM_TOPDIR}/AFDO"; mkdir -p "$dir"
  726. f="${dir}/flags-${SAFE_TAG}-${stage}.env"
  727. cur="$(afdo_snapshot)"
  728. if [[ -n "$parent" ]]; then
  729. pf="${dir}/flags-${SAFE_TAG}-${parent}.env"
  730. if [[ -r "$pf" ]]; then
  731. if [[ "$stage" == final-prop ]]; then
  732. d="$(diff <(printf '%s\n' "$cur") "$pf" || true)"
  733. else
  734. d="$(diff <(printf '%s\n' "$cur" | grep -v '^AFDO_SHA=') <(grep -v '^AFDO_SHA=' "$pf") || true)"
  735. fi
  736. if [[ -n "$d" ]]; then
  737. printf '%s\n' "$d" >&2
  738. if (( AFDO_FORCE )); then
  739. warn "stage ${stage} differs from ${parent} (shown above; '<' = now, '>' = ${parent}); continuing (--afdo-force)"
  740. else
  741. die "stage ${stage} differs from the recorded ${parent} build (see diff above). Rebuild with the same flags/tag, or pass --afdo-force"
  742. fi
  743. else
  744. ok "stage ${stage}: build flags match the recorded ${parent} build"
  745. fi
  746. else
  747. warn "no record of the ${parent} build (${pf}); cannot verify the profile matches these flags"
  748. fi
  749. fi
  750. printf '%s\n' "$cur" > "$f"
  751. info "stage ${stage}: flags recorded in ${f}"
  752. }
  753.  
  754. generate_spec() {
  755. local name="${RPM_NAME}" dirname="${RPM_NAME}-${SAFE_TAG}"
  756. local ver="${KERNEL_VER_RPM}" kv="${KERNEL_VER}"
  757. local cpu_desc="x86-64 native"
  758. (( NO_NATIVE )) && cpu_desc="x86-64${X86_LEVEL:+-v${X86_LEVEL}}"
  759. local spec="${RPM_TOPDIR}/SPECS/${PROGNAME}.spec"
  760. local prep_hacks bz_nm kinfo_hack extra_hacks afdo_arg afdo_save prop_arg
  761. mkdir -p "${RPM_TOPDIR}/SPECS"
  762. read -r -d '' kinfo_hack <<'PH' || true
  763. MF=arch/x86/boot/compressed/Makefile
  764. sed -i '/^LDFLAGS_vmlinux += -u kernel_info[[:space:]]*$/d' "$MF"
  765. sed -i '/^LDFLAGS_vmlinux += --undefined=kernel_info/d' "$MF"
  766. sed -i '/^LDFLAGS_vmlinux += -T[[:space:]]*$/i LDFLAGS_vmlinux += -u kernel_info' "$MF"
  767. grep -q -- '-u kernel_info' "$MF" || { echo "kernel_info retention not applied" >&2; exit 1; }
  768. PH
  769. if (( NO_BOOT_HACKS )); then
  770. prep_hacks="${kinfo_hack}"
  771. bz_nm='llvm-nm'
  772. else
  773. bz_nm='/usr/bin/nm'
  774. read -r -d '' extra_hacks <<'PH' || true
  775. sed -i 's|$(NM)|/usr/bin/nm|g' "$MF"
  776. PH
  777. prep_hacks="${kinfo_hack}"$'\n'"${extra_hacks}"
  778. fi
  779. afdo_arg=""; afdo_save=""; prop_arg=""
  780. if [[ -n "$AFDO_PROFILE" ]]; then afdo_arg="CLANG_AUTOFDO_PROFILE=${AFDO_PROFILE}"; fi
  781. if [[ -n "$PROPELLER_PREFIX" ]]; then prop_arg="CLANG_PROPELLER_PROFILE_PREFIX=${PROPELLER_PREFIX}"; fi
  782. case "$(afdo_stage)" in
  783. afdo1|prop1) afdo_save="install -D -m 0644 vmlinux ${RPM_TOPDIR}/AFDO/vmlinux-%{kernel_ver}-$(afdo_stage)" ;;
  784. esac
  785. cat > "$spec" <<EOF
  786. Name: ${name}
  787. Version: ${ver}
  788. Release: 1%{?dist}
  789. Summary: XanMod desktop kernel (Clang/LLVM/ld.lld)
  790. License: GPL-2.0-only
  791. Group: System/Kernel and hardware
  792. URL: https://xanmod.org/
  793. ExclusiveArch: x86_64
  794. %global kernel_ver ${kv}
  795. AutoReq: no
  796. AutoProv: no
  797. %global _use_internal_dependency_generator 0
  798. %global __find_provides %{nil}
  799. %global __find_requires %{nil}
  800. %global debug_package %{nil}
  801. %global __find_debuginfo /bin/true
  802. Source0: ${dirname}.tar
  803. Source1: config-${SAFE_TAG}
  804. BuildRequires: make binutils clang llvm lld flex bison bc perl gnutar rsync zstd
  805. BuildRequires: elfutils-libelf-devel openssl-devel dwarves
  806. Provides: installonlypkg(kernel)
  807. Requires: %{name}-modules = %{version}-%{release}
  808.  
  809. %description
  810. XanMod ${kv}: Clang/LLVM, ${cpu_desc}, ThinLTO, 250 Hz, NO_HZ_FULL.
  811. Module set from OpenMandriva donor config where applicable.
  812.  
  813. %package modules
  814. Summary: Loadable modules for %{name}
  815. AutoReq: no
  816. AutoProv: no
  817. Provides: installonlypkg(kernel)
  818. %description modules
  819. Modules for %{kernel_ver}.
  820.  
  821. %package devel
  822. Summary: Development files for %{name}
  823. AutoReq: no
  824. AutoProv: no
  825. Provides: kernel-devel-uname-r = %{kernel_ver}
  826. %description devel
  827. Headers and Module.symvers for DKMS.
  828.  
  829. %prep
  830. %setup -q -n ${dirname}
  831. cp %{SOURCE1} .config
  832. ${prep_hacks}
  833.  
  834. %build
  835. export PATH=${LLVM_BIN}:${HOME}/bin:\$PATH
  836. export LLVM=1 LLVM_IAS=1
  837. make -j${JOBS} ARCH=x86_64 SRCARCH=x86 \\
  838. CC=${CCBIN} LD=${LINKER} \\
  839. AR=llvm-ar NM=llvm-nm STRIP=llvm-strip OBJCOPY=llvm-objcopy \\
  840. HOSTCC=${CCBIN} HOSTCXX=${CXXBIN} HOSTLD=${LINKER} \\
  841. LLVM=1 LLVM_IAS=1 \\
  842. KCFLAGS="${OMX_KCFLAGS}" KCPPFLAGS="${OMX_KCPPFLAGS}" ${afdo_arg} ${prop_arg} \\
  843. olddefconfig </dev/null
  844. make -j${JOBS} ARCH=x86_64 SRCARCH=x86 \\
  845. CC=${CCBIN} LD=${LINKER} \\
  846. AR=llvm-ar NM=llvm-nm OBJCOPY=llvm-objcopy \\
  847. HOSTCC=${CCBIN} HOSTCXX=${CXXBIN} HOSTLD=${LINKER} \\
  848. LLVM=1 LLVM_IAS=1 \\
  849. KCFLAGS="${OMX_KCFLAGS}" KCPPFLAGS="${OMX_KCPPFLAGS}" ${afdo_arg} ${prop_arg} \\
  850. modules
  851. test -s Module.symvers
  852. omx_snap() { grep -E '^(# )?CONFIG_(LTO_CLANG_THIN|LTO_NONE|AUTOFDO_CLANG|PROPELLER_CLANG|X86_NATIVE_CPU|X86_64_VERSION|MODULE_COMPRESS_[A-Z0-9]+)[ =]' .config | sort; }
  853. omx_snap > .omx-snap-before
  854. make -j${JOBS} ARCH=x86_64 SRCARCH=x86 \\
  855. CC=${CCBIN} LD=${LINKER} \\
  856. AR=llvm-ar NM=${bz_nm} OBJCOPY=llvm-objcopy \\
  857. HOSTCC=${CCBIN} HOSTCXX=${CXXBIN} HOSTLD=${LINKER} \\
  858. LLVM=1 LLVM_IAS=1 \\
  859. KCFLAGS="${OMX_KCFLAGS}" KCPPFLAGS="${OMX_KCPPFLAGS}" ${afdo_arg} ${prop_arg} \\
  860. syncconfig </dev/null
  861. omx_snap > .omx-snap-after
  862. if ! cmp -s .omx-snap-before .omx-snap-after; then
  863. echo "ERROR: .config changed when re-synced for bzImage: a tool differs between make steps (Kconfig reads NM/AR/LD/CC output). Aborting before a full rebuild." >&2
  864. diff .omx-snap-before .omx-snap-after >&2 || true
  865. exit 1
  866. fi
  867. rm -f arch/x86/boot/bzImage arch/x86/boot/setup.elf arch/x86/boot/zoffset.h \\
  868. arch/x86/boot/compressed/vmlinux
  869. make -j${JOBS} ARCH=x86_64 SRCARCH=x86 \\
  870. CC=${CCBIN} LD=${LINKER} \\
  871. AR=llvm-ar NM=${bz_nm} OBJCOPY=llvm-objcopy \\
  872. HOSTCC=${CCBIN} HOSTCXX=${CXXBIN} HOSTLD=${LINKER} \\
  873. LLVM=1 LLVM_IAS=1 \\
  874. KCFLAGS="${OMX_KCFLAGS}" KCPPFLAGS="${OMX_KCPPFLAGS}" ${afdo_arg} ${prop_arg} \\
  875. bzImage
  876. test -s arch/x86/boot/bzImage
  877.  
  878. %install
  879. rm -rf %{buildroot}
  880. export PATH=${LLVM_BIN}:${HOME}/bin:\$PATH
  881. KREL=%{kernel_ver}
  882. MODROOT=%{buildroot}/lib/modules/\$KREL
  883. BOOTROOT=%{buildroot}/boot
  884. SRCDIR=%{buildroot}/usr/src/kernels/\$KREL
  885. mkdir -p "\$BOOTROOT" "\$MODROOT" "\$SRCDIR"
  886. export PATH=${HOME}/bin:\$PATH
  887. make ARCH=x86_64 INSTALL_MOD_PATH=%{buildroot} INSTALL_MOD_STRIP=1 STRIP=llvm-strip \\
  888. CC=${CCBIN} LD=${LINKER} LLVM=1 LLVM_IAS=1 \\
  889. KCFLAGS="${OMX_KCFLAGS}" KCPPFLAGS="${OMX_KCPPFLAGS}" ${afdo_arg} ${prop_arg} \\
  890. modules_install
  891. ${afdo_save}
  892. install -m 0644 arch/x86/boot/bzImage "\$BOOTROOT/vmlinuz-\$KREL"
  893. install -m 0644 System.map "\$BOOTROOT/System.map-\$KREL"
  894. install -m 0644 .config "\$BOOTROOT/config-\$KREL"
  895. rsync -a --delete \\
  896. --exclude='.git/' --exclude='arch/x86/boot/' \\
  897. --exclude='*.o' --exclude='*.a' --exclude='*.cmd' --exclude='*.ko' \\
  898. --exclude='*.mod' --exclude='*.mod.c' \\
  899. ./ "\$SRCDIR/"
  900. cp -af Module.symvers .config "\$SRCDIR/"
  901. rm -f "\$MODROOT/build" "\$MODROOT/source"
  902. ln -sfn /usr/src/kernels/\$KREL "\$MODROOT/build"
  903. ln -sfn /usr/src/kernels/\$KREL "\$MODROOT/source"
  904.  
  905. %files
  906. /boot/vmlinuz-%{kernel_ver}
  907. /boot/System.map-%{kernel_ver}
  908. /boot/config-%{kernel_ver}
  909.  
  910. %files modules
  911. /lib/modules/%{kernel_ver}
  912.  
  913. %files devel
  914. /usr/src/kernels/%{kernel_ver}
  915.  
  916. %posttrans
  917. depmod -a %{kernel_ver} || echo "depmod failed" >&2
  918. dracut --force --kver %{kernel_ver} /boot/initrd-%{kernel_ver}.img || echo "dracut FAILED for %{kernel_ver}" >&2
  919. grub2-mkconfig -o /boot/grub2/grub.cfg || echo "grub2-mkconfig failed" >&2
  920. exit 0
  921.  
  922. %changelog
  923. * $(date '+%a %b %d %Y') ${PROGNAME} - ${ver}-1
  924. - v${VERSION}: LLVM toolchain selection, x86-64-v3 distributable mode, corrected Propeller/AFDO toolchain tracking, rpmlint pass; 2.9.1: GNU-nm swap opt-in + config guard, Propeller LLVM only for Propeller builds, baked wrapper paths
  925. EOF
  926. ok "Spec written"
  927. }
  928.  
  929. run_rpmbuild() {
  930. info "rpmbuild (main + modules + devel)..."
  931. mkdir -p "$LOG_DIR"
  932. local logfile="${LOG_DIR}/rpmbuild.log" rc
  933. set +e
  934. rpmbuild -bb --nodeps --nocheck \
  935. --define "debug_package %{nil}" \
  936. --define "__find_debuginfo /bin/true" \
  937. --define "__find_provides %{nil}" \
  938. --define "__find_requires %{nil}" \
  939. --define "_build_pkgcheck %{nil}" \
  940. --define "_build_pkgcheck_set %{nil}" \
  941. --define "_build_pkgcheck_srpm %{nil}" \
  942. --define "_unpackaged_files_terminate_build 0" \
  943. "${RPM_TOPDIR}/SPECS/${PROGNAME}.spec" 2>&1 | tee "$logfile"
  944. rc=${PIPESTATUS[0]}
  945. set -e
  946. (( rc == 0 )) || die "rpmbuild failed: ${logfile}"
  947. local n
  948. n=$(find "${RPM_TOPDIR}/RPMS" -name "${RPM_NAME}*.rpm" | wc -l)
  949. (( n >= 3 )) || die "Expected 3 RPMs, found ${n}"
  950. ok "RPMs ready"
  951. ls -lh "${RPM_TOPDIR}/RPMS"/x86_64/${RPM_NAME}*.rpm 2>/dev/null || \
  952. find "${RPM_TOPDIR}/RPMS" -name "${RPM_NAME}*.rpm" -ls
  953. }
  954.  
  955. run_rpmlint() {
  956. command -v rpmlint >/dev/null 2>&1 || {
  957. warn "rpmlint not installed; skipping package lint"
  958. return 0
  959. }
  960. local -a rpms
  961. mapfile -t rpms < <(find "${RPM_TOPDIR}/RPMS" -type f -name "${RPM_NAME}*-${KERNEL_VER_RPM}-*.rpm" | sort)
  962. ((${#rpms[@]})) || die "no RPMs found for rpmlint"
  963. local log="${WORKDIR}/logs/rpmlint.log"
  964. mkdir -p "$(dirname "$log")"
  965. info "rpmlint (kernel RPMs; takes several minutes; full output: ${log})..."
  966. local rc=0
  967. rpmlint "${rpms[@]}" >"$log" 2>&1 || rc=$?
  968. tail -n 2 "$log" >&2
  969. if (( rc != 0 )); then
  970. warn "rpmlint reported findings (build/install is not blocked)"
  971. else
  972. ok "rpmlint clean"
  973. fi
  974. }
  975.  
  976. install_rpms() {
  977. (( NO_INSTALL )) && { info "--no-install; RPMs in ${RPM_TOPDIR}/RPMS"; return 0; }
  978. local -a rpms
  979. mapfile -t rpms < <(find "${RPM_TOPDIR}/RPMS" -name "${RPM_NAME}*-${KERNEL_VER_RPM}-*.rpm" | sort)
  980. ((${#rpms[@]})) || die "no RPMs for ${KERNEL_VER_RPM}"
  981. # rpm directly: dnf rejected the large -devel package with a bogus header-digest error here
  982. sudo rpm -Uvh --replacepkgs --oldpackage "${rpms[@]}" || die "rpm install failed. The RPMs are built and intact; install them by hand with: sudo rpm -Uvh --replacepkgs --oldpackage ${RPM_TOPDIR}/RPMS/x86_64/${RPM_NAME}*-${KERNEL_VER_RPM}-*.rpm"
  983. # verify the installed packages are the ones just built (BUILDTIME must match)
  984. local r name bt_f bt_i
  985. for r in "${rpms[@]}"; do
  986. name="$(rpm -qp --qf '%{NAME}' "$r")"
  987. bt_f="$(rpm -qp --qf '%{BUILDTIME}' "$r")"
  988. bt_i="$(rpm -q --qf '%{BUILDTIME}\n' "$name" | sort -n | tail -1)"
  989. [[ "$bt_f" == "$bt_i" ]] || die "installed ${name} is NOT the package just built"
  990. done
  991. info "vmlinuz: $(ls -l --time-style=long-iso "/boot/vmlinuz-${KERNEL_VER}" | awk '{print $6, $7}')"
  992. info "initrd : $(ls -l --time-style=long-iso "/boot/initrd-${KERNEL_VER}.img" | awk '{print $6, $7}')"
  993. info "LTO : $(grep -E '^CONFIG_LTO_(NONE|CLANG_THIN)=' "/boot/config-${KERNEL_VER}" | tr '\n' ' ')"
  994. ok "Installed and verified"
  995. }
  996.  
  997. maybe_cleanup_prompt() {
  998. local a
  999. a="$(ask 'Clean work tree under /tmp (re-clone next time)? [y/N]:' n)"
  1000. case "${a,,}" in y|yes) do_cleanup ;; *) info "Kept ${WORKDIR} for reuse" ;; esac
  1001. }
  1002.  
  1003. start_sudo_keepalive() {
  1004. (( NO_INSTALL )) && return 0
  1005. [[ $EUID -eq 0 ]] && return 0
  1006. sudo -v || die "sudo is needed to install the RPMs (use --no-install to skip installing)"
  1007. # refresh the sudo timestamp for as long as this script lives; no extra privileges are taken
  1008. (
  1009. while kill -0 "$$" 2>/dev/null; do
  1010. sudo -n true 2>/dev/null || exit 0
  1011. sleep "${OMX_SUDO_KEEPALIVE_INTERVAL:-50}"
  1012. done
  1013. ) &
  1014. SUDO_KEEPALIVE_PID=$!
  1015. trap 'kill "${SUDO_KEEPALIVE_PID:-0}" 2>/dev/null || true' EXIT
  1016. }
  1017.  
  1018. main() {
  1019. while (($#)); do
  1020. case "$1" in
  1021. -h|--help) help_menu; exit 0 ;;
  1022. --resume) DO_RESUME=1 ;;
  1023. --dry-run) DRY_RUN=1 ;;
  1024. --no-install) NO_INSTALL=1 ;;
  1025. --cleanup) do_cleanup; exit 0 ;;
  1026. --force-fetch) FORCE_FETCH=1 ;;
  1027. --jobs|-j) JOBS="${2:?}"; shift ;;
  1028. --srpm) USER_SRPM="${2:?}"; TREE_MODE=hybrid; shift ;;
  1029. --tag) FORCE_TAG="${2:?}"; TREE_MODE=classic; shift ;;
  1030. --hybrid) TREE_MODE=hybrid ;;
  1031. --xanmod|--classic) TREE_MODE=classic ;;
  1032. --xanmod-7|--7|--xanmod-latest) TREE_MODE=classic; XANMOD_MAJOR=7 ;;
  1033. --xanmod-github) TREE_MODE=classic; XANMOD_GIT="${XANMOD_GIT_GITHUB}" ;;
  1034. --use-bfd) USE_BFD=1 ;;
  1035. --xanmod-config) XANMOD_CFG="${2:?}"; XANMOD_CFG="${XANMOD_CFG#v}"; shift ;;
  1036. --native) WANT_NATIVE=1 ;;
  1037. --autofdo) AUTOFDO=1 ;;
  1038. --propeller) PROPELLER=1; AUTOFDO=1 ;;
  1039. --propeller-profile) [[ $# -ge 2 ]] || die "--propeller-profile needs a prefix"; PROPELLER_PREFIX="$2"; PROPELLER=1; AUTOFDO=1; shift ;;
  1040. --afdo-force) AFDO_FORCE=1 ;;
  1041. --afdo-profile) [[ $# -ge 2 ]] || die "--afdo-profile needs a file"; AFDO_PROFILE="$2"; AUTOFDO=1; shift ;;
  1042. --plain-lld) PLAIN_LLD=1 ;;
  1043. --lld-wrapper) PLAIN_LLD=0 ;;
  1044. --v3) X86_LEVEL=3 ;;
  1045. --x86-64-v3) X86_LEVEL=3; NO_NATIVE=1 ;;
  1046. --x86-level) X86_LEVEL="${2:?}"; shift ;;
  1047. --llvm-root) LLVM_ROOT="${2:?}"; shift ;;
  1048. --no-wrappers) NO_WRAPPERS=1 ;;
  1049. --no-thinlto) THINLTO=0 ;;
  1050. --no-native) NO_NATIVE=1 ;;
  1051. --no-boot-hacks) NO_BOOT_HACKS=1; FORCE_FETCH=1 ;;
  1052. --boot-hacks) NO_BOOT_HACKS=0 ;;
  1053. --rpmlint) RUN_RPMLINT=1 ;;
  1054. --bisect) THINLTO=0; NO_NATIVE=1; NO_BOOT_HACKS=1; FORCE_FETCH=1 ;;
  1055. --force-thinlto) THINLTO=1 ;;
  1056. --keep-tda18212) KEEP_TDA18212=1 ;;
  1057. -y|--yes) ASSUME_YES=1 ;;
  1058. *) die "Unknown: $1" ;;
  1059. esac
  1060. shift
  1061. done
  1062. [[ "$JOBS" =~ ^[1-9][0-9]*$ ]] || die "bad --jobs"
  1063. if (( AUTOFDO )); then
  1064. if [[ -n "$AFDO_PROFILE" ]]; then
  1065. [[ -r "$AFDO_PROFILE" ]] || die "AutoFDO profile not readable: ${AFDO_PROFILE}"
  1066. AFDO_PROFILE="$(readlink -f "$AFDO_PROFILE")"
  1067. fi
  1068. if (( PROPELLER )); then
  1069. if (( USE_BFD )); then die "Propeller needs ld.lld (drop --use-bfd)"; fi
  1070. [[ -n "$AFDO_PROFILE" ]] || die "Propeller stages need --afdo-profile (documented pipeline: build-afdo, train-afdo, build-propeller, train-propeller, build-optimized)"
  1071. fi
  1072. if [[ -n "$PROPELLER_PREFIX" ]]; then
  1073. PROPELLER_PREFIX="$(realpath -m "$PROPELLER_PREFIX")"
  1074. [[ -r "${PROPELLER_PREFIX}_cc_profile.txt" && -r "${PROPELLER_PREFIX}_ld_profile.txt" ]] \
  1075. || die "missing ${PROPELLER_PREFIX}_cc_profile.txt and/or ${PROPELLER_PREFIX}_ld_profile.txt"
  1076. fi
  1077. fi
  1078. [[ -z "$X86_LEVEL" || "$X86_LEVEL" =~ ^[1-4]$ ]] || die "--x86-level takes 1-4"
  1079. if [[ -n "$LLVM_ROOT" ]]; then
  1080. [[ -d "$LLVM_ROOT/bin" ]] || die "LLVM root has no bin directory: $LLVM_ROOT"
  1081. fi
  1082. if [[ -n "$XANMOD_CFG" ]]; then
  1083. [[ "$XANMOD_CFG" =~ ^[1-4]$ ]] || die "--xanmod-config takes v1, v2, v3 or v4"
  1084. if (( WANT_NATIVE )); then NO_NATIVE=0; else NO_NATIVE=1; fi
  1085. fi
  1086. (( NO_NATIVE )) && OMX_KCFLAGS="-Wno-unknown-warning-option"
  1087. if (( USE_BFD && THINLTO )); then die "ThinLTO needs ld.lld: with --use-bfd add --no-thinlto"; fi
  1088. info "flags: THINLTO=${THINLTO} NO_NATIVE=${NO_NATIVE} NO_BOOT_HACKS=${NO_BOOT_HACKS} USE_BFD=${USE_BFD} XANMOD_CFG=${XANMOD_CFG:-donor} X86_LEVEL=${X86_LEVEL:-default} PLAIN_LLD=${PLAIN_LLD} NO_WRAPPERS=${NO_WRAPPERS} LLVM_ROOT=${LLVM_ROOT:-auto} AUTOFDO=${AUTOFDO} AFDO_PROFILE=${AFDO_PROFILE:-none} PROPELLER=${PROPELLER} PROPELLER_PREFIX=${PROPELLER_PREFIX:-none} STAGE=$(afdo_stage)"
  1089. mkdir -p "$WORKDIR" "$LOG_DIR" "${RPM_TOPDIR}"/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS}
  1090. printf '\n%b▶ %s v%s%b\n\n' "$C_BOLD$C_CYAN" "$PROGNAME" "$VERSION" "$C_RESET"
  1091. start_sudo_keepalive
  1092. check_deps
  1093. preflight
  1094. if (( AUTOFDO )); then
  1095. _cv="$("$LLVM_CLANG" --version 2>/dev/null | sed -n 's/.*clang version \([0-9][0-9]*\).*/\1/p' | head -n1)"
  1096. [[ "${_cv:-0}" -ge 19 ]] || die "AutoFDO needs Clang >= 19 (found ${_cv:-none})"
  1097. if (( PROPELLER )); then
  1098. _lv="$("$LLVM_LLD" --version 2>/dev/null | sed -n 's/.*LLD \([0-9][0-9]*\).*/\1/p' | head -n1)"
  1099. [[ "${_lv:-0}" -ge 19 ]] || die "Propeller needs ld.lld >= 19 (found ${_lv:-none})"
  1100. fi
  1101. fi
  1102. (( DO_RESUME )) && do_resume
  1103. choose_tree_mode
  1104. ensure_gnutar
  1105. if [[ "$TREE_MODE" == hybrid ]]; then
  1106. info "Hybrid (OM SRPM base)"
  1107. fetch_om_base
  1108. else
  1109. info "Classic XanMod"
  1110. pick_xanmod_tag
  1111. fetch_xanmod_source
  1112. fi
  1113. SAFE_TAG="$(printf '%s' "$TAG" | tr '/:[:space:]' '---' | tr -cd 'A-Za-z0-9._+-')"
  1114. [[ -n "$SAFE_TAG" ]] || SAFE_TAG=unknown
  1115. (( DRY_RUN )) && { ok "Dry-run done"; exit 0; }
  1116. afdo_record_or_verify
  1117. synthesize_config
  1118. prepare_sources
  1119. generate_spec
  1120. run_rpmbuild
  1121. install_rpms
  1122. if (( RUN_RPMLINT )); then run_rpmlint; fi
  1123. maybe_cleanup_prompt
  1124. ok "Done"
  1125. }
  1126.  
  1127. main "$@"
Advertisement
Comments
  • RitchieSolo
    17 days
    # text 2.02 KB | 0 0
    1. export TMPDIR=/var/tmp # or any large directory you own
    2. # or
    3. export TMPDIR=$HOME/tmp
    4. mkdir -p "$TMPDIR"
    5. and then run this script using the flags which are listed from the --help flag. For instance to create an march=native ThinLTO, Clang / LLV, AutoFDO kernel with propeller capability using that xanmod-7 tree and using the 7.1.13 subversion you would do something like this ./OMX-Kernel-Build-Script-2.9.0.sh --xanmod-7 --tag 7.1.13 --afdo-profile ~/afdo/xanmod-7.1.13-autofdo-heavy-1h.afdo --propeller --force-thinlto -y
    6. In my case I have already created the afdo profile for AutoFDO capability. If you have not done this yet then run the command first without --afdo-profile and without --propeller first. Once you have a basic Clang / LLVM + ThinLTO kernel then you can generate an AutoFDO profile and you would then run this command as I have listed it. This will build a march=native kernel which is AutoFDO enabled and is Propeller capable. When you reboot into this kernel the next time after this you can use /opt/llvm-propeller-23/bin/generate_propeller_profiles to generate a propeller lc.txt and ld.txt to program propeller for the next compile. Once you finish this last compile your kernel will now be fully optimized with AutoFDO enabled and Propeller fully programmed so that the kernel is finely tuned for your hardware. If you wish to make distributable packages of this kernel in this way then please use --no-native to enable x86-64-v3 generically instead of march=native in the kernel .config file. I have also packaged an rpm package with Clang / LLVM 23 with Propeller included if anyone needs it I can supply this rpm. The LLVM-Propeller rpm installs in /opt and does not conflict with OpenMandriva's native Clang installation nor will it bother it when removing the rpm should you choose to do so. The omx-afdo-script.sh I have also created is used to create your profile for AutoFDO before compiling the AutoFDO kernel with Propeller capability baked in.
    7.  
    8. You can find that script here https://pastebin.com/9NAyDagY
  • RitchieSolo
    17 days
    # text 0.23 KB | 0 0
    1. use --no-boot-hacks flag if you wish to create a ThinLTO kernel. This flag will use nm-llvm instead of nm which silently drops LTO and changes it to LTO_NONE=y in the config. This updated version of 2.9.1 make --no-boot-hacks=1 the default.
  • RitchieSolo
    17 days
    # text 0.29 KB | 0 0
    1. In v2.9.1 --no-boot-hacks is enabled by default. Run it like this as an example:
    2.  
    3. cd ~
    4.  
    5. ./OMX-Kernel-Build-Script-2.9.1.sh \
    6. --xanmod-7 \
    7. --tag 7.1.13-xanmod1 \
    8. --afdo-profile ~/afdo/xanmod-7.1.13-autofdo-heavy-1h.afdo \
    9. --propeller \
    10. --force-thinlto \
    11. --force-fetch \
    12. -y
Add Comment
Please, Sign In to add comment