-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuild.sh
More file actions
executable file
·754 lines (659 loc) · 25.3 KB
/
build.sh
File metadata and controls
executable file
·754 lines (659 loc) · 25.3 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
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
#!/bin/bash
# TuringOS 构建脚本
#
# 用法:
# ./build.sh [--board <board>] <target>
#
# 目标板 (--board):
# rpi4 - Raspberry Pi 4B, ARM64 (默认)
# bbb - BeagleBone Black, AM335x ARM (真实硬件)
# virt - QEMU ARM Virt, Cortex-A15 (开发测试推荐)
#
# 构建目标:
# all - 完整构建 (内核 + L4Re + 引导镜像 + 收集产物)
# kernel - 仅构建 Fiasco 内核
# l4re - 仅构建 L4Re 运行时
# bootstrap - 仅生成引导镜像 (需先完成 kernel 和 l4re)
# collect - 收集构建产物到 build/artifacts 目录
# menuconfig - 交互式驱动配置菜单
# defconfig - 使用默认驱动配置
# clean - 清理编译中间文件
# cleanall - 完全清理构建目录
#
# 示例:
# ./build.sh # 默认 RPi4 全量构建
# ./build.sh --board virt all # QEMU virt 全量构建
# ./build.sh --board bbb kernel # BeagleBone Black 构建内核
# ./build.sh --board virt collect # 仅收集 virt 构建产物
#
# 快速开始 (QEMU 测试):
# ./build.sh --board virt all # 构建
# ./run_qemu_virt.sh # 运行
set -e
# macOS 自带 Make 3.81 太旧,优先使用 Homebrew 的 GNU Make 4+
if command -v gmake &>/dev/null; then
MAKE=gmake
else
MAKE=make
fi
PROJ_ROOT="$(cd "$(dirname "$0")" && pwd)"
KERNEL_DIR="$PROJ_ROOT/kernel"
CONF_DIR="$PROJ_ROOT/conf"
BUILD_OUT="$PROJ_ROOT/build"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
info() { echo -e "${GREEN}>>> $1${NC}"; }
warn() { echo -e "${YELLOW}!!! $1${NC}"; }
error() { echo -e "${RED}*** $1${NC}"; exit 1; }
# ============================================================
# 目标板配置
# ============================================================
setup_board() {
local board="$1"
case "$board" in
rpi4)
BOARD_NAME="Raspberry Pi 4B"
BOARD_ARCH="ARM64"
export CROSS_COMPILE="${CROSS_COMPILE:-aarch64-elf-}"
KERNEL_BUILD="$BUILD_OUT/kernel_arm64"
KERNEL_TEMPLATE="arm64-rpi4"
L4RE_BUILD="$BUILD_OUT/l4re_arm64"
L4RE_TEMPLATE="arm64-rv-v8a"
QEMU_CMD="qemu-system-aarch64"
;;
bbb)
BOARD_NAME="BeagleBone Black (AM335x)"
BOARD_ARCH="ARM"
export CROSS_COMPILE="${CROSS_COMPILE:-arm-linux-gnueabihf-}"
# macOS: brew 安装的工具链不在默认 PATH 中
local _arm_brew_prefix
_arm_brew_prefix="$(brew --prefix arm-unknown-linux-gnueabihf 2>/dev/null)"
if [ -n "$_arm_brew_prefix" ] && [ -d "$_arm_brew_prefix/bin" ]; then
export PATH="$_arm_brew_prefix/bin:$PATH"
fi
KERNEL_BUILD="$BUILD_OUT/kernel_arm"
KERNEL_TEMPLATE="arm-omap3-am33xx"
L4RE_BUILD="$BUILD_OUT/l4re_arm"
L4RE_TEMPLATE="arm-omap3-am33xx"
QEMU_CMD="" # AM335x 无 QEMU 支持
;;
virt)
BOARD_NAME="QEMU ARM Virt (Cortex-A15)"
BOARD_ARCH="ARM"
export CROSS_COMPILE="${CROSS_COMPILE:-arm-linux-gnueabihf-}"
# macOS: brew 安装的工具链不在默认 PATH 中
local _arm_brew_prefix
_arm_brew_prefix="$(brew --prefix arm-unknown-linux-gnueabihf 2>/dev/null)"
if [ -n "$_arm_brew_prefix" ] && [ -d "$_arm_brew_prefix/bin" ]; then
export PATH="$_arm_brew_prefix/bin:$PATH"
fi
KERNEL_BUILD="$BUILD_OUT/kernel_virt"
KERNEL_TEMPLATE="arm-virt-pl1"
L4RE_BUILD="$BUILD_OUT/l4re_virt"
L4RE_TEMPLATE="arm-virt-v7a"
QEMU_CMD="qemu-system-arm -M virt -cpu cortex-a15"
;;
*)
error "未知目标板: $board
支持的目标板:
rpi4 Raspberry Pi 4B (ARM64, 默认)
bbb BeagleBone Black (AM335x, ARM)"
;;
esac
}
# ============================================================
# 检查构建依赖
# ============================================================
check_deps() {
info "检查构建依赖..."
# 检查交叉编译工具链
if ! command -v "${CROSS_COMPILE}gcc" &>/dev/null; then
case "$BOARD" in
bbb)
error "找不到交叉编译器: ${CROSS_COMPILE}gcc
请安装 ARM Linux 工具链:
macOS: brew tap messense/macos-cross-toolchains && brew install arm-unknown-linux-gnueabihf
Ubuntu: sudo apt install gcc-arm-linux-gnueabihf
Fedora: sudo dnf install gcc-arm-linux-gnu
或设置 CROSS_COMPILE 环境变量指向你的工具链前缀:
export CROSS_COMPILE=arm-linux-gnueabihf-"
;;
*)
error "找不到交叉编译器: ${CROSS_COMPILE}gcc
请安装 aarch64 工具链:
macOS: brew install aarch64-elf-gcc (或使用 aarch64-linux-gnu- 前缀的工具链)
Ubuntu: sudo apt install gcc-aarch64-linux-gnu
Fedora: sudo dnf install gcc-aarch64-linux-gnu
或设置 CROSS_COMPILE 环境变量指向你的工具链前缀:
export CROSS_COMPILE=aarch64-none-elf-"
;;
esac
fi
# 检查 make
if ! command -v $MAKE &>/dev/null; then
error "找不到 $MAKE,请先安装 GNU Make 4+"
fi
# 检查 perl (内核构建需要)
if ! command -v perl &>/dev/null; then
error "找不到 perl,内核构建需要它"
fi
# 检查 qemu (可选,仅用于运行)
if [ -n "$QEMU_CMD" ] && ! command -v "$QEMU_CMD" &>/dev/null; then
warn "找不到 $QEMU_CMD,构建可以继续但无法运行"
fi
# 检查 flex/bison (kconfig 工具构建需要)
if ! command -v flex &>/dev/null; then
warn "找不到 flex,menuconfig 功能需要它"
fi
if ! command -v bison &>/dev/null; then
warn "找不到 bison,menuconfig 功能需要它"
fi
info "依赖检查通过"
}
# ============================================================
# 初始化 Git 子模块
# ============================================================
init_submodules() {
info "检查 Git 子模块..."
cd "$PROJ_ROOT"
if [ ! -f "$KERNEL_DIR/Makefile" ] || [ ! -f "$PROJ_ROOT/l4re/Makefile" ]; then
info "初始化 Git 子模块..."
git submodule update --init --recursive
fi
}
# ============================================================
# 构建 Fiasco 内核
# ============================================================
build_kernel() {
info "构建 Fiasco 内核 (模板: $KERNEL_TEMPLATE)..."
cd "$KERNEL_DIR"
# 检查 build 目录的 Makefile 中 srcdir 是否正确
local need_rebuild=0
if [ -f "$KERNEL_BUILD/Makefile" ]; then
if ! grep -qF "srcdir := $KERNEL_DIR/src" "$KERNEL_BUILD/Makefile"; then
warn "内核构建目录的源码路径过期,将重新创建"
need_rebuild=1
fi
else
need_rebuild=1
fi
if [ "$need_rebuild" -eq 1 ]; then
rm -rf "$KERNEL_BUILD"
mkdir -p "$(dirname "$KERNEL_BUILD")"
info "创建内核构建目录 (模板: $KERNEL_TEMPLATE)..."
$MAKE BUILDDIR="$KERNEL_BUILD" T="$KERNEL_TEMPLATE"
fi
# 编译内核
info "编译内核..."
$MAKE -C "$KERNEL_BUILD" -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"
if [ -f "$KERNEL_BUILD/fiasco" ]; then
info "内核已编译: $KERNEL_BUILD/fiasco"
else
error "内核编译失败: 找不到 fiasco 二进制文件"
fi
}
# ============================================================
# 构建 L4Re 运行时环境
# ============================================================
build_l4re() {
info "构建 L4Re 运行时环境..."
local l4mk_dir="$PROJ_ROOT/l4mk"
# 在 l4mk/pkg/ 下创建指向 l4re-core 和 pkg/ 下各包的符号链接
local l4mk_pkg="$PROJ_ROOT/l4mk/pkg"
if [ ! -e "$l4mk_pkg/l4re-core" ]; then
ln -s ../../l4re "$l4mk_pkg/l4re-core"
info "创建符号链接: l4mk/pkg/l4re-core -> ../../l4re"
fi
# 为 pkg/ 下每个包逐个创建符号链接
for pkg_dir in "$PROJ_ROOT"/pkg/*/; do
local pkg_name="$(basename "$pkg_dir")"
if [ ! -e "$l4mk_pkg/$pkg_name" ]; then
ln -s "../../pkg/$pkg_name" "$l4mk_pkg/$pkg_name"
info "创建符号链接: l4mk/pkg/$pkg_name -> ../../pkg/$pkg_name"
fi
done
# project.mk 的 find 命令不会跟随符号链接来发现 prj-config/aliases.d,
# 需要将各子项目的别名文件合并到 l4mk/mk/aliases.d/ (该目录已在搜索路径中).
# 多个包可能有同名的别名文件 (如 05-compiler-rt), 需要合并而非覆盖
local aliases_dst="$PROJ_ROOT/l4mk/mk/aliases.d"
local alias_dirs
alias_dirs=$(find "$PROJ_ROOT/l4re" "$PROJ_ROOT/pkg" \
-maxdepth 5 -type d -name aliases.d \
-path "*/prj-config/aliases.d" 2>/dev/null || true)
local aliases_changed=0
for adir in $alias_dirs; do
for f in "$adir"/*; do
[ -f "$f" ] || continue
local fname="$(basename "$f")"
local dst="$aliases_dst/$fname"
if [ ! -e "$dst" ]; then
cp "$f" "$dst"
aliases_changed=1
else
# 检查是否有尚未包含的别名定义行 (非注释、非空行)
local need_merge=0
while IFS= read -r line; do
[ -z "$line" ] && continue
case "$line" in \#*) continue ;; esac
if ! grep -qF "$line" "$dst" 2>/dev/null; then
need_merge=1
break
fi
done < "$f"
if [ "$need_merge" -eq 1 ]; then
echo "" >> "$dst"
cat "$f" >> "$dst"
aliases_changed=1
fi
fi
done
done
if [ "$aliases_changed" -eq 1 ]; then
info "已合并包别名定义到 l4mk/mk/aliases.d/"
fi
# 生成 Makeconf.local: 修复符号链接导致的路径问题
# make -C 会解析符号链接, 导致 CURDIR 指向物理路径 (l4re/、pkg/drivers/),
# 而非逻辑路径 (l4mk/pkg/l4re-core/、l4mk/pkg/drivers/).
# 这使得包被误判为 "external package", 构建产物路径错误.
# 此 Makeconf.local 将物理路径重映射回 l4mk/pkg/ 下的逻辑路径.
local makeconf_local="$l4mk_dir/Makeconf.local"
if [ ! -e "$makeconf_local" ]; then
cat > "$makeconf_local" << 'MAKECONF_EOF'
# Auto-generated by build.sh — DO NOT EDIT
# Remap symlinked package paths back to l4mk/pkg/ logical paths
#
# Problem: make -C resolves symlinks, so packages accessed via
# l4mk/pkg/l4re-core -> ../../l4re
# l4mk/pkg/drivers -> ../../pkg/drivers
# end up with CURDIR pointing to the physical path (l4re/*, pkg/drivers/*).
# This causes the build system to treat them as "external packages".
# Fix: remap CURDIR-based variables back to l4mk/pkg/ logical paths.
# Export absolute L4DIR so sub-makes through symlinked paths get the correct
# value instead of computing it from broken relative paths.
L4DIR := $(abspath $(L4DIR))
export L4DIR
export CROSS_COMPILE
ifdef OBJ_BASE
_L4_ABS := $(abspath $(L4DIR))
_PRJ := $(abspath $(L4DIR)/..)
# Skip remapping if we're inside the build directory (OBJ_BASE)
ifeq ($(patsubst $(OBJ_BASE)/%,,$(CURDIR)),$(CURDIR))
# l4re/<pkg>/ → l4mk/pkg/l4re-core/<pkg>/
ifneq ($(patsubst $(_PRJ)/l4re/%,,$(CURDIR)),$(CURDIR))
_REL := $(patsubst $(_PRJ)/l4re/%,%,$(CURDIR))
SRC_DIR := $(_L4_ABS)/pkg/l4re-core/$(_REL)
PKGDIR_ABS := $(abspath $(SRC_DIR)/$(PKGDIR))
OBJ_DIR := $(OBJ_BASE)/pkg/l4re-core/$(_REL)
PKGDIR_OBJ := $(abspath $(OBJ_DIR)/$(PKGDIR))
L4DIR := $(_L4_ABS)
endif
# pkg/<name>/... → l4mk/pkg/<name>/...
ifneq ($(patsubst $(_PRJ)/pkg/%,,$(CURDIR)),$(CURDIR))
_REL := $(patsubst $(_PRJ)/pkg/%,%,$(CURDIR))
SRC_DIR := $(_L4_ABS)/pkg/$(_REL)
PKGDIR_ABS := $(abspath $(SRC_DIR)/$(PKGDIR))
OBJ_DIR := $(OBJ_BASE)/pkg/$(_REL)
PKGDIR_OBJ := $(abspath $(OBJ_DIR)/$(PKGDIR))
L4DIR := $(_L4_ABS)
endif
endif
endif
MAKECONF_EOF
info "生成 l4mk/Makeconf.local (路径重映射)"
fi
# 检查构建目录是否存在且配置完整
if [ ! -d "$L4RE_BUILD" ] || [ ! -f "$L4RE_BUILD/.config.all" ]; then
if [ -d "$L4RE_BUILD" ] && [ ! -f "$L4RE_BUILD/.config.all" ]; then
warn "构建目录存在但配置不完整,重新初始化..."
rm -rf "$L4RE_BUILD"
fi
info "创建 L4Re 构建目录 (模板: $L4RE_TEMPLATE)..."
# PLATFORM_TYPE 应该与模板名称对应,从 defconfig 文件中提取
# 但由于 defconfig 已包含正确的 PLATFORM_TYPE,我们传递空值以避免重复
$MAKE -C "$l4mk_dir" B="$L4RE_BUILD" T="$L4RE_TEMPLATE" PLATFORM_TYPE= CROSS_COMPILE="${CROSS_COMPILE}"
# 验证配置文件是否正确生成
if [ ! -f "$L4RE_BUILD/.config.all" ]; then
warn "配置文件未自动生成,手动运行 olddefconfig..."
$MAKE -C "$l4mk_dir" O="$L4RE_BUILD" CROSS_COMPILE="${CROSS_COMPILE}" olddefconfig
fi
# 再次验证
if [ ! -f "$L4RE_BUILD/.config.all" ]; then
error "L4Re 构建目录配置失败,请检查构建环境"
fi
info "L4Re 构建目录已初始化"
fi
cd "$L4RE_BUILD"
# 传递绝对 L4DIR 以避免符号链接解析导致的相对路径错误:
# 包的 Makefile 使用 L4DIR ?= $(PKGDIR)/../../.. 来定位构建系统,
# 但 make -C 会解析符号链接, 导致相对路径失效
# 同时传递 CROSS_COMPILE 确保编译器一致性
$MAKE L4DIR="$l4mk_dir" CROSS_COMPILE="${CROSS_COMPILE}" -j"$(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)"
info "L4Re 构建完成"
}
# ============================================================
# 生成引导镜像 (bootstrap.elf)
# ============================================================
build_bootstrap() {
info "生成引导镜像..."
if [ ! -d "$L4RE_BUILD" ]; then
error "L4Re 构建目录不存在,请先构建 L4Re"
fi
if [ ! -f "$KERNEL_BUILD/fiasco" ]; then
error "内核尚未编译,请先构建内核"
fi
# 设置模块搜索路径: 内核构建目录 + 配置文件
export MODULE_SEARCH_PATH="$KERNEL_BUILD:$CONF_DIR"
# 选择启动入口 (可通过环境变量 ENTRY 覆盖)
# 可用入口: fiasco-base-test, shell, demo
local entry="${ENTRY:-demo}"
info "使用启动入口: $entry"
cd "$L4RE_BUILD"
$MAKE E="$entry" elfimage
# 复制引导镜像到输出目录
if [ -f "$L4RE_BUILD/images/bootstrap.elf" ]; then
cp "$L4RE_BUILD/images/bootstrap.elf" "$BUILD_OUT/"
info "引导镜像已生成: $BUILD_OUT/bootstrap.elf"
if [ -n "$QEMU_CMD" ]; then
info "可使用 ./run_qemu.sh 启动系统"
else
info "BBB 需要真机部署: 通过 U-Boot 从 SD 卡加载"
fi
else
error "引导镜像生成失败"
fi
}
# ============================================================
# 清理构建产物
# ============================================================
do_clean() {
local clean_type="${1:-full}"
if [ "$clean_type" = "full" ]; then
info "完全清理构建产物..."
# 清理内核构建目录
if [ -d "$KERNEL_BUILD" ]; then
info " 清理内核构建目录: $KERNEL_BUILD"
rm -rf "$KERNEL_BUILD"
fi
# 清理 L4Re 构建目录
if [ -d "$L4RE_BUILD" ]; then
info " 清理 L4Re 构建目录: $L4RE_BUILD"
rm -rf "$L4RE_BUILD"
fi
# 清理 artifacts 目录
if [ -d "$BUILD_OUT/artifacts" ]; then
info " 清理 artifacts 目录"
rm -rf "$BUILD_OUT/artifacts"
fi
# 清理 bootstrap.elf
if [ -f "$BUILD_OUT/bootstrap.elf" ]; then
info " 清理 bootstrap.elf"
rm -f "$BUILD_OUT/bootstrap.elf"
fi
# 清理 .config 文件
if [ -f "$BUILD_OUT/.config" ]; then
rm -f "$BUILD_OUT/.config" "$BUILD_OUT/.config.old"
fi
else
# 轻度清理:只清理编译中间文件
info "轻度清理(保留构建目录结构)..."
# 清理内核
if [ -d "$KERNEL_BUILD" ]; then
info " 清理内核中间文件"
$MAKE -C "$KERNEL_BUILD" clean 2>/dev/null || true
fi
# 清理 L4Re
if [ -d "$L4RE_BUILD" ]; then
info " 清理 L4Re 中间文件"
$MAKE -C "$L4RE_BUILD" clean 2>/dev/null || true
fi
# 清理 bootstrap.elf
if [ -f "$BUILD_OUT/bootstrap.elf" ]; then
rm -f "$BUILD_OUT/bootstrap.elf"
fi
fi
info "清理完成"
}
# ============================================================
# 收集构建产物
# ============================================================
collect_artifacts() {
info "收集构建产物到 $BUILD_OUT/artifacts/..."
local artifacts_dir="$BUILD_OUT/artifacts"
mkdir -p "$artifacts_dir"
# 收集内核
if [ -f "$KERNEL_BUILD/fiasco" ]; then
cp "$KERNEL_BUILD/fiasco" "$artifacts_dir/fiasco-${BOARD}"
info "✓ 内核: fiasco-${BOARD}"
fi
# 收集 bootstrap
local bootstrap_dir="$L4RE_BUILD/bin/arm_armv7a/plain"
if [ "$BOARD" = "rpi4" ]; then
bootstrap_dir="$L4RE_BUILD/bin/arm_armv8a/plain"
fi
if [ -f "$bootstrap_dir/bootstrap.elf" ]; then
cp "$bootstrap_dir/bootstrap.elf" "$artifacts_dir/bootstrap-${BOARD}.elf"
info "✓ Bootstrap ELF: bootstrap-${BOARD}.elf"
fi
if [ -f "$bootstrap_dir/bootstrap.raw" ] || [ -L "$bootstrap_dir/bootstrap.raw" ]; then
cp -L "$bootstrap_dir/bootstrap.raw" "$artifacts_dir/bootstrap-${BOARD}.raw" 2>/dev/null || true
info "✓ Bootstrap RAW: bootstrap-${BOARD}.raw"
fi
# 收集完整的引导镜像(需要先运行 build_bootstrap)
if [ -f "$L4RE_BUILD/images/bootstrap.elf" ]; then
cp "$L4RE_BUILD/images/bootstrap.elf" "$artifacts_dir/bootstrap-image-${BOARD}.elf"
info "✓ Bootstrap 完整镜像: bootstrap-image-${BOARD}.elf"
else
warn "✗ Bootstrap 完整镜像未找到 (需要运行: ./build.sh --board ${BOARD} bootstrap)"
fi
# 收集 build 根目录下的 bootstrap.elf(如果存在)
if [ -f "$BUILD_OUT/bootstrap.elf" ]; then
cp "$BUILD_OUT/bootstrap.elf" "$artifacts_dir/bootstrap-final-${BOARD}.elf"
info "✓ 最终引导镜像: bootstrap-final-${BOARD}.elf"
fi
# 创建说明文件
cat > "$artifacts_dir/README.md" << EOF
# TuringOS 构建产物
构建时间: $(date)
目标板: $BOARD_NAME ($BOARD_ARCH)
交叉编译器: ${CROSS_COMPILE}gcc
## 文件列表
### 内核
EOF
if [ -f "$artifacts_dir/fiasco-${BOARD}" ]; then
echo "- \`fiasco-${BOARD}\` - Fiasco 微内核" >> "$artifacts_dir/README.md"
fi
cat >> "$artifacts_dir/README.md" << EOF
### Bootstrap
EOF
if [ -f "$artifacts_dir/bootstrap-${BOARD}.elf" ]; then
echo "- \`bootstrap-${BOARD}.elf\` - Bootstrap 引导加载器 (ELF 格式)" >> "$artifacts_dir/README.md"
fi
if [ -f "$artifacts_dir/bootstrap-${BOARD}.raw" ]; then
echo "- \`bootstrap-${BOARD}.raw\` - Bootstrap 引导加载器 (RAW 二进制格式)" >> "$artifacts_dir/README.md"
fi
if [ -f "$artifacts_dir/bootstrap-image-${BOARD}.elf" ]; then
echo "- \`bootstrap-image-${BOARD}.elf\` - 包含所有模块的完整引导镜像" >> "$artifacts_dir/README.md"
fi
if [ -f "$artifacts_dir/bootstrap-final-${BOARD}.elf" ]; then
echo "- \`bootstrap-final-${BOARD}.elf\` - 最终引导镜像(包含内核和模块)" >> "$artifacts_dir/README.md"
fi
cat >> "$artifacts_dir/README.md" << EOF
## 使用方法
### BeagleBone Black (AM335x)
1. 将 SD 卡格式化为 FAT32
2. 复制 \`bootstrap-${BOARD}.raw\` 到 SD 卡
3. 通过 U-Boot 加载:
\`\`\`
fatload mmc 0 0x80000000 bootstrap-${BOARD}.raw
go 0x80000000
\`\`\`
### Raspberry Pi 4
1. 准备 SD 卡并安装固件
2. 复制 \`bootstrap-${BOARD}.elf\` 到 boot 分区
3. 配置 config.txt 使用该内核
## 生成完整镜像
如果需要包含所有模块的完整引导镜像,请运行:
\`\`\`bash
./build.sh --board ${BOARD} bootstrap
\`\`\`
这将生成 \`bootstrap-image-${BOARD}.elf\` 和 \`bootstrap-final-${BOARD}.elf\`
---
自动生成于 $(date +"%Y-%m-%d %H:%M:%S")
EOF
info "构建产物已收集到: $artifacts_dir"
ls -lh "$artifacts_dir"
}
# ============================================================
# 驱动配置
# ============================================================
check_config() {
if [ ! -f "$BUILD_OUT/.config" ]; then
warn "驱动配置文件 (build/.config) 不存在"
info "使用默认配置 (defconfig) ..."
$MAKE -C "$PROJ_ROOT" defconfig
fi
}
# 将配置同步到 L4Re 构建目录
sync_config_to_l4re() {
local auto_conf="$BUILD_OUT/include/config/auto.conf"
local autoconf_h="$BUILD_OUT/include/generated/autoconf.h"
# 确保 auto.conf 存在 (syncconfig 已在 defconfig/menuconfig 中自动执行)
if [ ! -f "$auto_conf" ]; then
info "生成 auto.conf ..."
$MAKE -C "$PROJ_ROOT" syncconfig
fi
# 如果 L4Re 构建目录存在,复制配置文件进去
if [ -d "$L4RE_BUILD" ]; then
info "同步驱动配置到 L4Re 构建目录..."
mkdir -p "$L4RE_BUILD/include/config"
mkdir -p "$L4RE_BUILD/include/generated"
cp "$auto_conf" "$L4RE_BUILD/include/config/auto.conf"
cp "$autoconf_h" "$L4RE_BUILD/include/generated/autoconf.h"
# 复制依赖跟踪用的空文件 (用于 make 增量构建)
if [ -d "$BUILD_OUT/include/config" ]; then
find "$BUILD_OUT/include/config" -maxdepth 1 -type f ! -name 'auto.conf*' \
-exec cp {} "$L4RE_BUILD/include/config/" \;
fi
info "驱动配置已同步"
fi
}
do_menuconfig() {
info "启动驱动配置菜单..."
$MAKE -C "$PROJ_ROOT" menuconfig
}
# ============================================================
# 主流程
# ============================================================
main() {
# 解析 --board 参数
local board="rpi4"
local target=""
while [[ $# -gt 0 ]]; do
case "$1" in
--board)
board="$2"
shift 2
;;
-h|--help)
show_usage
exit 0
;;
*)
target="$1"
shift
;;
esac
done
target="${target:-all}"
# 设置目标板相关变量
BOARD="$board"
setup_board "$board"
echo "========================================"
echo " TuringOS 构建系统"
echo " 目标板: $BOARD_NAME ($BOARD_ARCH)"
echo " 交叉编译器: ${CROSS_COMPILE}gcc"
echo "========================================"
case "$target" in
all)
check_deps
init_submodules
check_config
sync_config_to_l4re
build_kernel
build_l4re
build_bootstrap
collect_artifacts
;;
kernel)
check_deps
init_submodules
build_kernel
collect_artifacts
;;
l4re)
check_deps
check_config
sync_config_to_l4re
build_l4re
collect_artifacts
;;
bootstrap)
build_bootstrap
collect_artifacts
;;
collect)
collect_artifacts
;;
menuconfig)
do_menuconfig
;;
defconfig)
$MAKE -C "$PROJ_ROOT" defconfig
;;
clean)
do_clean "light"
;;
cleanall)
do_clean "full"
;;
*)
show_usage
exit 1
;;
esac
info "构建完成!"
}
show_usage() {
echo "用法: $0 [--board <board>] {all|kernel|l4re|bootstrap|collect|menuconfig|defconfig|clean|cleanall}"
echo ""
echo "目标板 (--board):"
echo " rpi4 Raspberry Pi 4B, ARM64 (默认)"
echo " bbb BeagleBone Black, AM335x ARM"
echo " virt QEMU ARM Virt (Cortex-A15)"
echo ""
echo "构建目标:"
echo " all 完整构建 (内核 + L4Re + 引导镜像 + 收集产物)"
echo " kernel 仅构建 Fiasco 内核"
echo " l4re 仅构建 L4Re 运行时"
echo " bootstrap 仅生成引导镜像 (需先完成 kernel 和 l4re)"
echo " collect 收集构建产物到 build/artifacts 目录"
echo " menuconfig 交互式驱动配置菜单"
echo " defconfig 使用默认驱动配置"
echo " clean 清理编译中间文件(保留构建目录结构)"
echo " cleanall 完全清理构建目录(删除 build/kernel_* 和 build/l4re_*)"
echo ""
echo "示例:"
echo " $0 # 默认 RPi4 全量构建"
echo " $0 --board bbb l4re # 为 BBB 构建 L4Re"
echo " $0 --board bbb all # BBB 全量构建"
echo " $0 --board bbb collect # 仅收集 BBB 构建产物"
echo ""
echo "环境变量:"
echo " CROSS_COMPILE 交叉编译器前缀 (会根据 --board 自动设置)"
echo ""
echo "构建产物将收集到: build/artifacts/"
}
main "$@"