-
Notifications
You must be signed in to change notification settings - Fork 152
503 lines (451 loc) · 16.9 KB
/
Copy pathmain.yml
File metadata and controls
503 lines (451 loc) · 16.9 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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
name: CI
on: [push, pull_request]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
permissions:
contents: read
jobs:
detect-code-related-file-changes:
runs-on: ubuntu-24.04
outputs:
has_code_related_changes: ${{ steps.changed-files.outputs.any_changed }}
steps:
- name: Check out the repo
uses: actions/checkout@v7
- name: Test changed files
id: changed-files
uses: tj-actions/changed-files@v47
with:
files: |
.ci/**
.github/actions/**
.github/workflows/**
build/**
configs/**
mk/**
scripts/**
src/**
tests/**
tools/**
.clang-format
Dockerfile
Makefile
# Emscripten output is platform independent, so it is built once on x64
# rather than in every host matrix leg.
wasm-build:
name: emcc build
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 30
runs-on: ubuntu-24.04
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
uses: ./.github/actions/setup-build
with:
llvm: 'false'
# No artifact prefetch: the build steps below open with "make
# distclean", which would throw away anything downloaded here.
- name: Set up emsdk
uses: mymindstorm/setup-emsdk@v16
with:
version: 3.1.51
actions-cache-folder: 'emsdk-cache'
# Note: wasm_defconfig sets CONFIG_BUILD_WASM=y which auto-selects CC=emcc
- name: Build user emulation
run: |
make distclean
make wasm_defconfig
.ci/emsdk-warm-cache.sh
make $PARALLEL
- name: Build system emulation
run: |
make distclean
make wasm_defconfig
make ENABLE_SYSTEM=1 ENABLE_GOLDFISH_RTC=1 $PARALLEL
host-x64:
name: x64 ${{ matrix.compiler }}
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
compiler: [gcc, clang]
runs-on: ubuntu-24.04
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
compiler: ${{ matrix.compiler }}
riscv-toolchain: 'true'
artifacts: elf linux-image doom
cache-suffix: host-${{ matrix.compiler }}
- name: Build with various optimization levels
run: .ci/build-opt-levels.sh defconfig
- name: Build system emulation with various optimization levels
run: .ci/build-opt-levels.sh system_defconfig
- name: check + tests
run: |
make cleanconfig
make defconfig
make check $PARALLEL
make tests $PARALLEL
make misalign $PARALLEL
make tool $PARALLEL
- name: SDL disable test
run: |
# SDL is the graphics subsystem; an interpreter-only test suffices.
make distclean && make defconfig && make ENABLE_SDL=0 check $PARALLEL
- name: misalignment test in block emulation
run: |
make -C tests/system/alignment/
make distclean && make system_defconfig && make ENABLE_ELF_LOADER=1 ENABLE_EXT_C=0 misalign-in-blk-emu $PARALLEL
- name: MMU test
run: |
make -C tests/system/mmu/
make distclean && make system_defconfig && make ENABLE_ELF_LOADER=1 mmu-test $PARALLEL
- name: gdbstub test
run: make distclean && make defconfig && make ENABLE_GDBSTUB=1 gdbstub-test $PARALLEL
- name: JIT base test
run: make distclean && make jit_defconfig && make check $PARALLEL
- name: undefined behavior test
if: success() || failure()
run: |
make distclean && make defconfig && make ENABLE_UBSAN=1 check $PARALLEL
make distclean && make jit_defconfig && make ENABLE_UBSAN=1 check $PARALLEL
# Each optional feature is independently switchable, so every one of them is
# built with the knob off. Split across runners because the serial run of all
# 24 builds dominated the job it used to live in.
host-x64-feature-disable:
name: x64 ${{ matrix.compiler }} feature disable (${{ matrix.group }})
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 45
strategy:
fail-fast: false
matrix:
compiler: [gcc, clang]
group: [core, bitmanip-perf] # .ci/test-ext-disable.sh owns the members
runs-on: ubuntu-24.04
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
compiler: ${{ matrix.compiler }}
riscv-toolchain: 'true'
artifacts: elf
cache-suffix: feature-${{ matrix.compiler }}-${{ matrix.group }}
- name: Feature disable tests (interpreter + JIT)
run: .ci/test-ext-disable.sh ${{ matrix.group }}
# The architecture test is compiler agnostic: it validates the emulator
# against the Sail model, so a second host compiler adds runtime, not
# coverage. It is x64 only, since the macOS runners are the scarcest
# resource in this workflow and provide nothing the Linux run does not.
arch-test-x64:
name: RISC-V architecture test
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 45
runs-on: ubuntu-24.04
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
compiler: gcc
llvm: 'false'
riscv-toolchain: 'true'
# No artifact prefetch: riscv-tests.sh starts with "make distclean",
# so anything cached under build/ would be thrown away unread.
- name: Set up Python
uses: actions/setup-python@v7
with:
python-version: '3.12'
cache: 'pip'
cache-dependency-path: .ci/requirements.txt
- name: Architecture test
run: .ci/riscv-tests.sh
# Boot tests are the long pole of the workflow, so each configuration gets
# its own runner. T2C is clang only because it goes through LLVM.
boot-tests-x64:
name: x64 ${{ matrix.compiler }} boot (${{ matrix.boot_type }})
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 40 # T2C boot ~30min + build ~3min + setup ~3min
strategy:
fail-fast: false
matrix:
include:
- compiler: gcc
boot_type: interpreter
defconfig: system_defconfig
make_flags: ""
timeout: 60
- compiler: gcc
boot_type: jit
defconfig: system_defconfig
make_flags: "ENABLE_JIT=1 ENABLE_MOP_FUSION=0"
timeout: 120
- compiler: clang
boot_type: interpreter
defconfig: system_defconfig
make_flags: ""
timeout: 60
- compiler: clang
boot_type: jit
defconfig: system_defconfig
make_flags: "ENABLE_JIT=1 ENABLE_MOP_FUSION=0"
timeout: 120
- compiler: clang
boot_type: t2c
defconfig: system_jit_defconfig
make_flags: "ENABLE_MOP_FUSION=0"
timeout: 150
runs-on: ubuntu-24.04
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
compiler: ${{ matrix.compiler }}
llvm: ${{ matrix.compiler == 'clang' }}
artifacts: linux-image
cache-suffix: boot-${{ matrix.compiler }}-${{ matrix.boot_type }}
- name: boot Linux kernel test (${{ matrix.boot_type }})
env:
BOOT_TIMEOUT: ${{ matrix.timeout }}
run: |
# A stale object would mask a failed LLVM detection below.
rm -f build/t2c.o
make distclean && make ${{ matrix.defconfig }} && make INITRD_SIZE=32 ${{ matrix.make_flags }} $PARALLEL && make artifact $PARALLEL
if [ "${{ matrix.boot_type }}" = "t2c" ]; then
test -f build/t2c.o || { echo "ERROR: T2C disabled (build/t2c.o missing) - LLVM $(cat .ci/llvm-version) detection failed"; exit 1; }
fi
.ci/boot-linux-test.sh
# Native AArch64 on GitHub ARM runners - fast, no QEMU overhead
# FIXME: gcc build fails on AArch64/Linux hosts, hence clang only
host-arm64:
name: arm64 clang
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 45
runs-on: ubuntu-24.04-arm
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: checkout code
uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
# Plain "clang" resolves through the LLVM bin directory this action
# prepends to PATH, so it is the pinned LLVM, not the distro's.
cc: clang
artifacts: elf linux-image
cache-suffix: host
- name: check + tests
run: |
make cleanconfig
make defconfig
make check $PARALLEL
- name: JIT tests
run: |
set -euo pipefail
make distclean && make jit_defconfig && make check $PARALLEL
for ext in ENABLE_EXT_A ENABLE_EXT_F ENABLE_EXT_C; do
echo "JIT test with ${ext}=0"
make ENABLE_JIT=1 clean && make ${ext}=0 ENABLE_JIT=1 check $PARALLEL
done
- name: boot Linux kernel test (T2C)
env:
BOOT_TIMEOUT: 120 # T2C with O1 optimization (via defconfig) is faster than O3
run: |
# A stale object would mask a failed LLVM detection below.
rm -f build/t2c.o
# system_jit_defconfig uses T2C_OPT_LEVEL=1 for ~50% faster LLVM compilation
make distclean && make system_jit_defconfig && make INITRD_SIZE=32 ENABLE_MOP_FUSION=0 $PARALLEL && make artifact $PARALLEL
test -f build/t2c.o || { echo "ERROR: T2C disabled (build/t2c.o missing) - LLVM ${{ steps.setup.outputs.llvm-version }} detection failed"; exit 1; }
.ci/boot-linux-test.sh
macOS-arm64:
name: macOS ${{ matrix.compiler }}
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
compiler: [gcc-15, clang]
runs-on: macos-latest # M1 chip
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
compiler: ${{ matrix.compiler }}
riscv-toolchain: 'true'
artifacts: elf linux-image doom
cache-suffix: host-${{ matrix.compiler }}
- name: check + tests
run: |
make cleanconfig
make defconfig
make check $PARALLEL
make tests $PARALLEL
make misalign $PARALLEL
make tool $PARALLEL
- name: SDL disable test
run: |
# SDL is the graphics subsystem; an interpreter-only test suffices.
make distclean && make defconfig && make ENABLE_SDL=0 check $PARALLEL
- name: gdbstub test, need RV32 toolchain
run: make distclean && make defconfig && make ENABLE_GDBSTUB=1 gdbstub-test $PARALLEL
- name: JIT base test
run: make distclean && make jit_defconfig && make check $PARALLEL
- name: undefined behavior test
# gcc on macOS/arm64 does not support sanitizers
if: (success() || failure()) && matrix.compiler == 'clang'
run: |
make distclean && make defconfig && make ENABLE_UBSAN=1 check $PARALLEL
make distclean && make jit_defconfig && make ENABLE_UBSAN=1 check $PARALLEL
- name: boot Linux kernel test
run: |
make distclean && make system_defconfig && make INITRD_SIZE=32 $PARALLEL && make artifact $PARALLEL
.ci/boot-linux-test.sh
make clean
- name: boot Linux kernel test (JIT)
env:
BOOT_TIMEOUT: 120 # JIT under macOS load has flaked at 90s
run: |
make distclean && make system_defconfig && make INITRD_SIZE=32 ENABLE_JIT=1 ENABLE_MOP_FUSION=0 $PARALLEL && make artifact $PARALLEL
.ci/boot-linux-test.sh
make clean
macOS-arm64-feature-disable:
name: macOS ${{ matrix.compiler }} feature disable
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
compiler: [gcc-15, clang]
runs-on: macos-latest
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up build environment
id: setup
uses: ./.github/actions/setup-build
with:
compiler: ${{ matrix.compiler }}
riscv-toolchain: 'true'
artifacts: elf
cache-suffix: feature-${{ matrix.compiler }}
- name: Feature disable tests (interpreter + JIT)
run: .ci/test-ext-disable.sh
coding-style:
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 15
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
- name: Install formatters
run: .ci/install-formatters.sh
- name: coding convention
run: |
.ci/check-newline.sh
.ci/check-format.sh
static-analysis:
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 45
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v7
with:
submodules: 'true'
# scan-build lives in clang-tools-<N>, and the analyzer resolves the
# versioned clang-<N>/scan-build-<N> names from /usr/bin. Those are apt
# symlinks outside /usr/lib/llvm-<N>, so the LLVM cache the other jobs use
# would restore the tree without the names this job calls: install fresh.
- name: Set up scan-build
run: |
LLVM_VERSION=$(cat .ci/llvm-version)
.ci/apt-install.sh curl wget lsb-release gnupg libsdl2-dev libsdl2-mixer-dev
sudo .ci/install-llvm.sh "${LLVM_VERSION}"
sudo apt-get install -y -q=2 "clang-${LLVM_VERSION}" "clang-tools-${LLVM_VERSION}"
- name: Run scan-build
run: .ci/scan-build.sh
# https://docs.docker.com/build/ci/github-actions/multi-platform/
docker-hub-build-and-publish:
needs: [detect-code-related-file-changes]
if: needs.detect-code-related-file-changes.outputs.has_code_related_changes == 'true'
timeout-minutes: 60
runs-on: ubuntu-24.04
steps:
- name: Check out the repo
uses: actions/checkout@v7
with:
submodules: 'true'
- name: Set up QEMU
uses: docker/setup-qemu-action@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v4
- name: Login to Docker Hub
uses: docker/login-action@v4
if: github.event_name == 'push'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_ACCESS_TOKEN }}
- name: Get short commit SHA1
if: github.event_name == 'push'
run: echo "short_hash=$(git rev-parse --short "$GITHUB_SHA")" >> "$GITHUB_ENV"
- name: Build and push
if: github.event_name == 'push'
uses: docker/build-push-action@v7
with:
push: true
context: .
platforms: linux/amd64,linux/arm64/v8
tags: sysprog21/rv32emu:latest, sysprog21/rv32emu:${{ env.short_hash }}
cache-from: type=gha
cache-to: type=gha,mode=max