##
## Makefile for CCCC - a C and C++ Code Counter
##
## derived from an original makefile generated by the pccts genmk utility
##

## see lower on this page for a description of what the CONF variable does
## for the moment we are just looking to see if we can set it to an
## appropriate value

ifeq "$(CONF)" ""
CONF=djgpp
endif

ifeq "$(OSTYPE)" "Linux"
CONF=linux
endif

ifeq "$(OSTYPE)" "OSF"
CONF=osf
endif

ifeq "$(OSTYPE)" "SOLARIS"
CONF=solaris
endif

## the sections below configure the make for the various machines
## which I do builds on
##
## each stanza is gated on a value of the variable CONF
## note that the sections mix freely differences due to the nature of
## the operating system and differences due to the configuration of the
## particular machine in use
## 
## the first stanza (which is selected if the CONF variable is empty)
## contains a template of all of the definitions which will be required

ifeq "$(CONF)" ""

## where to find components of PCCTS
PCCTS =          ## the root directory where PCCTS is installed
PCCTS_H =        ## the directory where PCCTS support code is
PCCTS_BIN =      ## the directory where the antlr and dlg binaries are

## compiler to use and associated flags 
CCC =            ## C++ compiler
LD =             ## linker
CFLAGS =         ## compiler flags
LDFLAGS =        ## linker flags
CPPEXT =         ## the extension on C++ files generate by PCCTS

COPY =           ## the operating system command for copying a file
CCCC_BIN =       ## the name of the cccc binary
INSTALL_BINDIR = ## the location where the binary is to be installed
INSTALL_LIBDIR = ## the location where the .dat files are to be installed
endif

ifeq "$(CONF)" "linux"

## when I packaged PCCTS for Linux, I made it install into /usr/bin and 
## /usr/lib, but now I prefer to run it from under the directory where I
## installed the source distribution
## the binaries are not on my path, but why would I want to run them 
## from the command line anyway
PCCTS =         /usr/local/src/pccts
PCCTS_H =       $(PCCTS)/h
PCCTS_BIN =     $(PCCTS)/bin

## using the GNU C++ compiler
## we need working templates - I use version 2.7.2, I am not sure whether
## versions earlier than 2.7 are OK
CCC=g++
LD=g++ 
CFLAGS =        -g -I/usr/include/g++-include -I. -I$(PCCTS_H) 
LDFLAGS =       -g -static
CPPEXT=cpp

COPY =           cp
CCCC_BIN =       cccc
INSTALL_BINDIR = /usr/local/bin
INSTALL_LIBDIR = /usr/local/lib/cccc

endif

ifeq "$(CONF)" "djgpp"

PCCTS =         e:/pccts
PCCTS_H =       $(PCCTS)/h
PCCTS_BIN =     $(PCCTS)/bin

## using the DJGPP port of GNU C++ to the DPMI 32 bit DOS environment
## NB binaries generated using this compiler WILL NOT WORK unless
## a suitable DPMI server is present - WfW 3.11, WinNT, Win95 and OS/2
## should all provide the right facilities in their respective DOS boxes,
## while recent versions of Linux/DosEmu may be OK (but why wouldn't you
## use the Linux version)
## NB Linux seems to give excellent protection to prevent runaway processes
## compromising the stability of the system - the same cannot be said
## of Windows (WfW 3.11 at least), where bugs in CCCC.EXE have been known
## to crash program manager or cause reboots of the whole machine
## ****SO PLEASE SAVE YOUR WORK IN ALL APPLICATIONS BEFORE RUNNING CCCC.EXE****
## ****SO PLEASE SAVE YOUR WORK IN ALL APPLICATIONS BEFORE RUNNING CCCC.EXE****
## ****SO PLEASE SAVE YOUR WORK IN ALL APPLICATIONS BEFORE RUNNING CCCC.EXE****
## ****SO PLEASE SAVE YOUR WORK IN ALL APPLICATIONS BEFORE RUNNING CCCC.EXE****
## ****SO PLEASE SAVE YOUR WORK IN ALL APPLICATIONS BEFORE RUNNING CCCC.EXE****
## consider yourself warned!!!
## NB As of version 2.1.0, I have not experienced the problems above for about
## three months, however, the system I am now running on is NT4.0
CCC=gcc
LD=gxx
CFLAGS =        -DPC -I$(PCCTS_H) 
LDFLAGS =       -static
CPPEXT=cpp

COPY =           copy
CCCC_BIN =       cccc.exe
INSTALL_BINDIR = c:\cccc
INSTALL_LIBDIR = c:\cccc

endif

ifeq "$(CONF)" "osf"

PCCTS =         /iocs/pccts
PCCTS_H =       $(PCCTS)
PCCTS_BIN =     /usr/local/bin

CCC=cxx -x cxx -define_templates
LD=cxx
CFLAGS =        -g -I. -I$(PCCTS_H) -DOSF_TEMPLATES -DEXPAND_TEMPLATES -nocleanup
LDFLAGS =       -g 

## the version of PCCTS on this machine is configured to generate C++ 
## implementation files with the extension cxx
CPPEXT=cxx

COPY =           cp
CCCC_BIN =       cccc
INSTALL_BINDIR = /usr/local/bin
INSTALL_LIBDIR = /usr/local/lib/cccc


endif

ifeq "$(CONF)" "solaris"

## MANY THANKS TO HERMAN H"UNI for the patch to add a Solaris configuration
## into the makefile
 
## PCCTS for SOLARIS installs into /usr/local/cccc/{bin,lib} 
## the binaries are not on my path, but why would I want to run them 
## from the command line anyway
PCCTS =         /opt/local/pccts
PCCTS_H =       $(PCCTS)/h
PCCTS_BIN =     $(PCCTS)/bin

## using the GNU C++ compiler
## we need working templates - I use version 2.7.2, I am not sure whether
## versions earlier than 2.7 are OK
CCC=g++
LD=g++ 
#CFLAGS =       -g -I/usr/include/g++-include -I. -I$(PCCTS_H) 
CFLAGS =        -O2 -I. -I$(PCCTS_H) 
LDFLAGS =       -O2 -static
CPPEXT=cpp

COPY =           cp
CCCC_BIN =       cccc
INSTALL_BINDIR = $(PCCTS_BIN)
INSTALL_LIBDIR = $(PCCTS)/lib

endif


## locations and flags for antlr and dlg (don't change the flags unless you 
## understand PCCTS)
ANTLR =         $(PCCTS_BIN)/antlr
DLG =           $(PCCTS_BIN)/dlg
AFLAGS =        -CC -k 2 -gd -ge -gt -gh -rl 5000 -w1 
DFLAGS =        -C2 -i -CC 


## list of files generated by the PCCTS utilities
CCCC_SPAWN =    cccc.$(CPPEXT) CParser.$(CPPEXT) CParser.h \
		Ctokens.h CLexer.$(CPPEXT) CLexer.h
JAVA_SPAWN =    java.$(CPPEXT) JParser.$(CPPEXT) JParser.h \
		Jtokens.h JLexer.$(CPPEXT) JLexer.h
ADA_SPAWN =     ada.$(CPPEXT) AdaPrser.$(CPPEXT) AdaPrser.h \
		Atokens.h ALexer.$(CPPEXT) ALexer.h

## the source files of the project itself
USR_G =         cccc.g java.g ada.g

USR_C =         ccccmain.cc cccc_ast.cc cccc_tok.cc cccc_met.cc cccc_utl.cc \
		cccc_db.cc cccc_stg.cc cccc_htm.cc cccc_tbl.cc \
		cccc_new.cc 

USR_H =         cccc.h cccc_ast.h cccc_tok.h cccc_met.h cccc_utl.h \
			cccc_db.h cccc_stg.h cccc_htm.h cccc_tbl.h

## configuration/runtime data files, manuals
USR_DAT =       cccc_tmt.dat cccc_inf.dat cccc_met.dat cccc_ug.htm

## documentation 
USR_TXT =       readme.txt

## all source files
USR_SOURCE =    makefile $(USR_G) $(USR_H) $(USR_C) $(USR_DAT) $(USR_TXT)

## the final executable is linked from 3 groups of object files:

# object files compiled from PCCTS support code which does not change
ifneq "$(CONF)" "djgpp"
PCCTS_OBJ =     AParser.o DLexerBase.o ASTBase.o PCCTSAST.o ATokenBuffer.o 
else
# DOS 8.3 file names truncate some of these
PCCTS_OBJ =     AParser.o DLexerBa.o ASTBase.o PCCTSAST.o ATokenBu.o 
endif

# object files compiled from C++ files generated by anltr and dlg
SPAWN_OBJ =     \
	cccc.o CLexer.o CParser.o \
	java.o JLexer.o JParser.o \
	ada.o ALexer.o AdaPrser.o


# object files compiled from .cc files which are part of the cccc source
USR_OBJ =       ccccmain.o cccc_utl.o cccc_stg.o cccc_db.o cccc_met.o \
		cccc_htm.o cccc_ast.o cccc_tok.o cccc_tbl.o cccc_new.o

ALL_OBJ = $(SPAWN_OBJ) $(USR_OBJ) $(PCCTS_OBJ) 

VPATH = $(PCCTS_H)


all: $(USR_G) $(ANLTR_SPAWN) $(DLG_SPAWN) $(USR_H) $(USR_C) $(ALL_OBJ) cccc


cccc : $(ALL_OBJ)
	$(LD) -o cccc $(LDFLAGS) $(ALL_OBJ) $(LD_EXTRA_LIBS)

.SUFFIXES: .cc .o .cpp .cxx .g .g_info

## ANTLR can give us some very useful documentation including a 
## cross reference of the rules and a list of first token sets
## for each rule

.g.g_info:
	$(ANTLR) $(AFLAGS) -gc -gx -pa $< > $*.1st
	$(ANTLR) $(AFLAGS) -gc -gx -cr $< > $*.xrf

## a special rule to make the version number appear
ifneq "$(VERSION)" ""
ccccmain.o : ccccmain.cc 
	$(CCC) -c $(CFLAGS) -DVERSION=\"$(VERSION)\" -o ccccmain.o ccccmain.cc
endif


.cc.o:
	$(CCC) -c $(CFLAGS) -o $*.o $<

.cpp.o:
	$(CCC) -c $(CFLAGS) -o $*.o $<

.cxx.o:
	$(CCC) -c $(CFLAGS) -o $*.o $<


ifneq "$(PCCTS_BIN)" ""
## the rule for running the PCCTS tools to regenerate the C++ files
## which implement the parser and lexical analyser
## notice that this rule can be supressed by not defining the symbol 
## $(PCCTS_BIN) which tells make where to find the binaries of the PCCTS tools
## this means that you can build cccc even if you haven't been able to 
## build PCCTS, although you do need the support files in $(PCCTS_H)
$(CCCC_SPAWN) : cccc.g
	$(ANTLR) $(AFLAGS) -ft Ctokens.h cccc.g
	$(DLG) $(DFLAGS) -cl CLexer parser.dlg

$(JAVA_SPAWN) : java.g
	$(ANTLR) $(AFLAGS) -ft Jtokens.h java.g
	$(DLG) $(DFLAGS) -cl JLexer parser.dlg

## -ci argument to DLG is because unlike C/C++/Java, Ada is defined as being
## case insensitive
## NB CCCC does not map case: if the code processed is not consistent in
## capitalisation of the name of a package, the reports will treat it as 
## two different packages
$(ADA_SPAWN) : ada.g
	$(ANTLR) $(AFLAGS) -ft Atokens.h ada.g
	$(DLG) $(DFLAGS) -ci -cl ALexer parser.dlg

endif

# touch enables us to mark everything up to date to avoid enormous 
# recompilations (particularly after checking everything in and out of RCS)

touch:
	touch cccc.g
	touch *.cpp
	touch *.cxx
	touch *.cc
	touch *.h
	touch *.o
	touch cccc

clean:
	rm -f *~ *.o core

ci:
	-ci $(CI_FLAGS) $(USR_SOURCE)

co:
	co -l $(USR_SOURCE)

cico: ci co


TODAY:=$(shell date +%y%m%d)

## part of my backup target copies all useful files to a new directory on
## my MS/DOS C: drive so that I can attempt a build with DJGPP

backup: copy_to_dos
	-tar czvf sr$(TODAY).tgz  *.g *.cc *.h makefile *.htm *.dat *.txt 
	-tar czvf rc$(TODAY).tgz  RCS/*,v 
	cp *$(TODAY).tgz /mnt/floppy

DOSDIR:=/mnt/dosc/cccc/$(TODAY)
copy_to_dos:
	-mkdir $(DOSDIR) 
	-cp $(USR_SOURCE) $(DOSDIR)


## installation target
install :
	-mkdir $(INSTALL_LIBDIR)
	$(COPY) $(USR_DAT) $(INSTALL_LIBDIR)
	-mkdir $(INSTALL_BINDIR)
	$(COPY) $(CCCC_BIN) $(INSTALL_BINDIR)
	strip $(INSTALL_BINDIR)/$(CCCC_BIN)


## distribution archives
SRCDIR=cccc-$(VERSION)
SRCTARFILE=$(SRCDIR)-src.tar
BINTARFILE=$(SRCDIR)-$(CONF).tar
ZIPFILE=$(SRCDIR).zip

tar_distribution: 
	@test "$(TAG)" != "" || (echo "No tag" && exit 3)
	@test "$(VERSION)" != "" || (echo "No version" && exit 4)
	@rcsdiff -q --brief RCS/*,v || (echo "RCS files differ" && exit 5)
	rcs -N$(TAG): RCS/*,v
	touch ccccmain.cc
	make ccccmain.o 
	make cccc
	su root make install
	-rm -rf ./usr
	mkdir ./usr
	mkdir ./usr/local
	mkdir ./usr/local/src
	mkdir ./usr/local/src/$(SRCDIR)
	cp $(USR_SOURCE) ./usr/local/src/$(SRCDIR)
	tar chvf $(SRCTARFILE) ./usr/local/src/$(SRCDIR) 
	cp $(SRCTARFILE) $(BINTARFILE)
	tar rhvf $(BINTARFILE) -C/ $(INSTALL_BINDIR)/cccc $(INSTALL_LIBDIR)
	gzip $(SRCTARFILE) $(BINTARFILE)

zip_distribution :
	zip -k $(ZIPFILE) $(USR_SOURCE) cccc.exe

examples :
	rm -rf examples
	mkdir examples
	make c++-examples ada-example java-example

c++-examples :
	./cccc -l. cccc*.h cccc*.cc -o examples/cccc-c++-cccc.htm
	./cccc -l. RCS/examples/c++/* -o examples/cccc-c++-iostream.htm

ada-example :
	./cccc -l. RCS/examples/ada/a-*io.ad? -o examples/cccc-ada-textio.htm

java-example :
	./cccc -l. RCS/examples/java/*.java -o examples/cccc-java-io.htm

  
## libcccc.a is not used in building the final binary, but it helps when
## making test rigs
library:
	@make -k $(USR_O)
	ar r libcccc.a cccc*.o
	ar d libcccc.a ccccmain.o

## this cross-reference report is useful for finding unreferenced rules
xref: 
	antlr -CC -gt -cr -o /tmp cccc.g > cccc.xref
	grep "{ }" cccc.xref


## the linking rules include the undefined variable $(LD_EXTRA_LIBS)
## this allows us to include any arbitrary extra libraries in the link
## overriding the default implementations of library functions
## one area where this is useful is in linking with special debugging
## versions of the malloc library

## Electric Fence by Bruce Perens, 
## available from ftp:://sunsite.unc.edu/pub/Linux/devel/lang/c/
cccc.ef : cccc
	-mv -f cccc cccc.old
	make LD_EXTRA_LIBS=-lefence
	-mv -f cccc cccc.ef
	-mv cccc.old cccc

## Dmalloc by Gray Watson, available from ftp://ftp.letters.com/src/dmalloc
cccc.dm :
	-mv -f cccc cccc.old
	make LD_EXTRA_LIBS=-ldmalloc
	-mv -f cccc cccc.dm
	-mv cccc.old cccc

## GNU malloc
## (I don't think this is any different from the malloc in Linux libc.a)
cccc.gm :
	-mv -f cccc cccc.old
	make LD_EXTRA_LIBS=/usr/local/lib/libmalloc.a
	-mv -f cccc cccc.gm
	-mv cccc.old cccc















