camellia/configure

178 lines
5.8 KiB
Python
Executable File

#!/usr/bin/env python3
from glob import glob
import os
file = open('Makefile', 'w', encoding='utf-8')
def raw(s):
print(s, file=file)
def srcobj(path):
srcs = None
if os.path.isfile(path):
srcs = [path]
else:
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 '$(V)'
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
V=@
CFLAGS = -g -std=gnu99 -Os -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=out/sysrootk/ -Isrc/
CFLAGS_LIBC = $(CFLAGS) -ffreestanding -Isrc/
SPARSEFLAGS = $(CFLAGS_KERNEL) -Wno-non-pointer-null -Iout/sysrootk/usr/include/ -D__SPARSE
LIB = out/sysrootu/lib/libc.a out/sysrootu/lib/libm.a out/sysrootu/lib/crt0.o
""")
t('all', 'out/boot.iso out/fs.e2 check', phony=True)
t('portdeps', 'out/sysrootu/usr/include/ $(LIB)', 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.gz', [
'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 $@ -lgcc',
'grub-file --is-x86-multiboot2 $@ || echo "$@ has an invalid multiboot2 header"',
'grub-file --is-x86-multiboot2 $@ || rm $@; test -e $@'
])
t('out/sysrootu/lib/libc.a', srcobj('src/libc/') + srcobj('src/libk/'), [
'$(AR) rcs $@ $^'
])
t('out/sysrootu/lib/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/sysrootu/lib/libc.a', [
'$(CC) -nostdlib -Wl,-no-pie -T $^ -o $@'
])
t('out/fs/boot/init.gz', 'out/bootstrap out/initrd.tar', ['cat $^ | gzip > $@'])
t('out/fs/boot/grub/grub.cfg', 'src/kernel/arch/amd64/grub.cfg', ['cp $< $@'])
t('out/fs.e2', '', ['mkfs.ext2 $@ 1024 >/dev/null'])
userbins = []
for src in glob('*', root_dir='src/cmd/'):
cmd = src.removesuffix('.c')
t(f'out/initrd/bin/amd64/{cmd}', '$(LIB) ' + srcobj(f'src/cmd/{src}'), [
'$(CC) $^ -o $@'
])
userbins.append(cmd)
raw("USERBINS = " + " ".join(userbins))
# 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 includes(target, modules, deps='', cmds=[]):
dirs = " ".join([f"src/{mod}/include/" for mod in modules])
t(target, deps, [
"set -eu;"
f"for file in $$(find {dirs} -type f,l -name '*.h'); do "
" out=$@$${file#src/*/include/};"
" mkdir -p $$(dirname $$out);"
" ln -rfs $$file $$out;"
"done"
] + cmds, phony=True)
includes("out/sysrootk/usr/include/", ["libk"])
# this must work without a toolchain available, as it's required to build
# the toolchain
includes("out/sysrootu/usr/include/", ["libc", "libk"], 'src/libc/include/__errno.h', [
'ln -rfs src/libc/include/__errno.h $@',
])
t('out/sysrootu/lib/crt0.o', 'out/obj/libc/_start.s.o', ['cp $^ $@'])
def cc(rule, args, deps):
# The | marks an order-only dependency. This means that sysroot will be
# built every time the rule is ran, but without forcing a rebuild if the
# rule is fresh.
# https://www.gnu.org/software/make/manual/make.html#index-order_002donly-prerequisites
t(f'out/obj/{rule}.o', f'src/{rule} | {deps}', [
f'$(CC) {args} -c $< -o $@'
])
cc("%.c", "$(CFLAGS)", "out/sysrootu/usr/include/")
cc("%.s", "$(CFLAGS)", "out/sysrootu/usr/include/")
cc("%.S", "$(CFLAGS)", "out/sysrootu/usr/include/")
cc("bootstrap/%.c", "$(CFLAGS) -fno-pie", "out/sysrootu/usr/include/")
cc("libc/%.c", "$(CFLAGS_LIBC)", "out/sysrootu/usr/include/")
cc("libc/vendor/dlmalloc/%.c", "$(CFLAGS_LIBC) -DMAP_ANONYMOUS -DHAVE_MORECORE=0 -DNO_MALLOC_H -Wno-expansion-to-defined -Wno-old-style-definition", "out/sysrootu/usr/include/")
cc("kernel/%.c", "$(CFLAGS_KERNEL)", "out/sysrootk/usr/include/")
cc("kernel/%.s", "$(CFLAGS_KERNEL)", "out/sysrootk/usr/include/")
cc("kernel/%.S", "$(CFLAGS_KERNEL)", "out/sysrootk/usr/include/")
cc("libk/%.c", "$(CFLAGS_KERNEL)", "out/sysrootk/usr/include/")
cc("libk/%.s", "$(CFLAGS_KERNEL)", "out/sysrootk/usr/include/")
cc("libk/%.S", "$(CFLAGS_KERNEL)", "out/sysrootk/usr/include/")
cc("kernel/arch/amd64/32/%.c", "$(CFLAGS_KERNEL) -fno-pic -m32", "out/sysrootk/usr/include/")
cc("kernel/arch/amd64/32/%.s", "$(CFLAGS_KERNEL) -fno-pic -m32", "out/sysrootk/usr/include/")