-
Notifications
You must be signed in to change notification settings - Fork 0
286 lines (254 loc) ยท 14.8 KB
/
build.yml
File metadata and controls
286 lines (254 loc) ยท 14.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
name: Hyperion Kernel Build CI
on:
workflow_dispatch:
concurrency:
group: hyperion-kernel
cancel-in-progress: false
permissions:
contents: write
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# CACHING ARCHITECTURE
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
#
# Layer 1 โ ccache โ ccache-<os>-<ver>-<cfg>-<patches>-<run_id>
# โ โ Always saves a NEW key per run so restore-keys
# โ โ always finds the freshest partial cache.
# โ โ SLOPPINESS + DIRECT mode = max hit rate.
#
# Layer 2 โ Source tarball โ kernel-tarball-<version>
# โ โ Immutable. Downloaded once, cached forever.
#
# Layer 3 โ Full build tree โ kernel-tree-<ver>-<cfg>-<patches>
# โ โ Exact match = zero rebuild (incremental make).
# โ โ Partial match via restore-keys still helps.
# โ โ Saved unconditionally after every build.
#
# โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
jobs:
validate-config:
runs-on: ubuntu-latest
outputs:
VERSION: ${{ steps.parse.outputs.VERSION }}
FULL_VERSION: ${{ steps.parse.outputs.FULL_VERSION }}
TAG: ${{ steps.parse.outputs.TAG }}
HYPERION_VER: ${{ steps.parse.outputs.HYPERION_VER }}
CONFIG_HASH: ${{ steps.parse.outputs.CONFIG_HASH }}
PATCHES_HASH: ${{ steps.parse.outputs.PATCHES_HASH }}
steps:
- uses: actions/checkout@v4
- name: Parse hyperion.config
id: parse
run: |
set -euo pipefail
python3 << 'EOF'
import os, hashlib, glob
config = {}
with open("hyperion.config") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"): continue
k, v = line.split("=", 1)
config[k.strip()] = v.strip().strip('"')
VERSION = int(config.get("CONFIG_VERSION", 0))
PATCH = int(config.get("CONFIG_PATCHLEVEL", 0))
SUB = int(config.get("CONFIG_SUBLEVEL", 0))
FULL_VERSION = f"{VERSION}.{PATCH}" if SUB == 0 else f"{VERSION}.{PATCH}.{SUB}"
LOCAL = config.get("CONFIG_LOCALVERSION", "")
HYPERION_VER = LOCAL.split("-Hyperion-", 1)[-1] if "-Hyperion-" in LOCAL else LOCAL.lstrip("-")
TAG = HYPERION_VER
CONFIG_HASH = hashlib.sha256(open("hyperion.config", "rb").read()).hexdigest()[:12]
patches = sorted(glob.glob("patches/*.patch"))
PATCHES_HASH = hashlib.sha256(b"".join(open(p, "rb").read() for p in patches)).hexdigest()[:12] if patches else "none"
out = os.environ["GITHUB_OUTPUT"]
with open(out, "a") as f:
for k, v in {
"VERSION": VERSION, "FULL_VERSION": FULL_VERSION,
"TAG": TAG, "HYPERION_VER": HYPERION_VER,
"CONFIG_HASH": CONFIG_HASH, "PATCHES_HASH": PATCHES_HASH,
}.items():
f.write(f"{k}={v}\n")
EOF
build-kernel:
needs: validate-config
runs-on: ubuntu-latest
env:
KERNEL_VERSION: ${{ needs.validate-config.outputs.VERSION }}
FULL_VERSION: ${{ needs.validate-config.outputs.FULL_VERSION }}
TAG_NAME: ${{ needs.validate-config.outputs.TAG }}
HYPERION_VER: ${{ needs.validate-config.outputs.HYPERION_VER }}
CONFIG_HASH: ${{ needs.validate-config.outputs.CONFIG_HASH }}
PATCHES_HASH: ${{ needs.validate-config.outputs.PATCHES_HASH }}
# โโ Reproducible build identity โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
KBUILD_BUILD_USER: Soumalya
KBUILD_BUILD_HOST: github-runner
# KBUILD_BUILD_TIMESTAMP is set dynamically from git history below
# โโ ccache โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
CCACHE_DIR: ${{ github.workspace }}/.ccache
CCACHE_MAXSIZE: 8G
# Compression: on, level 6 (good balance of speed vs size)
CCACHE_COMPRESS: 1
CCACHE_COMPRESSLEVEL: 6
# Direct mode: skip preprocessing step, cache by hash of source + headers
CCACHE_DIRECT: 1
# Basedir strips the workspace prefix from paths in the cache, so the
# cache is portable across different runner checkout paths
CCACHE_BASEDIR: ${{ github.workspace }}
CCACHE_NOHASHDIR: 1
# Sloppiness: critical for kernel builds
# time_macros โ ignore __DATE__ / __TIME__ (we fix the timestamp anyway)
# include_file_mtime โ don't invalidate on header mtime, only content
# include_file_ctime โ same for ctime
# file_stat_matches โ use stat() instead of content hash for unchanged files
# pch_defines โ handle precompiled-header define changes gracefully
CCACHE_SLOPPINESS: time_macros,include_file_mtime,include_file_ctime,file_stat_matches,pch_defines
steps:
- uses: actions/checkout@v4
# โโ Layer 0: Reproducible timestamps โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Pin KBUILD_BUILD_TIMESTAMP to the last git commit so every build of
# the same source tree produces the same byte-for-byte object files,
# which is what lets ccache achieve high hit rates.
- name: Pin build timestamps to last commit
run: |
SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH" >> "$GITHUB_ENV"
echo "KBUILD_BUILD_TIMESTAMP=$(date -u -d "@$SOURCE_DATE_EPOCH" '+%a %b %e %H:%M:%S UTC %Y')" >> "$GITHUB_ENV"
echo "KBUILD_BUILD_VERSION=${GITHUB_RUN_NUMBER}" >> "$GITHUB_ENV"
# โโ Dependencies โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# APT caching is intentionally omitted: GitHub runners refresh their
# package index on every boot, making cached .deb archives unreliable.
# The install is fast enough (~20โ30 s) that the complexity isn't worth it.
- name: Install build dependencies
run: |
sudo apt-get update -qq
sudo apt-get install -y --no-install-recommends \
build-essential bc bison flex \
libssl-dev libelf-dev libncurses-dev \
dwarves rsync cpio \
ccache zstd
# Put ccache shims first so 'gcc' resolves to ccache transparently
echo "/usr/lib/ccache" >> "$GITHUB_PATH"
# โโ Layer 1: ccache (restore) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Use cache/restore (not cache) so we can save a fresh key after build.
# Primary key includes run_id so we ALWAYS write a new entry, and
# restore-keys fan out from most- to least-specific for the best warmup.
- name: Restore ccache
id: ccache-restore
uses: actions/cache/restore@v4
with:
path: .ccache
key: ccache-${{ runner.os }}-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-${{ env.PATCHES_HASH }}-${{ github.run_id }}
restore-keys: |
ccache-${{ runner.os }}-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-${{ env.PATCHES_HASH }}-
ccache-${{ runner.os }}-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-
ccache-${{ runner.os }}-${{ env.FULL_VERSION }}-
ccache-${{ runner.os }}-
- name: Zero ccache stats (for clean per-run reporting)
run: ccache --zero-stats
# โโ Layer 2: Source tarball โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- name: Restore kernel source tarball
id: kernel-tarball
uses: actions/cache@v4
with:
path: linux-${{ env.FULL_VERSION }}.tar.xz
key: kernel-tarball-${{ env.FULL_VERSION }}
- name: Download kernel tarball
if: steps.kernel-tarball.outputs.cache-hit != 'true'
run: |
curl -fsSL --output "linux-${FULL_VERSION}.tar.xz" \
"https://cdn.kernel.org/pub/linux/kernel/v${KERNEL_VERSION}.x/linux-${FULL_VERSION}.tar.xz"
curl -fsSL "https://cdn.kernel.org/pub/linux/kernel/v${KERNEL_VERSION}.x/sha256sums.asc" \
| grep "linux-${FULL_VERSION}.tar.xz" | sha256sum -c -
# โโ Layer 3: Build tree (restore) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Exact hit = incremental make (only changed files recompile).
# Partial hit = more ccache warmup, still much faster than cold.
- name: Restore build tree
id: build-tree
uses: actions/cache/restore@v4
with:
path: kernel
key: kernel-tree-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-${{ env.PATCHES_HASH }}
restore-keys: |
kernel-tree-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-
kernel-tree-${{ env.FULL_VERSION }}-
# โโ Source extraction โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Only run if we have no usable build tree at all.
# Multi-threaded xz decompression cuts extraction time ~4ร.
- name: Extract kernel source
if: steps.build-tree.outputs.cache-hit != 'true'
run: |
rm -rf kernel && mkdir kernel
XZ_OPT="-T0" tar -xf "linux-${FULL_VERSION}.tar.xz" \
-C kernel --strip-components=1
# โโ Configure โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# LOCALVERSION passed to olddefconfig so it's baked into autoconf.h,
# keeping the value consistent across configure + build (ccache needs
# the same preprocessed output both times).
- name: Configure kernel
working-directory: kernel
run: |
cp ../hyperion.config .config
make olddefconfig LOCALVERSION="-Hyperion-${HYPERION_VER}"
# โโ Patches โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- name: Apply patches
working-directory: kernel
run: |
shopt -s nullglob
for patch in ../patches/*.patch; do
echo " โ applying $(basename "$patch")"
patch -p1 < "$patch"
done
# โโ Build โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# -pipe: use pipes instead of temp files between compiler passes
# bzImage only: modules are not packaged so skip the modules target to
# avoid spending ~30โ60 % of build time on unused output.
# LOCALVERSION: must match what was passed to olddefconfig above
- name: Build kernel
working-directory: kernel
run: |
make -j$(nproc) \
CC="ccache gcc" \
LOCALVERSION="-Hyperion-${HYPERION_VER}" \
KCFLAGS="-pipe" \
bzImage
# โโ ccache report โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
- name: ccache statistics
if: always()
run: ccache --show-stats --verbose
# โโ Layer 3: Build tree (save) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Always save so the next run gets the freshest incremental state.
# If key already exists GitHub skips the upload silently.
- name: Save build tree
if: success()
uses: actions/cache/save@v4
with:
path: kernel
key: kernel-tree-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-${{ env.PATCHES_HASH }}
# โโ Layer 1: ccache (save) โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# Save even on build failure so a partial run still warms future runs.
- name: Save ccache
if: always()
uses: actions/cache/save@v4
with:
path: .ccache
key: ccache-${{ runner.os }}-${{ env.FULL_VERSION }}-${{ env.CONFIG_HASH }}-${{ env.PATCHES_HASH }}-${{ github.run_id }}
# โโ Package โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
# vmlinux is excluded: it's ~600 MB unstripped and rarely needed in CI.
# Add it back if you need BTF / pahole post-processing.
- name: Package artifacts
run: |
mkdir -p artifacts
cp kernel/arch/x86/boot/bzImage artifacts/
cp kernel/System.map artifacts/
cp hyperion.config artifacts/
tar --zstd -cf "Hyperion-Kernel-${FULL_VERSION}.tar.zst" artifacts/
- name: Generate checksum
run: |
sha256sum "Hyperion-Kernel-${FULL_VERSION}.tar.zst" \
> "Hyperion-Kernel-${FULL_VERSION}.sha256"
- name: Create release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ env.TAG_NAME }}
files: |
Hyperion-Kernel-${{ env.FULL_VERSION }}.tar.zst
Hyperion-Kernel-${{ env.FULL_VERSION }}.sha256