RustForge

foundry

Foundry OS: the operating system built on the Rustbelt kernel

foundry / Makefile
6327 bytes ยท raw
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
# Foundry OS -- the single entry point. `make help` lists the targets.
#
# Everything generated goes to out/ (git-ignored); `make clean` removes it.
# Downloads (musl source etc.) go to cache/ (git-ignored, SHA256-checked).

include config.mk

OUT        := $(CURDIR)/out
IMAGE      := $(OUT)/$(IMAGE_NAME)
STAGING    := $(OUT)/staging
RUST_OUT   := $(OUT)/rust-target/x86_64-unknown-none/release
FIXTURES   := $(OUT)/fixtures
KSRC       := $(OUT)/kernel-src
KTARGET    := $(OUT)/kernel-target
KBOOT      := $(OUT)/kernel/bootimage.bin
KBOOT_HL   := $(OUT)/kernel/bootimage-headless.bin
SYSROOT    := $(OUT)/sysroot
FCC        := $(CURDIR)/toolchain/foundry-cc
C_OUT      := $(OUT)/c
# Everything in /bin, in order: the kernel's list, then Foundry OS's own.
ALL_BIN    := $(BIN_ORDER) $(FOUNDRY_C) $(FOUNDRY_PORTS)
PORTS_OUT  := $(OUT)/ports

.DEFAULT_GOAL := image
.PHONY: help image rust fixtures cprogs ports staging kernel kernel-src run test test-reference compare k1-check rbsh-test musl clean distclean

help:
	@echo "Foundry OS (userland for the Rustbelt kernel $(KERNEL_VERSION) @ $(KERNEL_REV))"
	@echo ""
	@echo "  make / make image   build out/$(IMAGE_NAME), the disk image (contract $(CONTRACT))"
	@echo "  make rust           cargo build the Rust programs in rust/"
	@echo "  make fixtures       build the kernel's ABI test programs from the pinned kernel"
	@echo "  make cprogs         build our C programs (c/) as static-PIEs with toolchain/foundry-cc"
	@echo "  make ports          fetch (cache/) + build the ports ($(FOUNDRY_PORTS)) the same way"
	@echo "  make staging        assemble out/staging (rootfs/ + /bin)"
	@echo "  make kernel         build the pinned kernel into out/kernel-target"
	@echo "  make run            boot the image in a QEMU window"
	@echo "  make test           headless boot + the shell self-test + expected-line checks"
	@echo "  make test-reference  the same headless test, but booting the kernel's own disk.img (baseline)"
	@echo "  make compare        compare out/$(IMAGE_NAME) with the kernel's own disk.img"
	@echo "  make rbsh-test      host unit tests for rbsh's parser and drive letters (no QEMU)"
	@echo "  make k1-check       build the kernel with RUSTBELT_DISK0=our image (K1) and check it boots ours"
	@echo "  make musl           fetch (cache/) + build musl $(MUSL_VERSION) into out/sysroot"
	@echo "  make clean          rm -rf out   (distclean also removes cache/)"

# ---- the pinned kernel -------------------------------------------------------
kernel-src:
	scripts/build-kernel.sh $(KERNEL_DIR) $(KERNEL_REV) $(OUT) --export-only

kernel:
	scripts/build-kernel.sh $(KERNEL_DIR) $(KERNEL_REV) $(OUT)

# ---- programs ---------------------------------------------------------------
rust:
	cd rust && CARGO_TARGET_DIR=$(OUT)/rust-target cargo build --release

fixtures: kernel-src
	scripts/build-fixtures.sh $(KSRC) $(FIXTURES) "$(FIXTURE_RUST)" "$(FIXTURE_C)" "$(FIXTURE_MUSL)"

# Our own C programs: gcc + our musl, static-PIE (docs/porting.md).
cprogs: $(SYSROOT)/lib/musl-pie.specs
	mkdir -p $(C_OUT)
	for p in $(FOUNDRY_C); do \
	    $(FCC) -O2 -Wall -Wextra -pthread -Wl,--build-id=none c/$$p.c -o $(C_OUT)/$$p || exit 1; \
	done
	@echo "[cprogs] built $(FOUNDRY_C) into $(C_OUT)"

# Ports: each one is fetched into cache/ (SHA256-checked) and built once;
# delete out/ports/bin/NAME to rebuild it.
ports: $(addprefix $(PORTS_OUT)/bin/,$(FOUNDRY_PORTS))

$(PORTS_OUT)/bin/%: $(SYSROOT)/lib/musl-pie.specs ports/%/build.sh
	ports/fetch.sh $* cache
	ports/$*/build.sh cache $(PORTS_OUT)/$*-build $@

# ---- the image ---------------------------------------------------------------
# Contract v1: rootfs/ minus etc/ (etc/ is for the contract-v2 ext2 root,
# see docs/plan.md) goes to the top of the FAT32 volume, programs to /bin.
staging: rust fixtures cprogs ports
	rm -rf $(STAGING) && mkdir -p $(STAGING)/bin
	cd rootfs && for e in $$(ls -A); do [ "$$e" = etc ] && [ "$(CONTRACT)" = v1 ] && continue; cp -r "$$e" $(STAGING)/; done
	for p in $(filter-out sh,$(RUST_PROGRAMS)); do cp $(RUST_OUT)/$$p $(STAGING)/bin/; done
	cp $(RUST_OUT)/rbsh $(STAGING)/bin/sh    # contract v1: the kernel runs /mnt/disk0/bin/sh
	cp $(FIXTURES)/* $(STAGING)/bin/
	for p in $(FOUNDRY_C); do cp $(C_OUT)/$$p $(STAGING)/bin/; done
	for p in $(FOUNDRY_PORTS); do cp $(PORTS_OUT)/bin/$$p $(STAGING)/bin/; done

image: staging
	scripts/mkimage.sh $(STAGING) $(IMAGE) $(IMAGE_MIB) $(IMAGE_LABEL) "$(ALL_BIN)"

# ---- booting ----------------------------------------------------------------
run: image kernel
	scripts/run-qemu.sh $(IMAGE) $(KBOOT) $(KTARGET) $(OUT)

# What the expected-line checks need to know about the pinned kernel.
TEST_ENV   := KERNEL_BANNER="$(KERNEL_BANNER)" KERNEL_VERSION=$(KERNEL_VERSION)

test: image kernel
	$(TEST_ENV) BIN_COUNT=$(words $(ALL_BIN)) EXTRA_EXPECT=scripts/expect-foundry.txt \
	    scripts/run-headless.sh $(IMAGE) $(KBOOT_HL) $(KTARGET) $(OUT)

# The baseline: the kernel's own disk.img through the very same checks
# (without Foundry OS's own programs and expected lines, which it lacks).
test-reference: kernel
	$(TEST_ENV) BIN_COUNT=$(words $(BIN_ORDER)) \
	    scripts/run-headless.sh $(KTARGET)/disk.img $(KBOOT_HL) $(KTARGET) $(OUT)/reference

compare: image kernel
	FOUNDRY_BIN="$(FOUNDRY_C) $(FOUNDRY_PORTS)" FOUNDRY_FILES="$(FOUNDRY_FILES)" scripts/compare-image.sh $(IMAGE) $(KTARGET)/disk.img $(OUT)

# rbsh's parser is pure Rust, so it is also tested on the host.
rbsh-test:
	mkdir -p $(OUT)/host-tests
	rustc --edition 2024 --test rust/rbsh/host-tests/parse_test.rs -o $(OUT)/host-tests/parse_test
	$(OUT)/host-tests/parse_test

# K1 (kernel 0.21.0+): the kernel's own build takes our image as disk 0.
# Uses its own target dir, so out/kernel-target (the reference) is untouched.
k1-check: image kernel-src
	scripts/k1-check.sh $(IMAGE) $(KSRC) $(OUT)/kernel-k1-target "$(RUST_PROGRAMS)"

# ---- toolchain ---------------------------------------------------------------
# musl is built once; delete out/sysroot (or run `make musl`) to rebuild it.
musl:
	toolchain/musl/fetch.sh cache
	toolchain/musl/build.sh cache $(OUT)/musl-build $(SYSROOT)

$(SYSROOT)/lib/musl-pie.specs: toolchain/musl/musl.sha256 toolchain/musl/musl-pie.specs.in toolchain/musl/build.sh
	$(MAKE) musl

clean:
	rm -rf out

distclean: clean
	rm -rf cache