#!/usr/bin/env python3 from glob import glob file = open('Makefile', 'w', encoding='utf-8') def raw(s): print(s, file=file) def srcobj(path): srcs = glob(path + '/**/*.[csS]', recursive=True) objs = ['out/obj/' + src.removeprefix('src/') + '.o' for src in srcs] return ' ' + ' '.join(objs) + ' ' def t(out, deps='', cmds=[], phony=False, verbose=False): if phony: raw(f".PHONY: {out}") else: cmds = ["mkdir -p $(@D)"] + cmds raw(f"{out}: {deps}") v = '' if verbose else '@' for cmd in cmds: raw(f"\t{v}{cmd}") raw(""" # automatically generated by ./configure PATH := $(shell pwd)/toolchain/prefix/bin/:$(PATH) AR = x86_64-camellia-ar AS = x86_64-camellia-as CC = x86_64-camellia-gcc CFLAGS = -g -std=gnu99 -O2 -fPIC -ftrack-macro-expansion=0 \ -Wall -Wextra -Wold-style-definition -Wno-address-of-packed-member \ -Werror=incompatible-pointer-types -Werror=implicit-function-declaration CFLAGS_KERNEL = $(CFLAGS) \ -ffreestanding -mno-sse -mgeneral-regs-only \ --sysroot=src/kernel/sysroot/ -Isrc/ -Isrc/libk/include/ CFLAGS_LIBC = $(CFLAGS) -ffreestanding -Isrc/ SPARSEFLAGS = $(CFLAGS_KERNEL) -Wno-non-pointer-null """) t('all', 'out/boot.iso out/fs.e2 check', phony=True) t('portdeps', 'out/libc.a out/libm.a src/libc/include/__errno.h', phony=True) # TODO check userland sources too t('check', '', [ 'find src/kernel/ -type f -name *.c | xargs -n 1 sparse $(SPARSEFLAGS)' ], phony=True) t('clean', '', [ 'rm -rf out/' ], phony=True, verbose=True) raw(""" PORTS= .PHONY: ports # portdeps is phony, so ports/% is automatically "phony" too ports: $(patsubst %,ports/%,$(PORTS)) ports/%: portdeps +$@/port install """) t('out/boot.iso', 'out/fs/boot/kernel out/fs/boot/grub/grub.cfg out/fs/boot/init', [ 'grub-mkrescue -o $@ out/fs/ >/dev/null 2>&1' ]) t('out/fs/boot/kernel', 'src/kernel/arch/amd64/linker.ld' + srcobj('src/kernel/') + srcobj('src/libk/'), [ '$(CC) -nostdlib -Wl,-zmax-page-size=4096 -Wl,--no-warn-mismatch -Wl,-no-pie -T $^ -o $@', 'grub-file --is-x86-multiboot2 $@ || echo "$@ has an invalid multiboot2 header"', 'grub-file --is-x86-multiboot2 $@ || rm $@; test -e $@' ]) t('out/libc.a', srcobj('src/libc/') + srcobj('src/libk/'), [ '$(AR) rcs $@ $^' ]) t('out/libm.a', '', [ '$(AR) rcs $@ $^' ]) t('out/bootstrap', 'out/bootstrap.elf', ['objcopy -O binary $^ $@']) t('out/bootstrap.elf', 'src/bootstrap/linker.ld' + srcobj('src/bootstrap/') + 'out/libc.a', [ '$(CC) -nostdlib -Wl,-no-pie -T $^ -o $@' ]) t('out/fs/boot/init', 'out/bootstrap out/initrd.tar', ['cat $^ > $@']) t('out/fs/boot/grub/grub.cfg', 'src/kernel/arch/amd64/grub.cfg', ['cp $< $@']) t('out/fs.e2', '', ['mkfs.ext2 $@ 1024 >/dev/null']) userbins = glob('*', root_dir='src/cmd/') raw("USERBINS = " + " ".join(userbins)) for cmd in userbins: t(f'out/initrd/bin/amd64/{cmd}', 'out/libc.a' + srcobj(f'src/cmd/{cmd}'), [ '$(CC) $^ -o $@' ]) # don't build the example implementation from libext2 t('out/obj/cmd/ext2fs/ext2/example.c.o', '', ['touch $@']) t('out/initrd/%', 'sysroot/%', ['cp $< $@']) t('out/initrd.tar', '$(patsubst sysroot/%,out/initrd/%,$(shell find sysroot/ -type f)) ' '$(patsubst %,out/initrd/bin/amd64/%,$(USERBINS)) ' '$(shell find out/initrd/) ' 'ports ', ['cd out/initrd; tar chf ../initrd.tar *']) t('src/libc/include/__errno.h', 'src/libc/include/__errno.h.awk src/libk/include/camellia/errno.h', ['awk -f $^ > $@']) t('src/libc/syscall.c', 'src/libc/syscall.c.awk src/libk/include/camellia/syscalls.h', ['awk -f $^ > $@']) def cc(rule, args): t(f'out/obj/{rule}.o', f'src/{rule}', [f'$(CC) -c $^ -o $@ {args}']) cc("%.c", "$(CFLAGS)") cc("%.s", "$(CFLAGS)") cc("%.S", "$(CFLAGS)") cc("bootstrap/%.c", "$(CFLAGS) -fno-pie") cc("kernel/%.c", "$(CFLAGS_KERNEL)") cc("libc/%.c", "$(CFLAGS_LIBC)") cc("libk/%.c", "$(CFLAGS_KERNEL)") cc("kernel/arch/amd64/32/%.c", "$(CFLAGS_KERNEL) -fno-pic -m32") cc("kernel/arch/amd64/32/%.s", "$(CFLAGS_KERNEL) -fno-pic -m32") cc("libc/vendor/dlmalloc/%.c", "$(CFLAGS_LIBC) -DMAP_ANONYMOUS -DHAVE_MORECORE=0 -DNO_MALLOC_H -Wno-expansion-to-defined -Wno-old-style-definition")