virt/qemu.nix
λpkgs, ports, filcc, world-pkgs
let
import./common.nix inherit pkgs ports filcc;
Minimal headless QEMU without GUI dependencies
pkgs.qemu_kvm.override
true
Only build for host CPU architecturefalse
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
false
used by imageBuilder
import./core.nix inherit pkgs ports world-pkgs dank-bashrc ghostty-terminfo lighttpd-demo;
Script that builds the rootfs and creates a disk image
pkgs.writeShellScript"build-filc-qemu-image"
set -euo pipefail
output="''${1:-filc-rootfs.img}"
echo "Building Fil-C QEMU disk image: $output"
# Create temporary directory for rootfs
workdir=$(mktemp -d)
trap 'chmod -R +w "$workdir" 2>/dev/null || true; rm -rf "$workdir"' EXIT
rootfs="$workdir/rootfs"
mkdir -p "$rootfs"
# Build rootfs using shared script
echo "Assembling rootfs..."
${mkRootfsScript"$rootfs"}
# Calculate actual size needed (with 20% overhead)
size_with_overhead=$((actual_size * 120 / 100))
echo "Rootfs size: $actual_size bytes (allocating $size_with_overhead bytes with overhead)"
# Create raw disk image
echo "Creating raw ext4 disk image..."
${pkgs.coreutils}/bin/truncate -s "$size_with_overhead" "$output"
# Format as ext4
${pkgs.e2fsprogs}/bin/mkfs.ext4 -q -L filc-root "$output"
# Mount and copy rootfs
echo "Copying rootfs to disk..."
mnt="$workdir/mnt"
mkdir -p "$mnt"
sudo ${pkgs.util-linux}/bin/mount -o loop "$output" "$mnt"
trap 'sudo ${pkgs.util-linux}/bin/umount "$mnt" 2>/dev/null || true; chmod -R +w "$workdir" 2>/dev/null || true; rm -rf "$workdir"' EXIT
sudo ${pkgs.rsync}/bin/rsync -a "$rootfs/" "$mnt/"
sudo ${pkgs.util-linux}/bin/umount "$mnt"
echo "Disk image created: $output"
${pkgs.coreutils}/bin/ls -lh "$output"
echo
echo "To compress for distribution:"
echo " ${qemu-headless}/bin/qemu-img convert -f raw -O qcow2 -c $output ''${output%.img}.qcow2"
in
pkgs.buildEnv
"filc-qemu"
pkgs.writeShellScriptBin"build-filc-qemu-image"
exec ${imageBuilder} "$@"
pkgs.writeShellScriptBin"run-filc-qemu"
set -euo pipefail
disk="''${1:-/tmp/filc.img}"
${imageBuilder} "$disk"
# Auto-detect format from extension
format="raw"
case "$disk" in
*.qcow2) format="qcow2" ;;
*.img|*.raw) format="raw" ;;
esac
qemu=${qemu-headless}/bin/qemu-system-x86_64
kernel=${kernel}/bzImage
accelFlags="-cpu max"
if [ -e /dev/kvm ] && [ -r /dev/kvm ] && [ -w /dev/kvm ]; then
accelFlags="-enable-kvm -cpu host"
else
echo "warning: /dev/kvm unavailable, falling back to TCG (-cpu max)" >&2
echo " Fil-C runtime may require modern CPU features; enable KVM if possible." >&2
fi
echo "Starting Fil-C QEMU (disk: $disk, format: $format)..."
exec "$qemu" \
-m 512 \
-kernel "$kernel" \
-drive file="$disk",if=virtio,format="$format" \
-netdev user,id=net0,hostfwd=tcp:127.0.0.1:2222-:22 \
-device virtio-net-pci,netdev=net0 \
-append "console=ttyS0 root=/dev/vda rootwait init=/bin/runit-init panic=-1 oops=panic earlyprintk=serial,ttyS0,115200" \
-nographic \
-no-reboot \
$accelFlags
"/bin"