Esta pagina se ve mejor con JavaScript habilitado

MercuryOS Wildcards gmake

 ·  🎃 kr0m

Conforme vaya creciendo nuestro SO cada vez resultará mas inmanegable tener todos los ficheros en un único directorio, debemos definir una estructura, una froma sencilla de organizar el código sería esta, boot -> Cualquier código relacionado con el bootloader o subrutinas utilizadas por este, kernel -> Cualquier código relacionado con el kernel, drivers -> Código de drivers específicos.

Antes de comenzar es recomendable que leas estos artículos anteriores:


Creamos la estructura de directorios:

mkdir -p Project/boot/
mkdir -p Project/kernel/
mkdir -p Project/drivers/

Copiamos o movemos los ficheros necesarios:

cp kernel_entry.asm boot_sect.asm boot_sect_print.asm boot_sect_print_hex.asm boot_sect_disk.asm 32bit-gdt.asm 32bit-print.asm 32bit-switch.asm Project/boot
cp kernel.c kernel_entry.asm Project/kernel

Make permite la utilización de wildcards, de este modo los scripts de compilación serán mas cortos y fáciles de mantener.

Podemos expandir los nombres de los ficheros que macheen un patrón:

C_SOURCES = $(wildcard kernel /*.c drivers /*.c)

Podemos crear una lista a partir de ciertos ficheros origen:

OBJ = $ {C_SOURCES : .c = .o}

Para utilizar la lista basta con hacer referencia a ella ${OBJ}:

kernel .bin : kernel/kernel_entry.o ${OBJ}
    ld -o $@ -Ttext 0x1000 $^ --oformat binary

Ahora que hemos movido los ficheros hay que modificar los includes de boot_sect.asm

vi boot/boot_sect.asm

%include "boot/boot_sect_print.asm"
%include "boot/boot_sect_print_hex.asm"
%include "boot/boot_sect_disk.asm"
%include "boot/32bit-gdt.asm"
%include "boot/32bit-print.asm"
%include "boot/32bit-switch.asm"

El Makefile final quedaría del siguiente modo:

vi Makefile

# Automatically generate lists of sources using wildcards.
C_SOURCES = $(wildcard kernel/*.c drivers/*.c)
HEADERS = $(wildcard kernel/*.h drivers/*.h)

# TODO : Make sources dep on all header files .
# Convert the *.c filenames to *.o to give a list of object files to build
OBJ = ${C_SOURCES:.c=.o}

# Run Qemu to simulate booting of our code.
run : all
	qemu-system-x86_64 os-image

# Run Qemu to simulate booting of our code with debugging session.
# gdb -ex "set architecture i386:x86-64" -ex "set disassembly-flavor intel" -ex "target remote localhost:1234" -ex "symbol-file kernel/kernel.elf"
debug : all kernel/kernel.elf
	qemu-system-x86_64 os-image -s -S &

# Used for debugging purposes
kernel/kernel.elf: boot/kernel_entry.o ${OBJ}
	ld -o $@ -Ttext 0x1000 $^

# Defaul build target
all: os-image

# This is the actual disk image that the computer loads
# which is the combination of our compiled bootsector and kernel
os-image : boot/boot_sect.bin kernel/kernel.bin
	cat $^ > os-image

# This builds the binary of our kernel from two object files :
# - the kernel_entry, which jumps to main () in our kernel
# - the compiled C kernel
kernel/kernel.bin : kernel/kernel_entry.o ${OBJ}
	ld -o $@ -Ttext 0x1000 $^ --oformat binary

# Generic rule for compiling C code to an object file
# For simplicity , we C files depend on all header files.
%.o : %.c ${HEADERS}
	cc -g -m32 -ffreestanding -c $< -o $@

# Assemble the kernel_entry.
%.o : %.asm
	nasm -f elf $< -o $@

%.bin : %.asm
	nasm -f bin $< -o $@

clean :
	rm -fr *.bin *.dis *.o *.core os-image
	rm -fr kernel/*.o boot/*.bin drivers/*.o

NOTA: Una vez mas remarcar la importancia de utilizar tabulaciones reales y no espacios en los ficheros Makefile.

Comprobamos que todo el proceso funcione:

gmake clean
gmake run

Si te ha gustado el artículo puedes invitarme a un RedBull aquí