########################################################################
#                                                                      #
# Standard rulesets for use when compiling and installing this system. #
#                                                                      #
########################################################################

ifndef TOPDIR
$(error TOPDIR is not defined)
endif

include $(TOPDIR)/Make.defs

########################################################################
#
# This file expects the following variables to have been defined before
# it is included into any other Makefile on this system:
#
#	BASEDIR 	The relative path from the directory the Makefile
#			is in to the base directory. This is used quite
#			extensively through these definitions, so must be
#			correct.
#
#	USEBCC		Whether to compile using BCC or GCC. If this is
#			set to 'N' it compiles using GCC, otherwise it
#			compiles using BCC.
#
#	CLEANDEP	Any files in the current directory that the
#			`make dep` command is dependent on.
#
#	CLEANME 	Any files in the current directory to be removed
#			by the `make clean` command that are not in the
#			standard list of files matching "*~", "*.bak",
#			"*.a", "*.o", "*.map" or "*.tmp" or named "core".
#			Also removed are any files matching "*.s" for
#			which a "*.c" or "*.S" file also exists.
#
#	DEPEND		Any files in the current directory that the
#			`make dep` command is dependent on.
#
#	DISTFILES	Any files in the current directory that are to
#			be included in a distribution made with the
#			`make dist` command that are not in the standard
#			list. This standard list consists of those files
#			NOT removed by `make clean` that match any of
#			the patterns "*.?", "*.cc", "*.html", "*.in",
#			"*.sh", "*.tk", "*.txt", "Makefile*" or "README*".
#
#	NOINDENT	Any files in the current directory that are NOT
#			to be processed in a `make indent` run. Usually,
#			these files include sections of assembly code,
#			which gets mangled by the `indent` command.
#
# No other variables should be defined before including this file.
#
#########################################################################
# State the current version of this system.

VERSION 	= 0	# (0-255)
PATCHLEVEL	= 3	# (0-255)
SUBLEVEL	= 0	# (0-255)
#PRE		= 0	# (0-255)	If not a pre, comment this line.

#########################################################################
# Specify the architecture we will use.

ARCH		= i86

#########################################################################
# Specify the target for the netboot image.

TARGET_NB_IMAGE	= $(TOPDIR)/elks/nbImage

#########################################################################
#									#
#   From here onwards, it is not normally necessary to edit this file   #
#									#
#########################################################################
# Define variables directly dependant on the current version number.

ifeq (x$(PRE), x)

DIST		= $(shell printf '%u.%u.%u' \
			$(VERSION) $(PATCHLEVEL) $(SUBLEVEL))

else

DIST		= $(shell printf '%u.%u.%u-pre%u' \
			$(VERSION) $(PATCHLEVEL) $(SUBLEVEL) $(PRE))

endif

#########################################################################
# Specify the various directories.

ARCH_DIR	= arch/$(ARCH)

INCLUDES = -I$(TOPDIR)/include -I$(TOPDIR)/elks/include

MYDIR		= $(shell pwd | sed 's:^$(TOPDIR):.:')

#########################################################################
# Specify the directory we are to create the distribution copy of this
# directory in, in such a way that no . or .. directories occur. This
# also makes this an absolute path, but that fact is not important.

DISTDIR 	= $(shell $(BASEDIR)/scripts/setdir $(TOPDIR)/elks-$(DIST)/$(MYDIR))

#########################################################################
# Specify the standard definitions to be given to system programs.

CCDEFS = -DUTS_RELEASE=\"$(DIST)\"			\
		  -D__KERNEL__ -DUSE_IA16

#########################################################################
# Set the target environment and the compiler to use.

ifeq ($(wildcard $(TOPDIR)/.config),)
    MK_ARCH	= ibmpc
    MK_CPU	= 8086
else
    MK_ARCH	= $(shell grep '^CONFIG_ARCH_' $(TOPDIR)/.config \
			| cut -d = -f 1 | cut -d _ -f 3- | tr A-Z a-z)
    MK_CPU	= $(shell grep '^CONFIG_CPU_' $(TOPDIR)/.config \
			| cut -d = -f 1 | cut -d _ -f 3- | tr A-Z a-z)
endif

# Use GCC-IA16 compiler

# Not linked to any target C library ('freestanding')
# Use ES only for segment ('elks')
# Small memory model: CS != DS == SS
# No relocation stuff related to MSDOS 'MZ' executable

CROSS_CC = ia16-elf-gcc
CROSS_CFLAGS = -ffreestanding -fno-inline -melks -mcmodel=small -mno-segment-relocation-stuff

#########################################################################
# Define architecture-specific flags.

ifeq ($(MK_ARCH), ibmpc)
    ARCH_AS	=
    ARCH_CC	=
    ARCH_LD	=
endif

ifeq ($(MK_ARCH), sibo)
    ARCH_AS	=
    ARCH_CC	=
    ARCH_LD	= -D 0xC00 -H 0x480
endif

#########################################################################
# Define CPU-specific flags.

ifeq ($(MK_CPU), 8086)
    CPU_AS	= -mtune=i8086
    CPU_CC	= -mtune=i8086
    CPU_LD	=
endif

ifeq ($(MK_CPU), 80186)
    CPU_AS	= -mtune=i186
    CPU_CC	= -mtune=i186
    CPU_LD	=
endif

ifeq ($(MK_CPU), 80286)
    CPU_AS	= -mtune=i286
    CPU_CC	= -mtune=i286
    CPU_LD	=
endif

#########################################################################
# Export all variables.

.EXPORT_ALL_VARIABLES:

#########################################################################
# Specify the tools to use, with their flags.

################################
# Common definitions

CC_PROTO	= gcc $(INCLUDES) -M -MG $(CCDEFS)
CFLBASE 	= $(INCLUDES) $(CCDEFS)
CPP		= $(CC) $(INCLUDES) -E $(CCDEFS) -ansi
LINT		= splint
LINTLEVEL	= -weak
LCFLAGS 	= $(INCLUDES) $(CCDEFS)
LHFLAGS 	= $(LCFLAGS) -exportfcn -declundef -fcnuse -fielduse \
		  -exportheader -varuse -exporttype -exportconst \
		  -exportvar -typeuse -enummemuse -constuse

ifneq ($(USEBCC), N)

################################
# Definitions using ia16-unknown-elks-gcc compiler

AS      = ia16-elf-as
ASFLAGS = $(CPU_AS) $(ARCH_AS)
CC      = $(CROSS_CC)
CFLAGS  = $(CROSS_CFLAGS) $(CPU_CC) $(ARCH_CC) $(CFLBASE) -Wall -Os
LD      = ia16-elf-ld
LDFLAGS = $(CPU_LD) -s
AR      = ia16-elf-ar

INCLUDES += -I$(TOPDIR)/libc/include

else

################################
# Definitions using GCC host compiler

AS      = as
ASFLAGS =
CC      = gcc
CFLAGS  = -Wall $(CFLBASE)
LD      = ld
LDFLAGS =
AR      = ar

endif

#########################################################################
# general construction rules

.S.s: ;

.S.o:
	gcc -E -traditional $(INCLUDES) $(CCDEFS) -o $*.tmp $<
	$(AS) $(ASFLAGS) -o $*.o $*.tmp
	rm $*.tmp

.s.o:
	$(AS) $(ASFLAGS) -o $*.o $<

ifneq ($(USEBCC), N)
.c.o:
	$(CC) $(CFLAGS) -c -o $*.o $<
endif

#########################################################################
# Default target, to allow standard targets to be included. This simply
# allows `make elks` to be called from any directory in the tree, and
# results in `make all` being called in the root directory of the tree.

elks:
	${MAKE} -C $(BASEDIR) all

#########################################################################
# Standard commands.

doclean: $(CLEANDEP)
	rm -fv *~ *.a *.bak *.lint *.map *.o *.tmp core $(CLEANME)
#	@for FILE in *.s ; do \
#		BASE=`basename "$$FILE" .s` ; \
#		if [ -f "$$BASE.c" -o -f "$$BASE.S" ]; then \
#			echo rm -fv "$$FILE" ; \
#			rm -fv "$$FILE" ; \
#		fi ; \
#	done
	@for DIR in */ ; do \
		if [ -f "$$DIR/Makefile" ]; then \
			${MAKE} -C "$$DIR" doclean ; \
		fi ; \
	done

dodep:	$(DEPEND)
	@if \ls *.c > /dev/null 2>&1 ; then \
		${MAKE} mkdep ; \
	fi
	@for DIR in */ ; do \
		if [ -f "$$DIR/Makefile" ]; then \
			${MAKE} -C "$$DIR" dodep ; \
		fi ; \
	done

dofixme:
	@for FILE in $${USEME:-*.[ch]} ; do \
	    if [ -f "$${FILE}" ]; then \
		if fgrep -q FIXME "$${FILE}" ; then \
		    echo WARNING: "$${FILE}" includes a FIXME comment. ; \
		fi ; \
	    fi ; \
	done
	@if [ -z "$${USEME}" ]; then \
		for DIR in */ ; do \
			if [ -f "$$DIR/Makefile" ]; then \
				${MAKE} -C "$$DIR" dolint ; \
			fi ; \
		done ; \
	fi

doindent:
	$(BASEDIR)/scripts/reindent $(NOINDENT)

dolint:
	@for FILE in $${USEME:-*.[ch]} ; do \
	    if [ -f "$${FILE}" ]; then \
		    echo $(LINT) ... "$${FILE}" ; \
		    SLEEP=N ; \
		    if fgrep -q FIXME "$${FILE}" ; then \
			echo WARNING: "$${FILE}" includes a FIXME comment. ; \
			SLEEP=Y ; \
		    fi ; \
		    if fgrep -q '#asm' "$${FILE}" ; then \
			echo WARNING: "$${FILE}" includes assembler section. ; \
			SLEEP=Y ; \
		    fi ; \
		    if fgrep -q '#ifndef S_SPLINT_S' "$${FILE}" ; then \
			echo WARNING: "$${FILE}" includes disabled section. ; \
			SLEEP=Y ; \
		    fi ; \
		    if fgrep -q '/*@ignore@*/' "$${FILE}" ; then \
			echo WARNING: "$${FILE}" includes section ignored by splint ; \
			SLEEP=Y ; \
		    fi ; \
		    if [ $SLEEP != N ]; then \
			sleep 1 ; \
		    fi ; \
		    if echo "$${FILE}" | grep -q '\.h$$' ; then \
			$(LINT) $(LINTLEVEL) $(LHFLAGS) "$${FILE}" \
				> "$${FILE}.lint" 2>&1 ; \
		    else \
			$(LINT) $(LINTLEVEL) $(LCFLAGS) "$${FILE}" \
				> "$${FILE}.lint" 2>&1 ; \
		    fi ; \
		    if [ $$? -eq 0 ]; then \
			rm -f "$${FILE}.lint" ; \
		    else \
			cat "$${FILE}.lint" ; \
		    fi ; \
	    fi ; \
	done
	@if [ -z "$${USEME}" ]; then \
		for DIR in */ ; do \
			if [ -f "$$DIR/Makefile" ]; then \
				${MAKE} -C "$$DIR" dolint ; \
			fi ; \
		done ; \
	fi

fixme:	dofixme
	@echo
	@echo Those are all the FIXME comments in this tree.
	@echo

indent:	doindent
	@for DIR in */ ; do \
		if [ -f "$$DIR/Makefile" ]; then \
			${MAKE} -C "$$DIR" indent ; \
		fi ; \
	done

lint:	dolint
	@echo
	@echo " * All files in and under this directory have now been checked. Where problems"
	@echo " * were found, they will be found in the relevant *.lint file in the same"
	@echo " * directory. However, where no problems were found, this file is deleted."
	@echo

mkdep:
	@sed '/\#\#\# Dependencies:/q' < Makefile > make.tmp
	@echo >> make.tmp
	@for FILE in *.c ; do \
		$(CC_PROTO) "$${FILE}" >> make.tmp ; \
		printf '\n\n' >> make.tmp ; \
	done
	@if ! diff Makefile make.tmp > /dev/null ; then \
		echo -n 'Assigning dependencies: ' ; \
		mv -fv make.tmp Makefile ; \
	else \
		rm -f make.tmp ; \
	fi

nodep:
	sed '/\#\#\# Dependencies:/q' < Makefile > make.tmp
	@if ! diff Makefile make.tmp > /dev/null ; then \
		echo -n 'Removing dependencies: ' ; \
		mv -fv make.tmp Makefile ; \
	else \
		rm -f make.tmp ; \
	fi
	@for DIR in */ ; do \
		if [ -f "$$DIR/Makefile" ]; then \
			${MAKE} -C "$$DIR" nodep ; \
		fi ; \
	done

#########################################################################
# Sub-command used by the `make dist` command in the toplevel Makefile.

MKDIST	= $(shell export allow_null_glob_expansion=Y ; \
	  echo *.? *.cc *.html *.in *.png *.sh *.tk *.txt Makefile* README*)

mkdist:
	mkdir -m 755 -p $(DISTDIR)
	cp -pf $(MKDIST) $(DISTFILES) $(DISTDIR)
	@for DIR in */ ; do \
		if [ -f "$${DIR}/Makefile" ]; then \
			${MAKE} -C "$${DIR}" mkdist ; \
		fi ; \
	done

#########################################################################
# End of standard rules file.
