Skip to main content
Department of Information Technology

Adapting the Example Makefile

In order to build your OS project, you need to adapt the example Makefile included with the example files.

You will add one or more build targets to the file, i.e. specific binaries that you want to be able to build. We propose that you have one main target for your operating system, and then zero or more smaller test programs. It is easiest just to keep one makefile for all cases, and keep this with your source files.

Structure of the Makefile

If you look at the example makefile, you will see the following at the top of the file:

# Object files for the examples
OBJS_TIMER=example_timer.o asm.o debug.o
OBJS_UART=example_uart.o asm.o i8259.o debug.o
OBJS_SYSCALL=example_syscall.o asm.o syscall.o debug.o

This basically lists for each target which files are part of it. Note that all files have the ending .o, indicating an object file, i.e. a compiled file. For your own targets, you will add a new line here, listing the object files which are part of it. Basically, this will be the names of the .c and .S (assembler) source files you use in your project, with the ending .o instead. There are rules in the makefile that makes the make program automatically compile the souce files and generate the object files.

In addition to listing the object files, you also need to specify build rules for each target. If you look at the file, you find the following interesting lines:

# Build the timer example
example_timer: $(OBJS_TIMER)
        $(LD) $(ARCH) -o example_timer $(OBJS_TIMER)

# Build the UART example
example_uart: $(OBJS_UART)
        $(LD) $(ARCH) -o example_uart $(OBJS_UART)

# Build the syscall example
example_syscall: $(OBJS_SYSCALL)
        $(LD) $(ARCH) -o example_syscall $(OBJS_SYSCALL)

# clean: remove object files and emacs backup files
clean:
        rm -f *.o *~

Each line starting with a NAME: is the start of a build rule. It basically says, "to build the target that we call NAME, please do the following". In our case:

  • We first say $(OBJS_NAME), which asks make to build all the files specified in the list earlier in the file. This will create the set of object files from the C and assembler files.
  • The next line specifies the linking (by tradition, the linker program is called ld). The interesting part of the line is the -o NAME which determines the name of the output file (which is arbitrary and can differ from the name of the target), and the specification $(OBJS_NAME) that asks the linker to take all the object files into the linking.

Finally, there is a special target clean, which deletes all object files and emacs backup files in the directory. Having a clean target is common, as doing a make clean before building a project ensures that all files are freshly recompiled.

Adding a target to build

Assume that you have a small operating system consisting of the following files: os_main.c, low_level_stuff.S, and user_progs.c. You would then create a binary called our_os to load into Simics and run. You need to do the following:

  • Add a new list of .o files to the start of the file
  • Add a new build target line towards the end

The list of .o files would be:

OBJS_OS=os_main.o low_level_stuff.o user_progs.o

The build target lines would be:

our_os: $(OBJS_OS)
        $(LD) $(ARCH) -o our_os $(OBJS_OS)

Note that you need to change both the target name (our_os:) and the name of the output binary (-o our_os). And that you list OBJS_OS on both lines.

You can now do the following on the command line to build your operating system:

host$ make our_os

Which will compile all the specified files and create the binary our_os. You can then run this in Simics:

host$ ./run.sh our_os

Updated  2004-10-25 19:17:18 by Jakob Engblom.