# @(#) makefile 1.110@(#) 96/05/06 #
# Makefile for ExFilter

#                                                                   #
# Copyright (c) 1993--1996 ExNet Systems Ltd.                       #
#                                                                   #
# THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF EXNET SYSTEMS LTD. #
# The copyright notice above does not evidence any                  #
# actual or intended publication of such source code.               #


SHELL=/bin/sh

.KEEP_STATE:

#--------------------------------------------------------------------------
# V gives the code version we are producing.  This is built into the code!
V=1.1.4-dev

#--------------------------------------------------------------------------
# Compute architecture types we can generate.

# ARCH is the applications architecture.
# KARCH is the kernel architecture.
# OSTYPE is the OS name, eg SunOS.
# OSMREV is the major revision level of the OS, eg 4 for SunOS 4.1.x,
#     5 for SunOS 5.x.
ARCH:sh=/bin/arch
KARCH:sh=/bin/arch -k
OSTYPE:sh=/bin/uname -s
OSMREV:sh=case `/bin/uname -s` in \
    SunOS) \
        case `/bin/uname -r` in 4.1*) echo 4;; 5*) echo 5;; *) exit 1;; esac;;\
    *) \
        exit 1;; \
    esac

# APPSARCH is the fully-qualified architechture (FQA) for non-kernel parts.
# KAPPSARCH is the FQA for kernel-dependent parts.
APPSARCH=$(ARCH)-$(OSTYPE)-$(OSMREV)
KAPPSARCH=$(ARCH)-$(KARCH)-$(OSTYPE)-$(OSMREV)

# GCC is location of gcc driver.
GCC=/usr/local/bin/gcc/bin/gcc

#--------------------------------------------------------------------------
# Compute target names and set default (`all') target.

# TARGET is the name of the executable.
# TARGETO is the name of the optimised executable.
# TARGETG is the name of the optimised gcc-compiled executable.
# TARGETc is the name of the crippled (demo) executable.
# TARGETL is the name of the lint output.
TARGET=ExFilter.N.$(APPSARCH)
TARGETO=ExFilter.O.$(APPSARCH)
TARGETG=ExFilter.G.$(APPSARCH)
TARGETc=ExFilter.c.$(APPSARCH)
TARGETL=ExFilter.L.$(APPSARCH)

# KTARGET is the name of the loadable-STREAMS-module.
# KTARGETO is the optimised version of KTARGET.
# KTARGETG is the optimised gcc-compiled version of KTARGET.
# (There is no kernel module for the crippled version.)
# KTARGETL is the lint output.
KTARGET=ExSTREAM.N.$(KAPPSARCH).o
KTARGETO=ExSTREAM.O.$(KAPPSARCH).o
KTARGETG=ExSTREAM.G.$(KAPPSARCH).o
KTARGETL=ExSTREAM.L.$(KAPPSARCH)

# DOC is the documentation target.
DOC=spec.dvi

# NCODETARGETS is all the non-optimised (ie quick-to-make) code targets,
# ie does not make any docs or lint output or any stuff like that, and
# is the quickest way to make the next code for testing.
#
# ALLTARGETS is all the normal targets, executables and streams modules,
# optimised and unoptimised, plus lint output.
#
# The order of targets is most-often-wanted first (during development).
NCODETARGETS= \
     $(TARGET)  $(KTARGET)

ALLTARGETS= \
     $(TARGET)  $(KTARGET) \
     $(TARGETO) $(KTARGETO) \
     $(TARGETG) $(KTARGETG) \
     $(TARGETL) $(KTARGETL) \
     $(TARGETc) \
	 $(DOC)

NGLTARGETS= \
     $(TARGET)  $(KTARGET) \
     $(TARGETG) $(KTARGETG) \
     $(TARGETL) $(KTARGETL)

NOLTARGETS= \
     $(TARGET)  $(KTARGET) \
     $(TARGETO) $(KTARGETO) \
     $(TARGETL) $(KTARGETL)

all: $(ALLTARGETS)
	@(echo Made:; echo '    '`echo $(ALLTARGETS)`.) | fmt -c

NGL: $(NGLTARGETS)
	@(echo Made:; echo '    '`echo $(NGLTARGETS)`.) | fmt -c

NOL: $(NOLTARGETS)
	@(echo Made:; echo '    '`echo $(NOLTARGETS)`.) | fmt -c

quick: $(NCODETARGETS)
	@(echo Made:; echo '    '`echo $(NCODETARGETS)`.) | fmt -c

quickcp: $(NCODETARGETS) quick
	cp $(NCODETARGETS) /tmp/
	chmod a+r $(NCODETARGETS)

#--------------------------------------------------------------------------
# Cleaning up, making distributions, etc.

clean: FORCE
	rm -f obj/*.o $(ALLTARGETS)

FORCE:

#--------------------------------------------------------------------------
# Making documentation...

# SOURCE is all the source files listed in Sman/sourcefiles.
SOURCE:sh = egrep -v '^(\#|\\)' Sman/sourcefiles | awk '{print "Sman/"$0;}'
# Other `built-in' source files.
SOURCEALSO = Sman/root.tex Sman/title.tex

spec.dvi: Sman/sourcefiles Sman/makefile Sman/onedvi $(SOURCE) $(SOURCEALSO)
	@rm -f $@
	cd Sman; $(MAKE)
	cd Sman; ./onedvi
	ln -s Sman/spec.dvi $@

#--------------------------------------------------------------------------
# List source files, headers and standard suffixes.

# CSRC is a list of the C source files.
# The most-used routines should be in files towards the start of the
# list so that pages from the end of the code area can be dropped more
# easily.  Those routines should be towards the start of their files.
CSRC=route.c stats.c muxmsgU.c muxmsgC.c rtconfig.c ifconfig.c hci.c \
	main.c version.c

# KSRC is a list of C source files that go into the STREAMS module.
KCSRC=route.c stats.c muxmsgK.c muxmsgC.c rtconfig.c \
	strmload.c version.c

# CHDR is a list of the C header files.
CHDR= conffile.h filter.h muxmsg.h queue.h route.h stats.h verbosity.h

# OD is the base directory for all the (intermediate) object files.
OD=obj

# OBJE is the ending for unoptimised object files.
# OBJOE is the ending for maximally-optimised object files.
# OBJGE is the ending for maximally-optimised gcc object files.
# Both of these are for non-kernel-dependent modules only.
OBJE=.N.$(APPSARCH).o
OBJOE=.O.$(APPSARCH).o
OBJGE=.G.$(APPSARCH).o

# OBJS is a list of executables for the current target.
# OBJSO is a list of executables for the current optimised target.
# OBJSO is a list of executables for the current optimised gcc target.
OBJS=$(CSRC:%.c=$(OD)/%$(OBJE))
OBJSO=$(CSRC:%.c=$(OD)/%$(OBJOE))
OBJSG=$(CSRC:%.c=$(OD)/%$(OBJGE))

# KOBJE is the ending for kernel-dependent unoptimised object files.
# KOBJOE is the ending for kernel-dependent maximally-optimised object files.
# KOBJGE is the ending for kernel-dependent maximally-optimised gcc obj files.
KOBJE=.K.N.$(KAPPSARCH).o
KOBJOE=.K.O.$(KAPPSARCH).o
KOBJGE=.K.G.$(KAPPSARCH).o

# KOBJS is a list of executables for the current kernel target.
# KOBJSO is a list of executables for the current optimised kernel target.
# KOBJSG is a list of executables for the current optimised kernel gcc target.
KOBJS=$(KCSRC:%.c=$(OD)/%$(KOBJE))
KOBJSO=$(KCSRC:%.c=$(OD)/%$(KOBJOE))
KOBJSG=$(KCSRC:%.c=$(OD)/%$(KOBJGE))

#--------------------------------------------------------------------------
# Force some explicit dependencies.

# List some of the common headers the objects depend on.
$(OBJS) $(OBJSO) $(OBJSG) \
	$(KOBJS) $(KOBJSO) $(KOBJSG): filter.h verbosity.h

# Force ``version'' to depend on all headers since it includes the SCCS IDs
# of the headers for version identification.
version$(OBJE) version$(OBJOE) version$(OBJGE) \
	version$(KOBJE) version$(KOBJOE) version$(KOBJGE): $(CHDR)

#--------------------------------------------------------------------------
# CFLAGS is the common set of flags passed to non-optimised, optimised
# and linted code.  This flags are used for all .c compilations.
# CoreFlags is an architecture-independent subset, useful for, for example,
# building the `strings' database.
CoreFlags='-DVersion="$V"' -DNO_MPX
CFLAGS=-D$(ARCH) $(CoreFlags)

# KCFLAGS is the extra set of flags passed to the STREAMS modules during
# compilation.
KCFLAGS=-DKERNEL -DSTREAMS # -I/usr/sys

#--------------------------------------------------------------------------
# Generating non-optimised versions, TARGET and KTARGET.

# DEBUG_FLAGS should be supplied as ``make DEBUG_FLAGS=XXX target'' if
# required.  Note that DEBUG_FLAGS cannot be applied to the kernel
# sources as run-time profiling would use a different mechanism.

# We use the -g flag, which should give better tracability in case
# of core dump or kernel panic.  (Actually, the -go flag is used on
# the kernel side.)

$(OD)/%$(OBJE): %.c
	cc -c $(CFLAGS) -g $(DEBUG_FLAGS) -o $@ $(@:$(OD)/%$(OBJE)=%.c)

$(OD)/%$(KOBJE): %.c
	cc -c $(CFLAGS) -go $(KCFLAGS) -o $@ $(@:$(OD)/%$(KOBJE)=%.c)

$(TARGET): $(CHDR) $(OBJS)
	cc $(CFLAGS) -g $(DEBUG_FLAGS) -o $@ $(OBJS)

$(KTARGET): $(CHDR) $(KOBJS)
	ld -r -o $@ $(KOBJS)

# Generate gprof output from running $(TARGET) with DEBUG_FLAGS=-pg.
#gmon.out: $(TARGET)
#	$(TARGET) -f ExFilter.conf

$(TARGET).gprof: gmon.out
	@rm -f $@
	gprof $(TARGET) gmon.out > $@

#--------------------------------------------------------------------------
# Generating lint commentary, based on non-optimised version.
# Don't give different conditional-compilation flags to the optimised
# version that might let lint miss something.

$(TARGETL): $(CSRC)
	lint -abx $(CFLAGS) $(CSRC) 2>&1 | tee $@

$(KTARGETL): $(KCSRC)
	lint -uabx $(KCFLAGS) $(KCSRC) 2>&1 | tee $@

#--------------------------------------------------------------------------
# Generating optimised versions, TARGETO and TARGETG.

# COFLAGS is the set of C flags for the optimised version
# (all of normal flags + optimisation that won't change anything that
# lint cares about, ie no conditional-compilation changes EXCEPT
# the elimination of extra*internal* consistency checking with
# -DNO_PARANOIA).
COFLAGS = $(CFLAGS) -DNO_PARANOIA -O2

# CGFLAGS is the set of C flags passed to the optimised gcc version
# instead of COFLAGS.  Just like COFLAGS, none of the switches in
# here should change any conditional compilation items in the source
# so semantically the executables are exactly the same as non-optimised
# and native-optimised ones. -DNO_PARANOIA is allowed.
#
# The first line choses which warnings to enable, and the general environment.
# The second line sets the optimisation options we use.
# The third line sets options to ensure we can safely link with /bin/cc code
# and the SunOS 4.1.x and 5.x kernels.
CGFLAGS = $(CFLAGS) -DNO_PARANOIA \
	-Wall -Wno-comment -ansi -fverbose-asm \
	-O2 -fomit-frame-pointer -funroll-loops -finline-functions \
	-fpcc-struct-return -fvolatile-global

# strings is the extracted-strings database and depends on all the source
# (non-kernel) C files.
#
# Note that the STREAMS module is *not* optimised using the strings
# database.
#
# We move the existing database out of the way while we build a new
# one from scratch.  If the new and the old differ we keep the new
# (possibly optimal) one, else we restore the old one, keeping its
# datestamp.
#
# We make the strings database after preprocessing with the native
# C compiler---gcc compilation should not generate extra strings.

# The strings database is too valuable to loose!
.PRECIOUS: strings

strings: $(CHDR) $(CSRC)
	@if [ -f strings ]; then mv -f strings strings.old; fi
	cc -E $(CoreFlags) $(CSRC) | xstr -c -
	@if cmp -s strings strings.old; then \
		echo Preserving old strings database. ; \
		mv -f strings.old strings; \
	 else \
		echo Discarding old strings database. ; \
	 fi

## for i in $(CSRC); do cc -E $(COFLAGS) $$i | xstr -c -; done

# xs.$(ARCH).o is made from strings separately to allow it to be built after
# we've tried building all the real .o files that we care about.
#
# Make the data read-only and shared (and in the text segment).
#
# This alone doesn't need CFLAGS.
$(OD)/xs.$(ARCH).o: strings
	xstr
	cc -c -R xs.c -o $(OD)/xs.$(ARCH).o
	@rm -f xs.c

# Report any new strings added at compile time, presumably from
# conditionally-compiled code and/or from headers.
$(OD)/%$(OBJOE): strings %.c
	@echo Optimising cc compile $(@:$(OD)/%$(OBJOE)=%.c) to $@.
	@cc -E $(COFLAGS) $(DEBUG_FLAGS) $(@:$(OD)/%$(OBJOE)=%.c) | \
		xstr -v -c - && \
		cc -c $(COFLAGS) $(DEBUG_FLAGS) -o $@ x.c
	@rm -f x.c

# GCC code.
# We share our strings database with the non-gcc code.
# Report any new strings added at compile time, presumably from
# conditionally-compiled code and/or from headers.
$(OD)/%$(OBJGE): strings %.c
	@echo Optimising gcc compile $(@:$(OD)/%$(OBJGE)=%.c) to $@.
	@$(GCC) -E $(CGFLAGS) $(DEBUG_FLAGS) $(@:$(OD)/%$(OBJGE)=%.c) | \
		xstr -v -c - && \
		$(GCC) -c $(CGFLAGS) $(DEBUG_FLAGS) -o $@ x.c
	@rm -f x.c

$(OD)/%$(KOBJOE): %.c
	cc -c $(COFLAGS) $(KCFLAGS) -o $@ $(@:$(OD)/%$(KOBJOE)=%.c)

$(OD)/%$(KOBJGE): %.c
	$(GCC) -c $(CGFLAGS) $(KCFLAGS) -o $@ $(@:$(OD)/%$(KOBJGE)=%.c)

# xs.$(ARCH).o is the shared strings library and is last to get all the other
# .o files compiled first.
$(TARGETO): $(CHDR) $(OBJSO) $(OD)/xs.$(ARCH).o
	cc $(COFLAGS) $(DEBUG_FLAGS) -o $@ $(OD)/xs.$(ARCH).o $(OBJSO)
	strip $@

# GCC optimised target.
# xs.$(ARCH).o is the shared strings library and is last to get all the other
# .o files compiled first.
$(TARGETG): $(CHDR) $(OBJSG) $(OD)/xs.$(ARCH).o
	$(GCC) $(CGFLAGS) $(DEBUG_FLAGS) -o $@ $(OD)/xs.$(ARCH).o $(OBJSG)
	strip $@

$(KTARGETO): $(CHDR) $(KOBJSO)
	ld -r -o $@ $(KOBJSO)

$(KTARGETG): $(CHDR) $(KOBJSG)
	ld -r -o $@ $(KOBJSG)

#--------------------------------------------------------------------------
# Generating crippled (demo) version TARGETc.

# CcFLAGS is the set of flags passed to the crippled version (built
# with /bin/cc) that can go out as a free demo.
# With it we severely restrict the number of routes and interfaces
# supported and define the DEMO preprocessor variable.  Note that
# we also pick inefficient values for some variables.  There is also
# no streams-module support in this version.  We also shrilly announce
# that this is a demo version.  We also disable HUP processing, so that
# reconfiguration requires the daemon be killed and restarted.
#
# All this should shame/force the user into getting the real thing.
#
# We remove extra internal checking, optimise the code, strip the executable,
# and put the modules together in a different (less efficient!) order;
# all to try to minimise the chance of reverse engineering.
CcFLAGS = $(CFLAGS) -O2 -DNO_PARANOIA \
	-DRT_MAXRT=13 -DMAX_IFS=2 -DDEMO '-DOfficialName="ExFilter-demo"' \
	-DNO_MUX -DNO_DOHUP

# Crippled target.  Note that it should be stripped.  It does not use xstr.
# All the .c files are compiled directly to make the executable.
# Note that we force the .h files to be brought out of the archive.
$(TARGETc): $(CHDR) $(CSRC)
	cc $(CcFLAGS) -o $@ `for f in $(CSRC); do echo $$f; done | sort -r`
	strip $@
