#
# OS/161 build environment: build a kernel
#
# Note that kernels build in kernel build directories and not into
# $(BUILDDIR).
#

#
# The makefile stub generated by the kernel config script looks like this:
#   KTOP=../..			# top of the kernel tree
#   TOP=$(KTOP)/..		# top of the whole tree
#   KDEBUG=-g			# debug vs. optimize
#   CONFNAME=GENERIC		# name of the kernel config file
#   .include "$(TOP)/mk/os161.config.mk"
#   .include "files.mk"
#   .include "$(TOP)/mk/os161.kernel.mk"
#
# files.mk is also generated by the kernel config script.
#

#
# Additional defs for building a kernel.
#

# All sources.
ALLSRCS=$(SRCS) $(SRCS.MACHINE.$(MACHINE)) $(SRCS.PLATFORM.$(PLATFORM))

# Filename for the kernel.
KERNEL=kernel

# Don't use headers and libraries that don't belong to the kernel.
# Kernels have to be standalone.
KCFLAGS+=-nostdinc
KLDFLAGS+=-nostdlib

# Do use the kernel's header files.
KCFLAGS+=-I$(KTOP)/include -I$(KTOP)/dev -I. -Iincludelinks

# Tell gcc that we're building something other than an ordinary
# application, so it makes fewer assumptions about standard library
# functions.
KCFLAGS+=-ffreestanding

# Define _KERNEL so code in src/common can tell which header files
# it should use.
KCFLAGS+=-D_KERNEL

# Provide the linker with a "linker script". This is a piece of
# obscure mumble that tells the linker how to put together the output
# program. We need it because a kernel needs (in general) to be linked
# to run at a different virtual address from an ordinary program.
#
# Traditionally all you need to do is pass -Ttext to set the address
# for the text (code), but this doesn't work with the GNU linker by
# default because of a silly design bug.
#
# Look for a linker script for the PLATFORM first, and if not that try
# MACHINE, and if neither of those exists assume we don't actually
# need one.

.if exists($(KTOP)/arch/$(PLATFORM)/conf/ldscript)
KLDFLAGS+=-T $(KTOP)/arch/$(PLATFORM)/conf/ldscript
.elif exists($(KTOP)/arch/$(MACHINE)/conf/ldscript)
KLDFLAGS+=-T $(KTOP)/arch/$(MACHINE)/conf/ldscript
.endif

#
# This should expand to all the header files in the kernel so they can
# be fed to tags.
#
TAGS_HEADERS=\
	$(KTOP)/*/*.h \
	$(KTOP)/include/kern/*.h \
	$(KTOP)/dev/*/*.h \
	$(KTOP)/arch/$(MACHINE)/*/*.h \
	$(KTOP)/arch/$(MACHINE)/include/kern/*.h \
	$(KTOP)/arch/$(PLATFORM)/*/*.h

#
# Rules.
#

# Default rule: link the kernel.
all: includelinks .WAIT $(KERNEL)

#
# Here's how we link the kernel.
#
# vers.c/.o is generated on every build. It contains a numeric serial
# number incremented every time newvers.sh is run.  These values are
# printed out by newvers.sh and are also displayed at boot time. This
# makes it possible to tell at a glance whether you're actually
# running the same kernel you just compiled.
#
# The version number is kept in the file called "version" in the build
# directory.
#
# By immemorial tradition, "size" is run on the kernel after it's linked.
#
$(KERNEL):
	$(KTOP)/conf/newvers.sh $(CONFNAME)
	$(CC) $(KCFLAGS) -c vers.c
	$(LD) $(KLDFLAGS) $(OBJS) vers.o -o $(KERNEL)
	@echo '*** This is $(CONFNAME) build #'`cat version`' ***'
	$(SIZE) $(KERNEL)

#
# Use the -M argument to gcc to get it to output dependency information.
# Note that we use -M, which includes deps for #include <...> files,
# rather than -MM, which doesn't. This is because we are the operating
# system: the #include <...> files are part of our project -- in fact, in
# the kernel they're the kernel's own include files -- and they will be
# changing!
#
# Each source file's depend info gets dumped into its own .depend file
# so the overall depend process parallelizes. Otherwise (assuming you
# have a reasonably modern machine) this is the slowest part of the
# kernel build.
#
depend:
	$(MAKE) includelinks
	rm -f .depend.* || true
	$(MAKE) realdepend

.for _S_ in $(ALLSRCS)
DEPFILES+=.depend.$(_S_:T)
.depend.$(_S_:T):
	$(CC) $(KCFLAGS) -M $(_S_) > .depend.$(_S_:T)
.endfor
realdepend: $(DEPFILES)
	cat $(DEPFILES) > .depend

# our make does this implicitly
#.-include ".depend"

#
# This allows includes of the forms
#    <machine/foo.h>
#    <kern/machine/foo.h>
#    <platform/foo.h>
# and also (for this platform/machine)
#    <mips/foo.h>
#    <kern/mips/foo.h>
#    <sys161/foo.h>
# to go to the right place.
#
includelinks:
	mkdir includelinks
	mkdir includelinks/kern
	ln -s ../../../arch/$(MACHINE)/include includelinks/$(MACHINE)
	ln -s ../../../../arch/$(MACHINE)/include/kern \
						includelinks/kern/$(MACHINE)
	ln -s ../../../arch/$(PLATFORM)/include includelinks/$(PLATFORM)
	ln -s $(MACHINE) includelinks/machine
	ln -s $(MACHINE) includelinks/kern/machine
	ln -s $(PLATFORM) includelinks/platform

#
# Remove everything generated during the compile.
# (To remove absolutely everything automatically generated, you can just
# blow away the whole compile directory.)
#
clean:
	rm -f *.o *.a tags $(KERNEL)
	rm -rf includelinks

distclean cleandir: clean
	rm -f .depend

#
# Rerun config for this configuration.
#
reconfig:
	(cd $(KTOP)/conf && ./config $(CONFNAME))

#
# [ -d $(OSTREE) ] succeeds if $(OSTREE) is a directory.
# (See test(1).) Thus, if $(OSTREE) doesn't exist, it will be created.
#
# The kernel gets installed at the top of the installed system tree.
# Since with OS/161 it's relatively likely that you'll be working with
# several configurations at once, it gets installed under the name of
# this config, and a symbolic link with the "real" name is set up to
# point to the last kernel installed.
#
install:
	[ -d $(OSTREE) ] || mkdir $(OSTREE)
	cp $(KERNEL) $(OSTREE)/$(KERNEL)-$(CONFNAME)
	-rm -f $(OSTREE)/$(KERNEL)
	ln -s $(KERNEL)-$(CONFNAME) $(OSTREE)/$(KERNEL)

#
# Run tags on all the sources and header files. This is probably not
# the most useful way to do this and may need attention. (XXX?)
#
tags:
	ctags -wtd $(ALLSRCS) $(TAGS_HEADERS)

#
# This tells make that these rules are not files so it (hopefully)
# won't become confused if files by those names appear.
#
.PHONY: all depend realdepend clean reconfig install tags

#
# Compilation rules.
#
.for _S_ in $(ALLSRCS)
OBJS+=$(_S_:T:R).o
$(_S_:T:R).o: $(_S_)
	$(CC) $(KCFLAGS) -c $(_S_)
.endfor

# Make the kernel depend on all the object files.
$(KERNEL): $(OBJS)

# End.
