:: commit 6dcce5f7d22d3277fc702084c2aaf300df677946

mintsuki <mintsuki@protonmail.com> — 2021-11-28 18:00

parents: 99c42e7686

build: Initial support for special characters in build path

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 9a2ff693..38fa9f4e 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -70,9 +70,6 @@ jobs:
       - name: Clean limine-install
         run: make -C limine-install clean
 
-      - name: Copy limine-install to bin
-        run: cp limine-install/* limine-install/.gitignore build/bin/
-
       - name: Copy LICENSE to bin
         run: cp LICENSE.md build/bin/
 
diff --git a/Makefile b/Makefile
index 789591c4..3c3023e6 100644
--- a/Makefile
+++ b/Makefile
@@ -8,6 +8,11 @@ DESTDIR ?=
 BUILDDIR ?= $(shell pwd)/build
 BINDIR ?= $(BUILDDIR)/bin
 
+SPACE := $(subst ,, )
+
+MKESCAPE = $(subst #,\#,$(subst $$,$$$$,$(subst $(SPACE),\ ,$(1))))
+SHESCAPE = $(subst ','\'',$(1))
+
 export PATH := $(shell pwd)/toolchain/bin:$(PATH)
 
 NCPUS := $(shell nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 1)
@@ -20,7 +25,7 @@ TOOLCHAIN ?= limine
 
 TOOLCHAIN_CC ?= $(TOOLCHAIN)-gcc
 
-ifeq ($(shell PATH="$(PATH)" command -v $(TOOLCHAIN_CC) ; ), )
+ifeq ($(shell PATH='$(call SHESCAPE,$(PATH))' command -v $(TOOLCHAIN_CC) ; ), )
 override TOOLCHAIN_CC := cc
 endif
 
@@ -32,7 +37,7 @@ MAKEOVERRIDES += TOOLCHAIN_CC+=--target=x86_64-elf
 endif
 endif
 
-CC_MACHINE := $(shell PATH="$(PATH)" $(TOOLCHAIN_CC) -dumpmachine | dd bs=6 count=1 2>/dev/null)
+CC_MACHINE := $(shell PATH='$(call SHESCAPE,$(PATH))' $(TOOLCHAIN_CC) -dumpmachine | dd bs=6 count=1 2>/dev/null)
 
 ifneq ($(MAKECMDGOALS), toolchain)
 ifneq ($(MAKECMDGOALS), distclean)
@@ -57,65 +62,67 @@ all:
 
 .PHONY: limine-install
 limine-install:
-	$(MAKE) -C limine-install LIMINE_HDD_BIN="$(BINDIR)/limine-hdd.bin" BUILDDIR="$(BINDIR)"
+	mkdir -p '$(call SHESCAPE,$(BINDIR))'
+	cp limine-install/* limine-install/.gitignore '$(call SHESCAPE,$(BINDIR))/'
+	$(MAKE) -C '$(call SHESCAPE,$(BINDIR))'
 
 .PHONY: clean
 clean: limine-bios-clean limine-uefi-clean limine-uefi32-clean
-	$(MAKE) -C limine-install clean
+	$(MAKE) -C '$(call SHESCAPE,$(BINDIR))' clean || true
 
 .PHONY: install
 install: all
-	install -d "$(DESTDIR)$(PREFIX)/bin"
-	install -s $(BINDIR)/limine-install "$(DESTDIR)$(PREFIX)/bin/"
-	install -d "$(DESTDIR)$(PREFIX)/share"
-	install -d "$(DESTDIR)$(PREFIX)/share/limine"
-	install -m 644 $(BINDIR)/limine.sys "$(DESTDIR)$(PREFIX)/share/limine/" || true
-	install -m 644 $(BINDIR)/limine-cd.bin "$(DESTDIR)$(PREFIX)/share/limine/" || true
-	install -m 644 $(BINDIR)/limine-eltorito-efi.bin "$(DESTDIR)$(PREFIX)/share/limine/" || true
-	install -m 644 $(BINDIR)/limine-pxe.bin "$(DESTDIR)$(PREFIX)/share/limine/" || true
-	install -m 644 $(BINDIR)/BOOTX64.EFI "$(DESTDIR)$(PREFIX)/share/limine/" || true
-	install -m 644 $(BINDIR)/BOOTIA32.EFI "$(DESTDIR)$(PREFIX)/share/limine/" || true
-
-$(BUILDDIR)/stage1: $(STAGE1_FILES) $(BUILDDIR)/decompressor/decompressor.bin $(BUILDDIR)/stage23-bios/stage2.bin.gz
-	mkdir -p $(BINDIR)
-	cd stage1/hdd && nasm bootsect.asm -Werror -fbin -DBUILDDIR="'$(BUILDDIR)'" -o $(BINDIR)/limine-hdd.bin
-	cd stage1/cd  && nasm bootsect.asm -Werror -fbin -DBUILDDIR="'$(BUILDDIR)'" -o $(BINDIR)/limine-cd.bin
-	cd stage1/pxe && nasm bootsect.asm -Werror -fbin -DBUILDDIR="'$(BUILDDIR)'" -o $(BINDIR)/limine-pxe.bin
-	cp $(BUILDDIR)/stage23-bios/limine.sys $(BINDIR)/
-	touch $(BUILDDIR)/stage1
+	install -d '$(DESTDIR)$(PREFIX)/bin'
+	install -s '$(call SHESCAPE,$(BINDIR))/limine-install' '$(DESTDIR)$(PREFIX)/bin/'
+	install -d '$(DESTDIR)$(PREFIX)/share'
+	install -d '$(DESTDIR)$(PREFIX)/share/limine'
+	install -m 644 '$(call SHESCAPE,$(BINDIR))/limine.sys' '$(DESTDIR)$(PREFIX)/share/limine/' || true
+	install -m 644 '$(call SHESCAPE,$(BINDIR))/limine-cd.bin' '$(DESTDIR)$(PREFIX)/share/limine/' || true
+	install -m 644 '$(call SHESCAPE,$(BINDIR))/limine-eltorito-efi.bin' '$(DESTDIR)$(PREFIX)/share/limine/' || true
+	install -m 644 '$(call SHESCAPE,$(BINDIR))/limine-pxe.bin' '$(DESTDIR)$(PREFIX)/share/limine/' || true
+	install -m 644 '$(call SHESCAPE,$(BINDIR))/BOOTX64.EFI' '$(DESTDIR)$(PREFIX)/share/limine/' || true
+	install -m 644 '$(call SHESCAPE,$(BINDIR))/BOOTIA32.EFI' '$(DESTDIR)$(PREFIX)/share/limine/' || true
+
+$(call MKESCAPE,$(BUILDDIR))/stage1: $(STAGE1_FILES) $(call MKESCAPE,$(BUILDDIR))/decompressor/decompressor.bin $(call MKESCAPE,$(BUILDDIR))/stage23-bios/stage2.bin.gz
+	mkdir -p '$(call SHESCAPE,$(BINDIR))'
+	cd stage1/hdd && nasm bootsect.asm -Werror -fbin -DBUILDDIR="'"'$(call SHESCAPE,$(BUILDDIR))'"'" -o '$(call SHESCAPE,$(BINDIR))/limine-hdd.bin'
+	cd stage1/cd  && nasm bootsect.asm -Werror -fbin -DBUILDDIR="'"'$(call SHESCAPE,$(BUILDDIR))'"'" -o '$(call SHESCAPE,$(BINDIR))/limine-cd.bin'
+	cd stage1/pxe && nasm bootsect.asm -Werror -fbin -DBUILDDIR="'"'$(call SHESCAPE,$(BUILDDIR))'"'" -o '$(call SHESCAPE,$(BINDIR))/limine-pxe.bin'
+	cp '$(call SHESCAPE,$(BUILDDIR))/stage23-bios/limine.sys' '$(call SHESCAPE,$(BINDIR))/'
+	touch '$(call SHESCAPE,$(BUILDDIR))/stage1'
 
 .PHONY: limine-bios
 limine-bios: stage23-bios decompressor
-	$(MAKE) $(BUILDDIR)/stage1
-
-.PHONY: $(BINDIR)/limine-eltorito-efi.bin
-$(BINDIR)/limine-eltorito-efi.bin:
-	mkdir -p $(BINDIR)
-	dd if=/dev/zero of=$@ bs=512 count=2880
-	( mformat -i $@ -f 1440 :: && \
-	  mmd -D s -i $@ ::/EFI && \
-	  mmd -D s -i $@ ::/EFI/BOOT && \
-	  ( ( [ -f $(BUILDDIR)/stage23-uefi/BOOTX64.EFI ] && \
-	      mcopy -D o -i $@ $(BUILDDIR)/stage23-uefi/BOOTX64.EFI ::/EFI/BOOT ) || true ) && \
-	  ( ( [ -f $(BUILDDIR)/stage23-uefi32/BOOTIA32.EFI ] && \
-	      mcopy -D o -i $@ $(BUILDDIR)/stage23-uefi32/BOOTIA32.EFI ::/EFI/BOOT ) || true ) \
-	) || rm -f $@
+	$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/stage1'
+
+.PHONY: $(call MKESCAPE,$(BINDIR))/limine-eltorito-efi.bin
+$(call MKESCAPE,$(BINDIR))/limine-eltorito-efi.bin:
+	mkdir -p '$(call SHESCAPE,$(BINDIR))'
+	dd if=/dev/zero of='$(call SHESCAPE,$@)' bs=512 count=2880
+	( mformat -i '$(call SHESCAPE,$@)' -f 1440 :: && \
+	  mmd -D s -i '$(call SHESCAPE,$@)' ::/EFI && \
+	  mmd -D s -i '$(call SHESCAPE,$@)' ::/EFI/BOOT && \
+	  ( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/stage23-uefi/BOOTX64.EFI' ] && \
+	      mcopy -D o -i '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/stage23-uefi/BOOTX64.EFI' ::/EFI/BOOT ) || true ) && \
+	  ( ( [ -f '$(call SHESCAPE,$(BUILDDIR))/stage23-uefi32/BOOTIA32.EFI' ] && \
+	      mcopy -D o -i '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/stage23-uefi32/BOOTIA32.EFI' ::/EFI/BOOT ) || true ) \
+	) || rm -f '$(call SHESCAPE,$@)'
 
 .PHONY: limine-uefi
 limine-uefi:
 	$(MAKE) gnu-efi
 	$(MAKE) stage23-uefi
-	mkdir -p $(BINDIR)
-	cp $(BUILDDIR)/stage23-uefi/BOOTX64.EFI $(BINDIR)/
-	$(MAKE) $(BINDIR)/limine-eltorito-efi.bin
+	mkdir -p '$(call SHESCAPE,$(BINDIR))'
+	cp '$(call SHESCAPE,$(BUILDDIR))/stage23-uefi/BOOTX64.EFI' '$(call SHESCAPE,$(BINDIR))/'
+	$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-eltorito-efi.bin'
 
 .PHONY: limine-uefi32
 limine-uefi32:
 	$(MAKE) gnu-efi
 	$(MAKE) stage23-uefi32
-	mkdir -p $(BINDIR)
-	cp $(BUILDDIR)/stage23-uefi32/BOOTIA32.EFI $(BINDIR)/
-	$(MAKE) $(BINDIR)/limine-eltorito-efi.bin
+	mkdir -p '$(call SHESCAPE,$(BINDIR))'
+	cp '$(call SHESCAPE,$(BUILDDIR))/stage23-uefi32/BOOTIA32.EFI' '$(call SHESCAPE,$(BINDIR))/'
+	$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-eltorito-efi.bin'
 
 .PHONY: limine-bios-clean
 limine-bios-clean: stage23-bios-clean decompressor-clean
@@ -156,35 +163,35 @@ stivale:
 
 .PHONY: stage23-uefi
 stage23-uefi: stivale
-	$(MAKE) -C stage23 all TARGET=uefi BUILDDIR="$(BUILDDIR)/stage23-uefi"
+	$(MAKE) -C stage23 all TARGET=uefi BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/stage23-uefi'
 
 .PHONY: stage23-uefi-clean
 stage23-uefi-clean:
-	$(MAKE) -C stage23 clean TARGET=uefi BUILDDIR="$(BUILDDIR)/stage23-uefi"
+	$(MAKE) -C stage23 clean TARGET=uefi BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/stage23-uefi'
 
 .PHONY: stage23-uefi32
 stage23-uefi32: stivale
-	$(MAKE) -C stage23 all TARGET=uefi32 BUILDDIR="$(BUILDDIR)/stage23-uefi32"
+	$(MAKE) -C stage23 all TARGET=uefi32 BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/stage23-uefi32'
 
 .PHONY: stage23-uefi32-clean
 stage23-uefi32-clean:
-	$(MAKE) -C stage23 clean TARGET=uefi32 BUILDDIR="$(BUILDDIR)/stage23-uefi32"
+	$(MAKE) -C stage23 clean TARGET=uefi32 BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/stage23-uefi32'
 
 .PHONY: stage23-bios
 stage23-bios: stivale
-	$(MAKE) -C stage23 all TARGET=bios BUILDDIR="$(BUILDDIR)/stage23-bios"
+	$(MAKE) -C stage23 all TARGET=bios BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/stage23-bios'
 
 .PHONY: stage23-bios-clean
 stage23-bios-clean:
-	$(MAKE) -C stage23 clean TARGET=bios BUILDDIR="$(BUILDDIR)/stage23-bios"
+	$(MAKE) -C stage23 clean TARGET=bios BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/stage23-bios'
 
 .PHONY: decompressor
 decompressor:
-	$(MAKE) -C decompressor all BUILDDIR="$(BUILDDIR)/decompressor"
+	$(MAKE) -C decompressor all BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/decompressor'
 
 .PHONY: decompressor-clean
 decompressor-clean:
-	$(MAKE) -C decompressor clean BUILDDIR="$(BUILDDIR)/decompressor"
+	$(MAKE) -C decompressor clean BUILDDIR='$(call SHESCAPE,$(BUILDDIR))/decompressor'
 
 .PHONY: test-clean
 test-clean:
@@ -196,7 +203,7 @@ toolchain:
 	MAKE="$(MAKE)" build-aux/make_toolchain.sh "`pwd`/toolchain" -j$(NCPUS)
 
 gnu-efi:
-	git clone https://github.com/limine-bootloader/gnu-efi.git --branch=3.0.14 --depth=1 $@
+	git clone https://github.com/limine-bootloader/gnu-efi.git --branch=3.0.14 --depth=1
 	cp build-aux/elf/* gnu-efi/inc/
 
 ovmf-x64:
diff --git a/decompressor/Makefile b/decompressor/Makefile
index dc27a3ac..9b53840f 100644
--- a/decompressor/Makefile
+++ b/decompressor/Makefile
@@ -4,8 +4,14 @@ endif
 
 BUILDDIR =
 
-ifeq ($(BUILDDIR), )
-	$(error BUILDDIR not specified)
+SPACE := $(subst ,, )
+
+MKESCAPE = $(subst #,\#,$(subst $$,$$$$,$(subst $(SPACE),\ ,$(1))))
+SHESCAPE = $(subst ','\'',$(1))
+OBJESCAPE = $(subst .a ,.a' ',$(subst .o ,.o' ',$(call SHESCAPE,$(1))))
+
+ifeq ($(call MKESCAPE,$(BUILDDIR)), )
+	$(error $(call MKESCAPE,$(BUILDDIR)) not specified)
 endif
 
 TOOLCHAIN ?= limine
@@ -46,7 +52,7 @@ INTERNAL_CFLAGS = \
 	-mno-sse2 \
 	-MMD \
 	-I. \
-	-I$(BUILDDIR)/tinf
+	-I'$(call SHESCAPE,$(BUILDDIR))/tinf'
 
 LDFLAGS ?=
 
@@ -57,39 +63,39 @@ INTERNAL_LDFLAGS = \
 	-static \
 	-Tlinker.ld
 
-.PHONY: all clean builddir
+.PHONY: all clean
 
 C_FILES := $(shell find -L ./ -type f -name '*.c' | sort)
 ASM_FILES := $(shell find -L ./ -type f -name '*.asm' | sort)
-OBJ := $(addprefix $(BUILDDIR)/, $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o))
-HEADER_DEPS := $(addprefix $(BUILDDIR)/, $(C_FILES:.c=.d))
+OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(ASM_FILES:.asm=.o) $(C_FILES:.c=.o))
+HEADER_DEPS := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.d))
 
 all:
-	$(MAKE) builddir
-	$(MAKE) $(BUILDDIR)/decompressor.bin
-
-builddir:
-	for i in $(OBJ); do mkdir -p `dirname $$i`; done
+	$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/decompressor.bin'
 
-$(BUILDDIR)/decompressor.bin: $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o
-	$(TOOLCHAIN_LD) $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $(BUILDDIR)/decompressor.elf
-	$(TOOLCHAIN_OBJCOPY) -O binary $(BUILDDIR)/decompressor.elf $@
+$(call MKESCAPE,$(BUILDDIR))/decompressor.bin: $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o
+	$(TOOLCHAIN_LD) '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -o '$(call SHESCAPE,$(BUILDDIR))/decompressor.elf'
+	$(TOOLCHAIN_OBJCOPY) -O binary '$(call SHESCAPE,$(BUILDDIR))/decompressor.elf' '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/tinf-copied: ../tinf/*
-	rm -rf $(BUILDDIR)/tinf
-	cp -r ../tinf $(BUILDDIR)/
-	touch $(BUILDDIR)/tinf-copied
+$(call MKESCAPE,$(BUILDDIR))/tinf-copied: ../tinf/*
+	rm -rf '$(call SHESCAPE,$(BUILDDIR))/tinf'
+	mkdir -p '$(call SHESCAPE,$(BUILDDIR))'
+	cp -r ../tinf '$(call SHESCAPE,$(BUILDDIR))/'
+	touch '$(call SHESCAPE,$(BUILDDIR))/tinf-copied'
 
-$(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o: $(BUILDDIR)/tinf-copied
-	$(TOOLCHAIN_CC) $(CFLAGS) -Os $(INTERNAL_CFLAGS) -c $(@:.o=.c) -o $@
+$(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o: $(call MKESCAPE,$(BUILDDIR))/tinf-copied
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) -Os $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$(@:.o=.c))' -o '$(call SHESCAPE,$@)'
 
 -include $(HEADER_DEPS)
 
-$(BUILDDIR)/%.o: %.c $(BUILDDIR)/tinf-copied
-	$(TOOLCHAIN_CC) $(CFLAGS) -Os $(INTERNAL_CFLAGS) -c $< -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/tinf-copied
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) -Os $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/%.o: %.asm
-	nasm $< -f elf32 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -f elf32 -o '$(call SHESCAPE,$@)'
 
 clean:
-	rm -rf $(BUILDDIR)
+	rm -rf '$(call SHESCAPE,$(BUILDDIR))'
diff --git a/limine-install/Makefile b/limine-install/Makefile
index 3237a53b..0f789d75 100644
--- a/limine-install/Makefile
+++ b/limine-install/Makefile
@@ -3,29 +3,26 @@ CC = cc
 PREFIX = /usr/local
 DESTDIR =
 
-BUILDDIR = .
-LIMINE_HDD_BIN = limine-hdd.bin
-
 CFLAGS = -O2 -pipe -Wall -Wextra
 
 .PHONY: all install clean
 
-all: $(BUILDDIR)/limine-install
+all: limine-install
 
 install: all
-	install -d "$(DESTDIR)$(PREFIX)/bin"
-	install -s "$(BUILDDIR)/limine-install" "$(DESTDIR)$(PREFIX)/bin/"
-	install -d "$(DESTDIR)$(PREFIX)/share"
-	install -d "$(DESTDIR)$(PREFIX)/share/limine"
-	install -m 644 limine.sys "$(DESTDIR)$(PREFIX)/share/limine/"
-	install -m 644 limine-cd.bin "$(DESTDIR)$(PREFIX)/share/limine/"
-	install -m 644 limine-eltorito-efi.bin "$(DESTDIR)$(PREFIX)/share/limine/"
-	install -m 644 limine-pxe.bin "$(DESTDIR)$(PREFIX)/share/limine/"
-	install -m 644 BOOTX64.EFI "$(DESTDIR)$(PREFIX)/share/limine/"
-	install -m 644 BOOTIA32.EFI "$(DESTDIR)$(PREFIX)/share/limine/"
+	install -d '$(DESTDIR)$(PREFIX)/bin'
+	install -s limine-install '$(DESTDIR)$(PREFIX)/bin/'
+	install -d '$(DESTDIR)$(PREFIX)/share'
+	install -d '$(DESTDIR)$(PREFIX)/share/limine'
+	install -m 644 limine.sys '$(DESTDIR)$(PREFIX)/share/limine/'
+	install -m 644 limine-cd.bin '$(DESTDIR)$(PREFIX)/share/limine/'
+	install -m 644 limine-eltorito-efi.bin '$(DESTDIR)$(PREFIX)/share/limine/'
+	install -m 644 limine-pxe.bin '$(DESTDIR)$(PREFIX)/share/limine/'
+	install -m 644 BOOTX64.EFI '$(DESTDIR)$(PREFIX)/share/limine/'
+	install -m 644 BOOTIA32.EFI '$(DESTDIR)$(PREFIX)/share/limine/'
 
 clean:
-	rm -f "$(BUILDDIR)/limine-install" "$(BUILDDIR)/limine-install.exe"
+	rm -f limine-install limine-install.exe
 
-$(BUILDDIR)/limine-install: limine-install.c inc.S $(LIMINE_HDD_BIN)
-	$(CC) $(CFLAGS) -std=c11 -DLIMINE_HDD_BIN='"$(LIMINE_HDD_BIN)"' limine-install.c inc.S -o "$@"
+limine-install: limine-install.c inc.S limine-hdd.bin
+	$(CC) $(CFLAGS) -std=c11 limine-install.c inc.S -o $@
diff --git a/limine-install/inc.S b/limine-install/inc.S
index 9edb2989..c28f3ca9 100644
--- a/limine-install/inc.S
+++ b/limine-install/inc.S
@@ -4,7 +4,7 @@
 .data
 .global __binary_limine_hdd_bin_start
 __binary_limine_hdd_bin_start:
-    .incbin LIMINE_HDD_BIN
+    .incbin "limine-hdd.bin"
 .global __binary_limine_hdd_bin_end
 __binary_limine_hdd_bin_end:
 
@@ -13,7 +13,7 @@ __binary_limine_hdd_bin_end:
 .section .data
 .global __binary_limine_hdd_bin_start
 __binary_limine_hdd_bin_start:
-    .incbin LIMINE_HDD_BIN
+    .incbin "limine-hdd.bin"
 .global __binary_limine_hdd_bin_end
 __binary_limine_hdd_bin_end:
 
@@ -26,7 +26,7 @@ __binary_limine_hdd_bin_end:
 .section .data
 .global _binary_limine_hdd_bin_start
 _binary_limine_hdd_bin_start:
-    .incbin LIMINE_HDD_BIN
+    .incbin "limine-hdd.bin"
 .global _binary_limine_hdd_bin_end
 _binary_limine_hdd_bin_end:
 
diff --git a/stage23/Makefile b/stage23/Makefile
index 16ab52bd..cb6408ce 100644
--- a/stage23/Makefile
+++ b/stage23/Makefile
@@ -5,8 +5,16 @@ endif
 TARGET =
 BUILDDIR =
 
-ifeq ($(BUILDDIR), )
-	$(error BUILDDIR not specified)
+SRCDIR := $(shell pwd)
+
+SPACE := $(subst ,, )
+
+MKESCAPE = $(subst #,\#,$(subst $$,$$$$,$(subst $(SPACE),\ ,$(1))))
+SHESCAPE = $(subst ','\'',$(1))
+OBJESCAPE = $(subst .a ,.a' ',$(subst .o ,.o' ',$(call SHESCAPE,$(1))))
+
+ifeq ($(call MKESCAPE,$(BUILDDIR)), )
+	$(error $(call MKESCAPE,$(BUILDDIR)) not specified)
 endif
 
 ifeq ($(TARGET), bios)
@@ -75,7 +83,7 @@ INTERNAL_CFLAGS := \
 	-DE9_OUTPUT=$(E9_OUTPUT) \
 	-I. \
 	-I../stivale \
-	-I$(BUILDDIR)/tinf
+	-I'$(call SHESCAPE,$(BUILDDIR))/tinf'
 
 ifeq ($(TARGET), bios)
 	INTERNAL_CFLAGS += \
@@ -109,8 +117,8 @@ ifeq ($(TARGET), uefi)
 		-mtune=generic \
 		-mabi=sysv \
 		-DGNU_EFI_USE_MS_ABI \
-		-I$(BUILDDIR)/gnu-efi/inc \
-		-I$(BUILDDIR)/gnu-efi/inc/x86_64 \
+		-I'$(call SHESCAPE,$(BUILDDIR))/gnu-efi/inc' \
+		-I'$(call SHESCAPE,$(BUILDDIR))/gnu-efi/inc/x86_64' \
 		-fpie \
 		-mno-red-zone
 endif
@@ -124,8 +132,8 @@ ifeq ($(TARGET), uefi32)
 		-mtune=generic \
 		-mabi=sysv \
 		-DGNU_EFI_USE_MS_ABI \
-		-I$(BUILDDIR)/gnu-efi/inc \
-		-I$(BUILDDIR)/gnu-efi/inc/ia32 \
+		-I'$(call SHESCAPE,$(BUILDDIR))/gnu-efi/inc' \
+		-I'$(call SHESCAPE,$(BUILDDIR))/gnu-efi/inc/ia32' \
 		-fpie
 endif
 
@@ -160,243 +168,249 @@ ifeq ($(TARGET), uefi32)
 		-ztext
 endif
 
-.PHONY: all clean builddir
+.PHONY: all clean
 
 C_FILES := $(shell find -L ./ -type f -name '*.c' | sort)
 ifeq ($(TARGET), bios)
 ASM32_FILES := $(shell find -L ./ -type f -name '*.asm32' | sort)
 ASMB_FILES := $(shell find -L ./ -type f -name '*.asmb' | sort)
 
-OBJ := $(addprefix $(BUILDDIR)/, $(ASM32_FILES:.asm32=.o) $(ASMB_FILES:.asmb=.o) $(C_FILES:.c=.o))
+OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(ASM32_FILES:.asm32=.o) $(ASMB_FILES:.asmb=.o) $(C_FILES:.c=.o))
 endif
 ifeq ($(TARGET), uefi)
 ASM64_FILES := $(shell find -L ./ -type f -name '*.asm64' | sort)
 ASM64U_FILES := $(shell find -L ./ -type f -name '*.asm64u' | sort)
 
-OBJ := $(addprefix $(BUILDDIR)/, $(ASM64_FILES:.asm64=.o) $(ASM64U_FILES:.asm64u=.o) $(C_FILES:.c=.o))
+OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(ASM64_FILES:.asm64=.o) $(ASM64U_FILES:.asm64u=.o) $(C_FILES:.c=.o))
 endif
 ifeq ($(TARGET), uefi32)
 ASM32_FILES := $(shell find -L ./ -type f -name '*.asm32' | sort)
 ASM32U_FILES := $(shell find -L ./ -type f -name '*.asm32u' | sort)
 
-OBJ := $(addprefix $(BUILDDIR)/, $(ASM32_FILES:.asm32=.o) $(ASM32U_FILES:.asm32u=.o) $(C_FILES:.c=.o))
+OBJ := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(ASM32_FILES:.asm32=.o) $(ASM32U_FILES:.asm32u=.o) $(C_FILES:.c=.o))
 endif
-HEADER_DEPS := $(addprefix $(BUILDDIR)/, $(C_FILES:.c=.d))
+HEADER_DEPS := $(addprefix $(call MKESCAPE,$(BUILDDIR))/, $(C_FILES:.c=.d))
 
 ifeq ($(TARGET), bios)
 all:
-	$(MAKE) builddir
-	$(MAKE) $(BUILDDIR)/limine_dbg.elf $(BUILDDIR)/limine.sys $(BUILDDIR)/stage2.bin $(BUILDDIR)/stage2.bin.gz
+	$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/limine_dbg.elf' '$(call SHESCAPE,$(BUILDDIR))/limine.sys' '$(call SHESCAPE,$(BUILDDIR))/stage2.bin' '$(call SHESCAPE,$(BUILDDIR))/stage2.bin.gz'
 else ifeq ($(TARGET), uefi)
 all:
-	$(MAKE) builddir
-	$(MAKE) $(BUILDDIR)/BOOTX64.EFI
+	$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/BOOTX64.EFI'
 else ifeq ($(TARGET), uefi32)
 all:
-	$(MAKE) builddir
-	$(MAKE) $(BUILDDIR)/BOOTIA32.EFI
+	$(MAKE) '$(call SHESCAPE,$(BUILDDIR))/BOOTIA32.EFI'
 endif
 
-builddir:
-	for i in $(OBJ); do mkdir -p `dirname $$i`; done
-
-$(BUILDDIR)/sys/smp_trampoline.bin: sys/smp_trampoline.real
-	nasm $< -f bin -o $@
+$(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.bin: sys/smp_trampoline.real
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm $< -f bin -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/sys/smp_trampoline.o: $(BUILDDIR)/sys/smp_trampoline.bin
-	cd "`dirname $<`" && \
-		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) "`basename $<`" $@
+$(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o: $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.bin
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	cd '$(call SHESCAPE,$(BUILDDIR))/sys' && \
+		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) smp_trampoline.bin '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/font.o: font.bin
-	cd "`dirname $<`" && \
-		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) "`basename $<`" $@
+$(call MKESCAPE,$(BUILDDIR))/font.o: font.bin
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) font.bin '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/tinf-copied: ../tinf/*
-	rm -rf $(BUILDDIR)/tinf
-	cp -r ../tinf $(BUILDDIR)/
-	touch $(BUILDDIR)/tinf-copied
+$(call MKESCAPE,$(BUILDDIR))/tinf-copied: ../tinf/*
+	rm -rf '$(call SHESCAPE,$(BUILDDIR))/tinf'
+	mkdir -p '$(call SHESCAPE,$(BUILDDIR))'
+	cp -r ../tinf '$(call SHESCAPE,$(BUILDDIR))/'
+	touch '$(call SHESCAPE,$(BUILDDIR))/tinf-copied'
 
-$(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o: $(BUILDDIR)/tinf-copied
-	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $(@:.o=.c) -o $@
+$(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o: $(call MKESCAPE,$(BUILDDIR))/tinf-copied
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$(@:.o=.c))' -o '$(call SHESCAPE,$@)'
 
 ifeq ($(TARGET), bios)
 
-$(BUILDDIR)/stage2.bin.gz: $(BUILDDIR)/stage2.bin
-	gzip -n -9 < $< > $@
+$(call MKESCAPE,$(BUILDDIR))/stage2.bin.gz: $(call MKESCAPE,$(BUILDDIR))/stage2.bin
+	gzip -n -9 < '$(call SHESCAPE,$<)' > '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/stage2.bin: $(BUILDDIR)/limine.sys
-	dd if=$< bs=$$(( 0x$$($(TOOLCHAIN_READELF) -S $(BUILDDIR)/limine.elf | grep .stage3.text | sed 's/^.*] //' | awk '{print $$3}' | sed 's/^0*//') - 0x8000 )) count=1 of=$@
+$(call MKESCAPE,$(BUILDDIR))/stage2.bin: $(call MKESCAPE,$(BUILDDIR))/limine.sys
+	dd if='$(call SHESCAPE,$<)' bs=$$(( 0x$$($(TOOLCHAIN_READELF) -S '$(call SHESCAPE,$(BUILDDIR))/limine.elf' | grep .stage3.text | sed 's/^.*] //' | awk '{print $$3}' | sed 's/^0*//') - 0x8000 )) count=1 of='$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/stage2.map.o: $(BUILDDIR)/limine_stage2only.elf
-	GENSYMS="`pwd`/gensyms.sh" && \
-	cd "`dirname $<`" && \
-	"$$GENSYMS" $(TOOLCHAIN_OBJDUMP) $< stage2 32
+$(call MKESCAPE,$(BUILDDIR))/stage2.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_stage2only.elf
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
+		'$(call SHESCAPE,$(SRCDIR))/gensyms.sh' $(TOOLCHAIN_OBJDUMP) '$(call SHESCAPE,$<)' stage2 32
 
-$(BUILDDIR)/full.map.o: $(BUILDDIR)/limine_nomap.elf
-	GENSYMS="`pwd`/gensyms.sh" && \
-	cd "`dirname $<`" && \
-	"$$GENSYMS" $(TOOLCHAIN_OBJDUMP) $< full 32
+$(call MKESCAPE,$(BUILDDIR))/full.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
+		'$(call SHESCAPE,$(SRCDIR))/gensyms.sh' $(TOOLCHAIN_OBJDUMP) '$(call SHESCAPE,$<)' full 32
 
-$(BUILDDIR)/limine.sys: $(BUILDDIR)/limine.elf
-	$(TOOLCHAIN_OBJCOPY) -O binary $< $@
+$(call MKESCAPE,$(BUILDDIR))/limine.sys: $(call MKESCAPE,$(BUILDDIR))/limine.elf
+	$(TOOLCHAIN_OBJCOPY) -O binary '$(call SHESCAPE,$<)' '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/limine_stage2only.elf: $(OBJ)
-	$(TOOLCHAIN_LD) $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_stage2only.ld -o $@ || \
+$(call MKESCAPE,$(BUILDDIR))/limine_stage2only.elf: $(OBJ)
+	$(TOOLCHAIN_LD) '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_stage2only.ld -o '$(call SHESCAPE,$@)' || \
 		( echo "This error may mean that stage 2 was trying to use stage 3 symbols before loading stage 3" && \
 		  false )
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s2.bin
-	cd "$(BUILDDIR)" && \
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s2.bin build-id.s2.o
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s3.bin
-	cd "$(BUILDDIR)" && \
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s3.bin build-id.s3.o
-	$(TOOLCHAIN_LD) $(BUILDDIR)/build-id.s2.o $(BUILDDIR)/build-id.s3.o $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_stage2only.ld -o $@
+	$(TOOLCHAIN_LD) '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.o' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.o' '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_stage2only.ld -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/limine_nomap.elf: $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o $(BUILDDIR)/stage2.map.o
-	$(TOOLCHAIN_LD) $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s2.bin
-	cd "$(BUILDDIR)" && \
+$(call MKESCAPE,$(BUILDDIR))/limine_nomap.elf: $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o $(call MKESCAPE,$(BUILDDIR))/stage2.map.o
+	$(TOOLCHAIN_LD) '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o '$(call SHESCAPE,$@)'
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s2.bin build-id.s2.o
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s3.bin
-	cd "$(BUILDDIR)" && \
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s3.bin build-id.s3.o
-	$(TOOLCHAIN_LD) $(BUILDDIR)/build-id.s2.o $(BUILDDIR)/build-id.s3.o $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o $@
+	$(TOOLCHAIN_LD) '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.o' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.o' '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_nomap.ld -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/limine.elf: $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o $(BUILDDIR)/stage2.map.o $(BUILDDIR)/full.map.o
-	$(TOOLCHAIN_LD) $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o $@
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s2.bin
-	cd "$(BUILDDIR)" && \
+$(call MKESCAPE,$(BUILDDIR))/limine.elf: $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o $(call MKESCAPE,$(BUILDDIR))/stage2.map.o $(call MKESCAPE,$(BUILDDIR))/full.map.o
+	$(TOOLCHAIN_LD) '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o '$(call SHESCAPE,$@)'
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s2.bin build-id.s2.o
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s3.bin
-	cd "$(BUILDDIR)" && \
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s3.bin build-id.s3.o
-	$(TOOLCHAIN_LD) $(BUILDDIR)/build-id.s2.o $(BUILDDIR)/build-id.s3.o $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o $@
+	$(TOOLCHAIN_LD) '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.o' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.o' '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker.ld -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/limine_dbg.elf: $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o $(BUILDDIR)/stage2.map.o $(BUILDDIR)/full.map.o
-	$(TOOLCHAIN_LD) $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_dbg.ld -o $@
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s2.bin
-	cd "$(BUILDDIR)" && \
+$(call MKESCAPE,$(BUILDDIR))/limine_dbg.elf: $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o $(call MKESCAPE,$(BUILDDIR))/stage2.map.o $(call MKESCAPE,$(BUILDDIR))/full.map.o
+	$(TOOLCHAIN_LD) '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_dbg.ld -o '$(call SHESCAPE,$@)'
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s2.bin build-id.s2.o
-	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id $@ $(BUILDDIR)/build-id.s3.bin
-	cd "$(BUILDDIR)" && \
+	$(TOOLCHAIN_OBJCOPY) -O binary --only-section=.note.gnu.build-id '$(call SHESCAPE,$@)' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.bin'
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
 		$(TOOLCHAIN_OBJCOPY) -B i8086 -I binary -O $(OBJCOPY_ARCH) build-id.s3.bin build-id.s3.o
-	$(TOOLCHAIN_LD) $(BUILDDIR)/build-id.s2.o $(BUILDDIR)/build-id.s3.o $^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_dbg.ld -o $@
+	$(TOOLCHAIN_LD) '$(call SHESCAPE,$(BUILDDIR))/build-id.s2.o' '$(call SHESCAPE,$(BUILDDIR))/build-id.s3.o' '$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -Tlinker_dbg.ld -o '$(call SHESCAPE,$@)'
 
 endif
 
-$(BUILDDIR)/gnu-efi:
-	cp -r ../gnu-efi $(BUILDDIR)/
+$(call MKESCAPE,$(BUILDDIR))/gnu-efi:
+	mkdir -p '$(call SHESCAPE,$(BUILDDIR))/'
+	cp -r ../gnu-efi '$(call SHESCAPE,$(BUILDDIR))/'
 	# gnu-efi's build system is broken and fails to actually detect clang.
 	# This is a workaround.
-	sed 's/-maccumulate-outgoing-args//g' < "$(BUILDDIR)/gnu-efi/Make.defaults" > sed.tmp
-	mv sed.tmp "$(BUILDDIR)/gnu-efi/Make.defaults"
+	sed 's/-maccumulate-outgoing-args//g' < '$(call SHESCAPE,$(BUILDDIR))/gnu-efi/Make.defaults' > sed.tmp
+	mv sed.tmp '$(call SHESCAPE,$(BUILDDIR))/gnu-efi/Make.defaults'
 
 ifeq ($(TARGET), uefi)
 
-$(BUILDDIR)/full.map.o: $(BUILDDIR)/limine_efi_nomap.elf
-	GENSYMS="`pwd`/gensyms.sh" && \
-	cd "`dirname $<`" && \
-	"$$GENSYMS" $(TOOLCHAIN_OBJDUMP) $< full 64
+$(call MKESCAPE,$(BUILDDIR))/full.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_efi_nomap.elf
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
+		'$(call SHESCAPE,$(SRCDIR))/gensyms.sh' $(TOOLCHAIN_OBJDUMP) '$(call SHESCAPE,$<)' full 64
 
-$(BUILDDIR)/BOOTX64.EFI: $(BUILDDIR)/limine_efi.elf
-	$(TOOLCHAIN_OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc -j .sbat --target efi-app-x86_64 --subsystem=10 $< $@
+$(call MKESCAPE,$(BUILDDIR))/BOOTX64.EFI: $(call MKESCAPE,$(BUILDDIR))/limine_efi.elf
+	$(TOOLCHAIN_OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc -j .sbat --target efi-app-x86_64 --subsystem=10 '$(call SHESCAPE,$<)' '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/gnu-efi/gnuefi/crt0-efi-x86_64.o $(BUILDDIR)/gnu-efi/gnuefi/libgnuefi.a: $(BUILDDIR)/gnu-efi
-	$(MAKE) -C $(BUILDDIR)/gnu-efi/gnuefi CC="$(TOOLCHAIN_CC) -m64 -march=x86-64 -mtune=generic" AR="$(TOOLCHAIN_AR)" ARCH=x86_64
+$(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/crt0-efi-x86_64.o $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/libgnuefi.a: $(call MKESCAPE,$(BUILDDIR))/gnu-efi
+	$(MAKE) -C '$(call SHESCAPE,$(BUILDDIR))/gnu-efi/gnuefi' CC="$(TOOLCHAIN_CC) -m64 -march=x86-64 -mtune=generic" AR="$(TOOLCHAIN_AR)" ARCH=x86_64
 
-$(BUILDDIR)/limine_efi_nomap.elf: $(BUILDDIR)/gnu-efi/gnuefi/crt0-efi-x86_64.o $(BUILDDIR)/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o
+$(call MKESCAPE,$(BUILDDIR))/limine_efi_nomap.elf: $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/crt0-efi-x86_64.o $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o
 	$(TOOLCHAIN_LD) \
 		-Tlinker_uefi_nomap.ld \
-		$^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $@
+		'$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/limine_efi.elf: $(BUILDDIR)/gnu-efi/gnuefi/crt0-efi-x86_64.o $(BUILDDIR)/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o $(BUILDDIR)/full.map.o
+$(call MKESCAPE,$(BUILDDIR))/limine_efi.elf: $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/crt0-efi-x86_64.o $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o $(call MKESCAPE,$(BUILDDIR))/full.map.o
 	$(TOOLCHAIN_LD) \
 		-Tlinker_uefi.ld \
-		$^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $@
+		'$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -o '$(call SHESCAPE,$@)'
 
 endif
 
 ifeq ($(TARGET), uefi32)
 
-$(BUILDDIR)/full.map.o: $(BUILDDIR)/limine_efi_nomap.elf
-	GENSYMS="`pwd`/gensyms.sh" && \
-	cd "`dirname $<`" && \
-	"$$GENSYMS" $(TOOLCHAIN_OBJDUMP) $< full 32
+$(call MKESCAPE,$(BUILDDIR))/full.map.o: $(call MKESCAPE,$(BUILDDIR))/limine_efi_nomap.elf
+	cd '$(call SHESCAPE,$(BUILDDIR))' && \
+		'$(call SHESCAPE,$(SRCDIR))/gensyms.sh' $(TOOLCHAIN_OBJDUMP) '$(call SHESCAPE,$<)' full 32
 
-$(BUILDDIR)/BOOTIA32.EFI: $(BUILDDIR)/limine_efi.elf
-	$(TOOLCHAIN_OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc -j .sbat --target efi-app-ia32 --subsystem=10 $< $@
+$(call MKESCAPE,$(BUILDDIR))/BOOTIA32.EFI: $(call MKESCAPE,$(BUILDDIR))/limine_efi.elf
+	$(TOOLCHAIN_OBJCOPY) -j .text -j .sdata -j .data -j .dynamic -j .dynsym -j .rel -j .rela -j .rel.* -j .rela.* -j .reloc -j .sbat --target efi-app-ia32 --subsystem=10 '$(call SHESCAPE,$<)' '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/gnu-efi/gnuefi/crt0-efi-ia32.o $(BUILDDIR)/gnu-efi/gnuefi/libgnuefi.a: $(BUILDDIR)/gnu-efi
-	$(MAKE) -C $(BUILDDIR)/gnu-efi/gnuefi CC="$(TOOLCHAIN_CC) -m32 -march=i686 -mtune=generic" AR="$(TOOLCHAIN_AR)" ARCH=ia32
+$(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/crt0-efi-ia32.o $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/libgnuefi.a: $(call MKESCAPE,$(BUILDDIR))/gnu-efi
+	$(MAKE) -C '$(call SHESCAPE,$(BUILDDIR))/gnu-efi/gnuefi' CC="$(TOOLCHAIN_CC) -m32 -march=i686 -mtune=generic" AR="$(TOOLCHAIN_AR)" ARCH=ia32
 
-$(BUILDDIR)/limine_efi_nomap.elf: $(BUILDDIR)/gnu-efi/gnuefi/crt0-efi-ia32.o $(BUILDDIR)/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o
+$(call MKESCAPE,$(BUILDDIR))/limine_efi_nomap.elf: $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/crt0-efi-ia32.o $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o
 	$(TOOLCHAIN_LD) \
 		-Tlinker_uefi32_nomap.ld \
-		$^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $@
+		'$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/limine_efi.elf: $(BUILDDIR)/gnu-efi/gnuefi/crt0-efi-ia32.o $(BUILDDIR)/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(BUILDDIR)/tinf/tinfgzip.o $(BUILDDIR)/tinf/tinflate.o $(BUILDDIR)/font.o $(BUILDDIR)/sys/smp_trampoline.o $(BUILDDIR)/full.map.o
+$(call MKESCAPE,$(BUILDDIR))/limine_efi.elf: $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/crt0-efi-ia32.o $(call MKESCAPE,$(BUILDDIR))/gnu-efi/gnuefi/libgnuefi.a $(OBJ) $(call MKESCAPE,$(BUILDDIR))/tinf/tinfgzip.o $(call MKESCAPE,$(BUILDDIR))/tinf/tinflate.o $(call MKESCAPE,$(BUILDDIR))/font.o $(call MKESCAPE,$(BUILDDIR))/sys/smp_trampoline.o $(call MKESCAPE,$(BUILDDIR))/full.map.o
 	$(TOOLCHAIN_LD) \
 		-Tlinker_uefi32.ld \
-		$^ $(LDFLAGS) $(INTERNAL_LDFLAGS) -o $@
+		'$(call OBJESCAPE,$^)' $(LDFLAGS) $(INTERNAL_LDFLAGS) -o '$(call SHESCAPE,$@)'
 
 endif
 
 -include $(HEADER_DEPS)
 
 ifeq ($(TARGET), uefi)
-$(BUILDDIR)/%.o: %.c $(BUILDDIR)/tinf-copied $(BUILDDIR)/gnu-efi
-	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/tinf-copied $(call MKESCAPE,$(BUILDDIR))/gnu-efi
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
 endif
 
 ifeq ($(TARGET), uefi32)
-$(BUILDDIR)/%.o: %.c $(BUILDDIR)/tinf-copied $(BUILDDIR)/gnu-efi
-	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/tinf-copied $(call MKESCAPE,$(BUILDDIR))/gnu-efi
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
 endif
 
 ifeq ($(TARGET), bios)
-$(BUILDDIR)/%.o: %.c $(BUILDDIR)/tinf-copied
-	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.c $(call MKESCAPE,$(BUILDDIR))/tinf-copied
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
 endif
 
 -include $(HEADER_DEPS)
 
 ifeq ($(TARGET), bios)
-$(BUILDDIR)/%.s2.o: %.s2.c
-	$(TOOLCHAIN_CC) $(S2CFLAGS) $(INTERNAL_CFLAGS) -c $< -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.s2.o: %.s2.c
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(S2CFLAGS) $(INTERNAL_CFLAGS) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@)'
 endif
 
 -include $(HEADER_DEPS)
 
 ifeq ($(TARGET), uefi)
-$(BUILDDIR)/%.32.o: %.32.c $(BUILDDIR)/gnu-efi
-	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS32) -c $< -o $@.32
-	$(TOOLCHAIN_OBJCOPY) -I elf32-i386 -O elf64-x86-64 $@.32 $@
-	rm $@.32
+$(call MKESCAPE,$(BUILDDIR))/%.32.o: %.32.c $(call MKESCAPE,$(BUILDDIR))/gnu-efi
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	$(TOOLCHAIN_CC) $(CFLAGS) $(INTERNAL_CFLAGS32) -c '$(call SHESCAPE,$<)' -o '$(call SHESCAPE,$@).32'
+	$(TOOLCHAIN_OBJCOPY) -I elf32-i386 -O elf64-x86-64 '$(call SHESCAPE,$@).32' '$(call SHESCAPE,$@)'
+	rm '$(call SHESCAPE,$@).32'
 endif
 
 ifeq ($(TARGET), bios)
-$(BUILDDIR)/%.o: %.asm32
-	nasm $< -F dwarf -g -Werror -f elf32 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm32
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -F dwarf -g -Werror -f elf32 -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/%.o: %.asmb
-	nasm $< -F dwarf -g -Werror -f elf32 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asmb
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -F dwarf -g -Werror -f elf32 -o '$(call SHESCAPE,$@)'
 endif
 
 ifeq ($(TARGET), uefi)
-$(BUILDDIR)/%.o: %.asm64
-	nasm $< -F dwarf -g -Werror -f elf64 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm64
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -F dwarf -g -Werror -f elf64 -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/%.o: %.asm64u
-	nasm $< -F dwarf -g -Werror -f elf64 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm64u
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -F dwarf -g -Werror -f elf64 -o '$(call SHESCAPE,$@)'
 endif
 
 ifeq ($(TARGET), uefi32)
-$(BUILDDIR)/%.o: %.asm32
-	nasm $< -F dwarf -g -Werror -f elf32 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm32
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -F dwarf -g -Werror -f elf32 -o '$(call SHESCAPE,$@)'
 
-$(BUILDDIR)/%.o: %.asm32u
-	nasm $< -F dwarf -g -Werror -f elf32 -o $@
+$(call MKESCAPE,$(BUILDDIR))/%.o: %.asm32u
+	dirname '$(call SHESCAPE,$@)' | xargs -d '\n' mkdir -p
+	nasm '$(call SHESCAPE,$<)' -F dwarf -g -Werror -f elf32 -o '$(call SHESCAPE,$@)'
 endif
 
 clean:
-	rm -rf $(BUILDDIR)
+	rm -rf '$(call SHESCAPE,$(BUILDDIR))'
diff --git a/stage23/gensyms.sh b/stage23/gensyms.sh
index b32c9433..61a33aa1 100755
--- a/stage23/gensyms.sh
+++ b/stage23/gensyms.sh
@@ -2,9 +2,21 @@
 
 set -e
 
-SCRIPT_PATH="$(dirname $0)"
+TMP0=$(mktemp)
 
-"$SCRIPT_PATH/test_pipefail.sh" && set -o pipefail
+cat >"$TMP0" <<EOF
+#!/bin/sh
+
+set -e
+
+set -o pipefail 2>/dev/null
+EOF
+
+chmod +x "$TMP0"
+
+"$TMP0" && set -o pipefail
+
+rm "$TMP0"
 
 TMP1=$(mktemp)
 TMP2=$(mktemp)
diff --git a/stage23/test_pipefail.sh b/stage23/test_pipefail.sh
deleted file mode 100755
index c6a34fa1..00000000
--- a/stage23/test_pipefail.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-set -e
-
-set -o pipefail 2>/dev/null
tab: 248 wrap: offon