Build and tools work on Linux, macOS and BSD as well as Windows
Developed from both Windows and Linux, so nothing in the build should care which host it runs on. It did, in four places. Toolchain: one path instead of two. clang is a cross-compiler by construction, so a single LLVM install targets bare-metal ELF, 16/32-bit code below 1 MB, and Linux/musl userland from any host -- which is how the Windows build already worked. The GNU branch beside it had drifted into passing --no-warn-rwx-segments, a hard error on lld, which is the default linker on both FreeBSD and macOS; and it required a brewed x86_64-elf-gcc before anything built on a Mac at all. GNU is kept as a fallback (USE_GNU=1) but clang+lld is chosen whenever both are present. Host tools use the host's own cc; only mingw needs naming explicitly. tools/mkschfs.c included <sys/sysmacros.h> unconditionally on non-mingw hosts. That header is glibc/musl only -- macOS and the BSDs have neither the header nor a need for it, since major()/minor() come from <sys/types.h> there. Now guarded on __linux__. Ports verified tarballs with `sha256sum -c -`, which does not exist on macOS (shasum), FreeBSD/NetBSD (sha256), or OpenBSD (cksum -a sha256), and each spells its check mode differently. tools/sha256check.sh picks whichever of the five the host has and compares digests itself. nproc is coreutils, so absent on macOS and BSD; falls through to sysctl -n hw.ncpu before defaulting to 4. The PowerShell tools now run under pwsh on any OS: QEMU is found on PATH (the scoop location is a Windows-only fallback), and path literals use forward slashes -- Join-Path $root 'build\x' produces a *filename containing a backslash* on a Unix host. The backslash sweep is limited to known directory prefixes on purpose: bootcheck sends printf 'caf\303\251' to the guest to test UTF-8, and a blanket substitution would have quietly changed what that asserts. Also fixes six tools left booting build/fs.img, which stopped being bootable when SchFS became the root filesystem: crashshot, dispshot, fbshot, splashshot, textshot and ttyshot all take build/schfs.img now, and the -SchFS switches that used to select it are gone. Verified on Windows: full build, and bootcheck green. The Linux, macOS and BSD paths are written from their documented behaviour and are NOT executed here -- this machine has no WSL and no second host.
This commit is contained in:
parent
e04ca28812
commit
cda5908660
15 changed files with 427 additions and 105 deletions
140
Makefile
140
Makefile
|
|
@ -8,7 +8,10 @@ SYSROOT = sysroot
|
|||
# there is no reason to compile one file at a time. Override with `make -j1`
|
||||
# when you want readable output from a failing build.
|
||||
# -----------------------------------------------------------------------
|
||||
NPROC := $(shell nproc 2>/dev/null || echo 4)
|
||||
# nproc is coreutils, so it exists on Linux and under Git Bash but not on
|
||||
# macOS or the BSDs, where the same number comes from sysctl. Falling through
|
||||
# to 4 is a working build either way, just a slower one.
|
||||
NPROC := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 4)
|
||||
MAKEFLAGS += -j$(NPROC)
|
||||
|
||||
# Kernel object files — organized by subsystem
|
||||
|
|
@ -92,31 +95,29 @@ CMDBINS = $(addprefix $(BUILD)/cmd/, $(CMDS))
|
|||
UNAME_S := $(shell uname -s)
|
||||
UNAME_P := $(shell uname -p)
|
||||
|
||||
# Windows, under Git Bash or MSYS2 — WINHOST.
|
||||
# Host platform.
|
||||
#
|
||||
# WINHOST Windows, under Git Bash or MSYS2
|
||||
# MACHOST macOS
|
||||
# BSDHOST FreeBSD / OpenBSD / NetBSD / DragonFly
|
||||
# (else) Linux
|
||||
#
|
||||
# All four are supported hosts: this is developed from both Windows and Linux,
|
||||
# and nothing here should care which.
|
||||
#
|
||||
# Building natively on Windows rather than in WSL, because WSL2 is a real Linux
|
||||
# kernel in a Hyper-V VM and so hard-requires virtualisation; turning that on
|
||||
# puts the Hyper-V hypervisor underneath the whole machine and demotes VMware
|
||||
# to running nested on top of it, which is a real and permanent cost to pay for
|
||||
# a build environment.
|
||||
#
|
||||
# The usual answer is a cross binutils+gcc, which is a day of work that then
|
||||
# rots. clang does not need any of it: it is a cross-compiler by construction,
|
||||
# so one ordinary LLVM install targets both the bare-metal kernel and Linux
|
||||
# userland, and llvm-objcopy/objdump stand in for binutils. Everything else the
|
||||
# build shells out to — perl, sed, dd, sha256sum — comes with Git Bash.
|
||||
ifneq (,$(filter MINGW% MSYS% CYGWIN%,$(UNAME_S)))
|
||||
WINHOST := 1
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
ifeq ($(UNAME_P),aarch64)
|
||||
TOOLPREFIX = x86_64-linux-gnu-
|
||||
else
|
||||
TOOLPREFIX =
|
||||
endif
|
||||
else ifeq ($(UNAME_S),Darwin)
|
||||
TOOLPREFIX = x86_64-elf-
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
MACHOST := 1
|
||||
endif
|
||||
ifneq (,$(filter FreeBSD OpenBSD NetBSD DragonFly,$(UNAME_S)))
|
||||
BSDHOST := 1
|
||||
endif
|
||||
|
||||
QEMU = qemu-system-x86_64
|
||||
|
|
@ -133,10 +134,40 @@ QEMU = qemu-system-x86_64
|
|||
# virtio-gpu wins the display class, stdvga carries the splash and text console.
|
||||
QEMU_DISPLAY = -vga std -device virtio-gpu-pci
|
||||
|
||||
ifdef WINHOST
|
||||
# An explicit --target is what makes clang emit ELF instead of the COFF it
|
||||
# would default to on this host. Without it every object is silently the
|
||||
# wrong format and the first thing to complain is the linker.
|
||||
# -----------------------------------------------------------------------
|
||||
# Cross-compilation: clang everywhere it can be had
|
||||
#
|
||||
# The kernel, the bootloader and the ports all need a compiler targeting
|
||||
# something other than the host -- bare-metal ELF, 16/32-bit code below one
|
||||
# megabyte, and Linux/musl userland respectively. The traditional answer is a
|
||||
# cross binutils+gcc per host, which is a day of work per platform that then
|
||||
# rots, and on macOS means brewing x86_64-elf-* before anything builds at all.
|
||||
#
|
||||
# clang needs none of it: it is a cross-compiler by construction, so one
|
||||
# ordinary LLVM install produces every target from every host. That was already
|
||||
# how the Windows build worked; using it on all four hosts collapses what used
|
||||
# to be two divergent toolchain branches -- one of which had drifted into
|
||||
# passing GNU-ld-only flags to what is nowadays lld on FreeBSD and macOS -- into
|
||||
# a single path that gets exercised on every platform instead of one.
|
||||
#
|
||||
# GNU is kept as a fallback for hosts without clang, but it is the exception.
|
||||
# -----------------------------------------------------------------------
|
||||
HAVE_CLANG := $(shell command -v clang 2>/dev/null)
|
||||
HAVE_LLD := $(shell command -v ld.lld 2>/dev/null)
|
||||
|
||||
ifeq ($(origin USE_GNU), undefined)
|
||||
ifneq (,$(HAVE_CLANG))
|
||||
ifneq (,$(HAVE_LLD))
|
||||
USE_CLANG := 1
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifdef USE_CLANG
|
||||
# An explicit --target is what makes clang emit ELF rather than whatever the
|
||||
# host defaults to -- COFF on Windows, Mach-O on macOS. Without it every
|
||||
# object is silently the wrong format and the first thing to complain is the
|
||||
# linker.
|
||||
CC = clang --target=x86_64-elf
|
||||
CC32 = clang --target=i386-elf
|
||||
LD = ld.lld
|
||||
|
|
@ -151,49 +182,66 @@ ifdef WINHOST
|
|||
# and refuses, because for a hosted program that would be a bug. Saying the
|
||||
# base is zero is how you tell it this is not a hosted program.
|
||||
LD_LOWBASE = --image-base=0
|
||||
# Host tools (mkfs, mkschfs, the SchFS suites) are ordinary Windows programs.
|
||||
# They must be built with mingw-w64 rather than clang's default MSVC target:
|
||||
# tools/mkfs.c includes <unistd.h> and <dirent.h>, and the Windows SDK has
|
||||
# neither.
|
||||
HOSTCC = gcc
|
||||
# mingw-w64's gcc warns about things glibc's does not (notably %lld/%zu in
|
||||
# printf against msvcrt). Those warnings are about the host build only and
|
||||
# say nothing about the image, so they must not stop it.
|
||||
HOSTWARN = -Wall
|
||||
# MinGW gcc appends .exe when the -o name has no extension, so a rule
|
||||
# whose target lacks it is never considered built -- mkfs was recompiled on
|
||||
# every single invocation of make, forever, because of this.
|
||||
EXE = .exe
|
||||
# `python3` is not on PATH from the python.org installer; `python` is.
|
||||
PYTHON = python
|
||||
# Compiler for ports/, which build *Linux userland* against musl -- a third
|
||||
# target, distinct from both the kernel (bare-metal ELF) and the host tools
|
||||
# (Windows PE). mingw's gcc cannot do it: it targets Windows, so linking it
|
||||
# against musl gives undefined `stderr` and `__errno_location`.
|
||||
# ports/ build *Linux userland* against musl -- a third target, distinct from
|
||||
# both the kernel (bare-metal ELF) and the host tools (native).
|
||||
#
|
||||
# -nostdlib with the crt files named explicitly, because clang otherwise
|
||||
# reaches for gcc's crtbeginT.o and libgcc, which do not exist on this host.
|
||||
# reaches for gcc's crtbeginT.o and libgcc, which need not exist on any
|
||||
# particular host.
|
||||
MUSLPREFIX = $(abspath $(BUILD))/ports/musl/prefix
|
||||
PORTCC = clang --target=x86_64-unknown-linux-musl -fuse-ld=lld
|
||||
PORTCRT = -nostdlib $(MUSLPREFIX)/lib/crt1.o $(MUSLPREFIX)/lib/crti.o
|
||||
PORTEND = $(MUSLPREFIX)/lib/crtn.o
|
||||
else
|
||||
# GNU fallback. Needs a cross toolchain anywhere the host's own gcc does not
|
||||
# already emit x86_64 ELF -- notably macOS, where TOOLPREFIX has to name a
|
||||
# brewed x86_64-elf-gcc.
|
||||
ifdef MACHOST
|
||||
TOOLPREFIX ?= x86_64-elf-
|
||||
else ifeq ($(UNAME_P),aarch64)
|
||||
TOOLPREFIX ?= x86_64-linux-gnu-
|
||||
else
|
||||
TOOLPREFIX ?=
|
||||
endif
|
||||
CC = $(TOOLPREFIX)gcc
|
||||
CC32 = $(CC) -m32
|
||||
LD = $(TOOLPREFIX)ld
|
||||
OBJCOPY = $(TOOLPREFIX)objcopy
|
||||
OBJDUMP = $(TOOLPREFIX)objdump
|
||||
LDFLAGS = -m elf_x86_64 -nostdlib --no-warn-rwx-segments
|
||||
HOSTCC = gcc
|
||||
HOSTWARN = -Werror -Wall
|
||||
EXE =
|
||||
PYTHON = python3
|
||||
LD_LOWBASE =
|
||||
PORTCC = gcc
|
||||
PORTCC = $(TOOLPREFIX)gcc
|
||||
PORTCRT =
|
||||
PORTEND =
|
||||
endif
|
||||
|
||||
# -----------------------------------------------------------------------
|
||||
# Host tools: mkfs, mkschfs, the SchFS suites, qrtest. Ordinary programs for
|
||||
# the machine doing the building, so they use its native compiler.
|
||||
# -----------------------------------------------------------------------
|
||||
HOSTCC ?= cc
|
||||
|
||||
ifdef WINHOST
|
||||
# mingw-w64's gcc, not clang: clang defaults to an MSVC target here, and
|
||||
# tools/mkfs.c includes <unistd.h> and <dirent.h>, which the Windows SDK
|
||||
# does not have.
|
||||
HOSTCC = gcc
|
||||
# mingw-w64's gcc warns about things glibc's does not (notably %lld/%zu in
|
||||
# printf against msvcrt). Those warnings are about the host build only and
|
||||
# say nothing about the image, so they must not stop it.
|
||||
HOSTWARN = -Wall
|
||||
# MinGW gcc appends .exe when the -o name has no extension, so a rule whose
|
||||
# target lacks it is never considered built -- mkfs was recompiled on every
|
||||
# single invocation of make, forever, because of this.
|
||||
EXE = .exe
|
||||
# `python3` is not on PATH from the python.org installer; `python` is.
|
||||
PYTHON = python
|
||||
else
|
||||
HOSTWARN = -Werror -Wall
|
||||
EXE =
|
||||
PYTHON = python3
|
||||
endif
|
||||
|
||||
# Host tools are generated output and live under build/, per docs/layout.md.
|
||||
# $(EXE) matters: MinGW appends it, and a rule whose target lacks it never
|
||||
# looks satisfied.
|
||||
|
|
|
|||
Loading…
Reference in a new issue