Harden the Bash pipeline with SHA256 pins, fingerprints/stamps, build summaries, and QEMU smoke tests; ship size-focused kernel and BusyBox configs; enable virtio networking, optional Dropbear, and BIOS+UEFI hybrid ISO generation documented for USB boot. |
||
|---|---|---|
| overlay | ||
| .gitignore | ||
| busybox.config | ||
| checksums.sha256 | ||
| config | ||
| kernel.config | ||
| ntmkstdlib.sh | ||
| README.md | ||
| script.sh | ||
makecore
makecore is a Bash-based build script that creates a tiny bootable Linux ISO for x86_64.
It automates:
- Linux kernel download/build
- Optional glibc build (for dynamic BusyBox)
- BusyBox build (static by default)
- Root filesystem + initramfs generation
- Optional
./overlay/merge into the rootfs - Bootable ISO creation with Syslinux/Isolinux
- SHA256 verification of source archives
- Build summary (stage times + artefact sizes)
- Optional QEMU run and headless smoke test
- Network (virtio-net + DHCP) and optional Dropbear SSH
Repository layout
| Path | Role |
|---|---|
script.sh |
Main entry point |
config |
Build configuration (URLs + options) |
checksums.sha256 |
SHA256 pins for source archives |
kernel.config |
Minimal kvm-oriented kernel config (Linux 6.12.x) |
busybox.config |
Minimal static BusyBox config (versioned) |
overlay/ |
Optional rootfs overlay (OVERLAY_TYPE=folder) |
sources/ |
Optional local source archives (offline mode) |
ntmkstdlib.sh |
Logging / error helpers |
Prerequisites
-
bash,make,gcc,tar,cpio,gzip,sed,find,wget,sha256sum -
One ISO tool:
xorrisoormkisofsorgenisoimage -
qemu-system-x86_64(forrunandtest) -
Static C library for default static BusyBox:
glibc-static(Fedora/RHEL) orlibc6-devwith static libs (Debian/Ubuntu). Without it the build fails with a clear message; alternative:USE_GLIBC=truefor a dynamic BusyBox. Notes: -
USE_LOCAL_SOURCE=truelooks for archives undersources/first. -
Exact basename from the URL is preferred; otherwise a
component-*.tar.*match is used. -
If nothing is local, the script downloads from the configured URL.
-
With
VERIFY_CHECKSUMS=true, archives are checked againstchecksums.sha256.
Quick start
chmod +x script.sh
./script.sh all
./script.sh test # headless QEMU smoke test
Outputs:
- ISO:
~/work/tmp/out/minidistro.iso(override withWORK_DIR/ISO_NAME) - Summary:
~/work/tmp/out/build-summary.txt - Workspace:
~/work/tmpby default
Interactive QEMU (serial console; quit with Ctrl-A then X):
./script.sh run
Commands
./script.sh all # kernel → (glibc) → busybox → initramfs → ISO + summary
./script.sh kernel # kernel only
./script.sh glibc # glibc only (needs USE_GLIBC=true)
./script.sh busybox # BusyBox only
./script.sh initramfs # rootfs + initramfs only
./script.sh iso # ISO stage (needs kernel + initramfs)
./script.sh dropbear # Dropbear only (ENABLE_DROPBEAR=true)
./script.sh menuconfig # interactive kernel config → kernel.config
./script.sh busybox-config # interactive BusyBox config → busybox.config
./script.sh run # QEMU BIOS + virtio-net (+ SSH hostfwd)
./script.sh run-uefi # QEMU UEFI (OVMF)
./script.sh test # BIOS smoke (MAKECORE_BOOT_OK)
./script.sh test-net # BIOS + DHCP (MAKECORE_NET_OK)
./script.sh test-uefi # UEFI smoke (OVMF)
./script.sh test-uefi-net # UEFI + DHCP
./script.sh summary # print last build sizes / stage times
./script.sh clean # remove WORK_DIR
./script.sh help
Options:
./script.sh --force all # ignore stamps, rebuild
./script.sh -f busybox # force BusyBox rebuild only
Phase D: UEFI hybrid boot
The ISO is BIOS + UEFI hybrid:
| Mode | Bootloader | How |
|---|---|---|
| BIOS | Isolinux | El Torito + isohybrid MBR |
| UEFI | GRUB BOOTX64.EFI |
El Torito ESP (EFI/efiboot.img) + GPT basdat |
Kernel has CONFIG_EFI + CONFIG_EFI_STUB (+ ACPI). The ESP embeds kernel+initrd so UEFI does not depend on ISO9660 path search.
./script.sh all
./script.sh test # BIOS
./script.sh test-uefi # OVMF UEFI
./script.sh run-uefi # interactive UEFI
Host packages for UEFI build/test: xorriso, grub2-efi-x64-modules, grub2-tools, mtools, dosfstools, edk2-ovmf (or ovmf).
Write to USB (hybrid ISO)
# CAUTION: destroys all data on the target device
sudo dd if=~/work/tmp/out/minidistro.iso of=/dev/sdX bs=4M status=progress oflag=sync
# or:
sudo cp ~/work/tmp/out/minidistro.iso /dev/sdX && sync
Then boot the USB stick in either legacy BIOS or UEFI mode (disable Secure Boot if GRUB is unsigned — this image is not signed).
| Variable | Default | Meaning |
|---|---|---|
ENABLE_UEFI |
true |
Build hybrid BIOS+UEFI ISO |
UEFI_ESP_SIZE_KB |
auto (≥8MiB) | Minimum ESP size override |
OVMF_CODE / OVMF_VARS |
auto | QEMU firmware paths |
TEST_UEFI_TIMEOUT |
240 |
UEFI smoke timeout (s) |
Phase C: network & services
| Feature | How |
|---|---|
| Virtio-net in QEMU | ./script.sh run / test attach -device virtio-net-pci + user net |
| DHCP | /init runs udhcpc → marker MAKECORE_NET_OK |
| Dropbear SSH | Static build; host keys baked at build; password from ROOT_PASSWORD |
| Overlay examples | overlay/etc/motd, issue, root/.profile, … |
./script.sh all && ./script.sh test-net
./script.sh run
# other terminal:
ssh -p 2222 root@127.0.0.1 # password: makecore (default)
| Variable | Default | Meaning |
|---|---|---|
ENABLE_NETWORK |
true |
Bring up lo + first NIC |
ENABLE_DHCP |
true |
udhcpc on that NIC |
ENABLE_DROPBEAR |
true |
Build/install dropbear |
ROOT_PASSWORD |
makecore |
root shadow password |
QEMU_SSH_PORT |
2222 |
Host port → guest :22 |
DROPBEAR_SOURCE_URL |
dropbear-2025.88 | Source tarball |
Disable SSH to shrink the image: ENABLE_DROPBEAR=false then rebuild.
Phase B: minimalism
Versioned configs tuned for a small QEMU-friendly image:
| Artefact | Phase A (defconfig-ish) | Phase B (minimal) |
|---|---|---|
| Kernel bzImage | ~14M | ~2.7M |
| BusyBox | ~2.4M | ~2.0M |
| Initramfs | ~1.3M | ~1.0M |
| ISO | ~16M | ~4.2M |
| Full build (16 cores) | ~5+ min | ~2.5 min |
kernel.config: allnoconfig base + initrd, serial, virtio, networking, ext4/squashfs/overlay;CONFIG_CC_OPTIMIZE_FOR_SIZE, no modules.busybox.config: static, ash, coreutils, mount, ip/udhcpc/wget, vi/awk — servers and niche applets off.USE_PREDEFINED_BUSYBOX_CONFIG=trueby default.- Iterate configs:
./script.sh menuconfig/./script.sh busybox-config, then./script.sh --force all && ./script.sh test.
Phase A: reliability features
Checksums
Pinned SHA256 digests live in checksums.sha256 (standard sha256sum format).
| Variable | Default | Meaning |
|---|---|---|
VERIFY_CHECKSUMS |
true |
Hash each archive after resolve/download |
CHECKSUMS_REQUIRED |
false |
If true, fail when an archive has no entry |
CHECKSUMS_FILE |
checksums.sha256 |
Path to the pin file |
Manual check:
cd sources && sha256sum -c ../checksums.sha256
Build summary
After all (and several single stages), the script prints and saves:
- Per-stage durations (
kernel,glibc,busybox,initramfs,iso) - Artefact sizes (kernel, busybox, initramfs, ISO)
File: $WORK_DIR/out/build-summary.txt — also via ./script.sh summary.
Smoke test
./script.sh test
Boots the ISO headless in QEMU (-display none -serial file:…), waits for the marker string emitted by /init:
MAKECORE_BOOT_OK
| Variable | Default | Meaning |
|---|---|---|
TEST_TIMEOUT |
180 |
Seconds before failure |
TEST_MARKER |
MAKECORE_BOOT_OK |
Success string on serial |
QEMU_MEM |
256 |
Guest RAM (MiB) |
Logs: $WORK_DIR/test/serial.log, last-result.txt, qemu.stderr.
Uses KVM when /dev/kvm is available.
Configuration (config)
| Variable | Meaning |
|---|---|
KERNEL_SOURCE_URL |
Linux kernel tarball URL |
GLIBC_SOURCE_URL |
glibc tarball URL |
BUSYBOX_SOURCE_URL |
BusyBox tarball URL |
SYSLINUX_SOURCE_URL |
Syslinux tarball URL |
WORK_DIR |
Build workspace (default ~/work/tmp) |
ISO_NAME |
Output ISO filename |
USE_PREDEFINED_KERNEL_CONFIG |
true → use kernel.config, else x86_64_defconfig |
USE_PREDEFINED_BUSYBOX_CONFIG |
true → use busybox.config if present |
USE_GLIBC |
Dynamic BusyBox + glibc runtime in rootfs |
USE_LOCAL_SOURCE |
Prefer ./sources/ archives |
OVERLAY_TYPE |
none or folder (copy ./overlay/) |
JOB_FACTOR |
jobs = cores * JOB_FACTOR |
CFLAGS |
BusyBox compile flags |
KERNEL_CMDLINE |
Appended by isolinux (default dual console) |
QEMU_MEM |
RAM in MiB for run / test |
VERIFY_CHECKSUMS |
Enable SHA256 checks |
CHECKSUMS_REQUIRED |
Fail on missing checksum entries |
CHECKSUMS_FILE |
Checksums path |
TEST_TIMEOUT |
Smoke test timeout (s) |
TEST_MARKER |
Smoke test success string |
Incremental builds (stamps)
Each stage writes a stamp under $WORK_DIR/stamps/ that embeds a fingerprint of its inputs. Changing those inputs invalidates the stamp. Downstream stages are also invalidated when an upstream stage is rebuilt. Use --force to rebuild regardless.
Overlay
- Put files under
overlay/mirroring the rootfs tree. - Set
OVERLAY_TYPE=folderinconfig. - Rebuild initramfs /
all.
Boot behaviour
The initramfs /init mounts proc, sys, dev, tmp, run, sets hostname, prints a banner, emits MAKECORE_BOOT_OK, then starts a shell.
Default kernel cmdline includes serial + VGA (console=tty0 console=ttyS0).
Troubleshooting
| Problem | What to try |
|---|---|
iso fails (missing kernel/initramfs) |
Run ./script.sh all first |
| ISO tool missing | Install xorriso, mkisofs, or genisoimage |
| Download fails / offline | Put archives in sources/ or set USE_LOCAL_SOURCE=false |
| SHA256 mismatch | Re-download archive or update checksums.sha256 |
| Smoke test timeout | Raise TEST_TIMEOUT; inspect $WORK_DIR/test/serial.log |
| Smoke test: QEMU dies early | Check qemu.stderr; ensure ISO boots under BIOS |
| Slow build | Raise JOB_FACTOR |
| Stamp seems stuck | ./script.sh --force <stage> or ./script.sh clean |