# 
# $Id: Makefile,v 1.15 2003/12/17 18:43:11 rgb Exp $
#
#========================================================================
# THIS IS A "GENERIC" MAKEFILE FOR MASTER/SLAVE PVM C PROGRAMS
#
# make          alone should build the application(s).
#
# make tar      makes $(TAR) from >>all<< the sources
# make tgz      makes $(TGZ) from >>all<< the sources
# make rpm      makes $(RPM). This is experimental!  See below.
# make cvs      does a cvs commit and creates the timestamp $(CVS)
# make sync     does a cvs commit and runs synccvs to list of
#               CVSROOT hosts
# make clean    deletes the application and all object files
# make install  strips and installs application and a man page
# make installweb installs a "standard distribution" set of files on
#               your personal website with rsync.
# make printout prints out all source and include files
# 
#========================================================================
# This is the name of the toplevel directory, the CVS repository
# and goes into e.g. the tarball names.
DIR = project_pvm
PVM_ARCH=LINUX

# This is revision information that MUST be set here.  It is minimally
# used to set variables in an accompanying spec file (see template in
# this directory) and/or in defines passed to the application so that
# it knows its own version information.
VERSION_MAJOR=1
VERSION_MINOR=0.0
RELEASE=1

#========================================================================
# Define all sources.  We ALWAYS have $(SOURCE) derived from $(PROGRAM)
# and $(INCLUDE) derived from $(PROGRAM) and will usually have parsecl.c
# and other modules.
#========================================================================
# This should be the name of the binary produced by this package.
PROGRAM1 = project_master
PROGRAM2 = project_slave

SOURCE1 = $(PROGRAM1:=.c)
SOURCE2 = $(PROGRAM2:=.c)

SOURCES1 = $(SOURCE1) \
  parsecl_master.c \
  project_master_work.c \
  # Add more/new sources to list above this line...
SOURCES2 = $(SOURCE2) \
  parsecl_slave.c \
  project_slave_work.c \
  # Add more/new sources to list above this line...

OBJECTS1 = $(SOURCES1:.c=.o)
OBJECTS2 = $(SOURCES2:.c=.o)

INCLUDE1 = $(PROGRAM1:=.h)
INCLUDE2 = $(PROGRAM2:=.h)

INCLUDES1 = $(INCLUDE1) \
  # Add more/new includes to list above this line.  This makefile
  # doesn't support horribly complex includes and dependencies.
INCLUDES2 = $(INCLUDE2) \
  # Add more/new includes to list above this line.  This makefile
  # doesn't support horribly complex includes and dependencies.


#========================================================================
# These defines are VERY USEFUL for versioning.  Don't mess with
# RELEASE -- it is used in rpm builds on remote sites to measure
# deviation from your major/minor release number, so for you it should
# always be 1 or unset.
#
# Note that by default the web install installs the current snapshot of
# the rpm's, with NO MAJOR/MINOR RELEASE NUMBERS.  You can easily alter 
# this and install the full major/minor labelled rpm (you do make it
# anyway) but you'll then have to work a bit harder to automagically
# present the rpm's in a sorted, timestamped table.
#========================================================================
DEFINES = -DVERSION_MAJOR=$(VERSION_MAJOR) -DVERSION_MINOR=$(VERSION_MINOR) \
          -DRELEASE=$(RELEASE) -DRSHCOMMAND=\"/usr/bin/ssh\"

#========================================================================
# Tree point to install (Choose one or set your own)
#========================================================================
# RPM's into /usr, please!  (Red Hat standard rule)
# PREFIX=/usr/share/pvm3
# Alternative for execution in home pvm3 directory
PREFIX=$(HOME)/pvm3

#========================================================================
# AMAZING!  INCREDIBLE!  BUILT IN "make rpm" SUPPORT!
# So much to break, but so much mindless work saved.  Oh, well.  Be
# patient and make it work; it is worth it.  For this to work one
# OBVIOUSLY needs write permission to RPM_TOPDIR and it needs to either
# be the default /usr/src/redhat or whatever is defined by the following
# macro in your ~/.rpmmacros (without the "#", obviously).  All the
# standard subdirectories [BUILD,SOURCES,SRPMS,RPMS,SPEC...etc] need to
# exist in RPM_TOPDIR as well.
#
# This defines your local architecture, also the place the RPM is left
# after a build in RPM_TOPDIR/RPMS.  Probably should set this from
# whereever rpm sets it.  Who knows why/when it builds for i386 (as opposed
# to e.g. i586 or i686) anyway?  Then there are alpha and noarch etc.
# Still...
ARCH=i386
#
# For a root build/install, use
# RPM_TOPDIR=/usr/src/redhat
#
# Otherwise, add the following:
# %_topdir	/home/rgb/Src/redhat
# to your personal $(HOME)/.rpmmacros after building
# yourself a private copy of the /usr/src/redhat directory structure.
# Change the "rgb" to your OWN home directory and "Src" to your source
# directory, of course.
RPM_TOPDIR=$(HOME)/Src/rpm_tree
#========================================================================

#========================================================================
# Define parameters and directives needed in compile/link steps.  We
# presume Gnu, optimized, ANSI C and the math link library.  -g -p is
# always set as we strip before installing below.  We always
# pass a definition of VERSION and RELEASE in the event that it is 
# needed in the program.  Adjust as needed.
#========================================================================
# C Compiler
CC = gcc
# Compile flags

CFLAGS = -O3 -ansi -g -I/usr/share/pvm3/include $(DEFINES)
# Or use the following for profiling as well as debugging.
# CFLAGS = -O3 -ansi -g -p $(DEFINES)
# Linker flags
LDFLAGS = -L/usr/share/pvm3/lib/$(PVM_ARCH)
# Libraries (I always include math library)
LIBS = -lpvm3 -lm

#========================================================================
# Define standard sources and targets.
#========================================================================
ABS = $(DIR).abs
PHP = $(DIR).php
TAR = $(DIR).tar
TGZ = $(DIR).tgz
RPM = $(DIR)-$(VERSION_MAJOR).$(VERSION_MINOR)-$(RELEASE).i386.rpm
SRPM = $(DIR)-$(VERSION_MAJOR).$(VERSION_MINOR)-$(RELEASE).src.rpm
WRPM = $(DIR).i386.rpm
WSRPM = $(DIR).src.rpm
SPEC = $(DIR:=.spec)
CVS = $(DIR:=.cvs.time)

#========================================================================
# List of variants one can make.  all is the default.  We always
# presume the simplest of dependencies and remake if includes change
# for example.
#========================================================================
all: $(PROGRAM1) $(PROGRAM2)

$(PROGRAM1): $(OBJECTS1) $(INCLUDES1)
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS1) $(LIBS) 

$(PROGRAM2): $(OBJECTS2) $(INCLUDES2)
	$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS2) $(LIBS) 

$(WRPM):	rpm
$(TGZ):		tgz

#========================================================================
# Build targets (from commands)
#========================================================================
tar:	$(SOURCES1) $(SOURCES2)
	rm -f core $(PROGRAM1) $(OBJECTS1) $(PROGRAM2) $(OBJECTS2) $(PROGRAM).1.gz
	tar -cvpf $(TAR) \
           --exclude=$(DIR)/$(TAR) \
           --exclude=$(DIR)/$(TGZ) \
           --exclude=$(DIR)/$(RPM) \
           --exclude=$(DIR)/CRUFT \
           -C .. $(DIR)

#========================================================================
# This is a complicated target, but VERY USEFUL.  It makes a .tgz tarball
# of the exact form preferred for an RPM.  Eventually I'll add a sed script
# that automatically fixes the accompanying rpm spec file to correspond
# right before building the tgz to really automate this, so that I can just
# move the spec to SPEC, move the source tgz to SOURCE and do an
# rpm -ba blah.spec.
#========================================================================
tgz:	$(SOURCES1) $(SOURCES2)
	# clean up stuff we don't want in the tarball.
	rm -f core $(PROGRAM1) $(OBJECTS1) $(PROGRAM2) $(OBJECTS2) \
           $(WRPM) $(WSRPM) $(TGZ) $(TAR) $(RPM) $(SRPM) $(PROGRAM).1.gz
	rm -f .$(DIR)
	# Update the specfile here, because we want the packed one to be 
	# in sync with the VERSION/RELEASE defined ABOVE (only)!
	# Might need another line or two here, e.g. %Source:
	cat $(SPEC) | \
        sed -e 's/^\(%define version\) \(.*\)/\1 $(VERSION_MAJOR).$(VERSION_MINOR)/' \
            -e 's/^\(%define release\) \(.*\)/\1 $(RELEASE)/' >> $(SPEC).$$
	mv $(SPEC).$$ $(SPEC)
	mkdir -p .$(DIR)
	cp -a * .$(DIR)
	mv .$(DIR) $(DIR)
	# Exclude any cruft/development directories and CVS stuff.  Add
	# lines as needed.
	tar -cvpf $(TAR) \
            --exclude=CVS --exclude=CRUFT \
            --exclude=$(TAR) \
            --exclude=$(TGZ) \
            --exclude=$(RPM) \
            --exclude=$(SRPM) \
            ./$(DIR)
	gzip $(TAR)
	mv $(TAR).gz $(TGZ)
	rm -rf $(DIR)

#========================================================================
# This is an EVEN MORE USEFUL target, but take a moment to understand it.  
# We take the .tgz script above, fix the revision information in the 
# (presumed existing) $(PROGRAM).spec file, copy them both to (note 
# CAREFULLY!) a presumed environmentally defined $(RPM_TOPDIR)/[SOURCE,SPEC], 
# do a build, and (Inshallah!) retrieve the results from 
# $(RPM_TOPDIR)/RPMS/i386.  Works for me...  Note well you should have
# set RPM_TOPDIR and ARCH according to the instructions above.
# 
#========================================================================
rpm:	Makefile $(SPEC) $(SOURCES1) $(SOURCES2) $(TGZ)
	cp $(TGZ) $(RPM_TOPDIR)/SOURCES
	cp $(SPEC) $(RPM_TOPDIR)/SPECS
	rpmbuild -ba  $(RPM_TOPDIR)/SPECS/$(SPEC)
	cp $(RPM_TOPDIR)/RPMS/i386/$(RPM) $(WRPM)
	mv $(RPM_TOPDIR)/RPMS/i386/$(RPM) .
	cp $(RPM_TOPDIR)/SRPMS/$(SRPM) $(WSRPM)
	mv $(RPM_TOPDIR)/SRPMS/$(SRPM) .

#========================================================================
# It will help greatly if $(CVS) exists, contains and RCS label and
# any comments, and is added to the CVS distribution, of course.
# The timestamp of for your own benefit -- an instant way to check
# which of several working directories is really currentest.
#========================================================================
cvs:
	cat $(CVS) | \
	sed -e '/^New Checkin/d' >> $(CVS).tmp
	mv $(CVS).tmp $(CVS)
	echo "New Checkin `date`" >> $(CVS)	# Will force a commit and increment revision
	cvs commit .		# doesn't sync (yet).

#========================================================================
# This is a poor man's solution to both backup and having several
# development "homes" each with their own CVSROOT (as I do -- one at
# literally my home, one at Duke, and one on my laptop that needs to
# be sync'd up before and after trips.  Just add one line per host
# to be kept identical.  Be warned that if a host on the list is down,
# this will hang boring while waiting for a timeout.  It presumes that
# you have rsync (and that you use ssh) and that you have installed
# the "synccvs" script:
#
#!/bin/sh
# CVS_PKG=$1;CVS_HOST=$2
# rsync -avz --delete --rsh=/usr/bin/ssh $CVSROOT/$CVS_PKG $CVS_HOST:\$CVSROOT
#
# on your path.  There's probably some way to protect the latter CVSROOT
# from early interpretation in a Makefile, but I cannot find it.
#========================================================================
sync:
	make cvs	# Start by checking in ALWAYS.
	synccvs $(DIR) login.phy.duke.edu
	synccvs $(DIR) 209.42.212.5
	# Change these to your own set of CVSROOTed sources.  TEST
	# CAREFULLY!

#========================================================================
# printout makes an enscript -2r printout of SOURCES and
# and INCLUDES.  Use lpr if you don't have enscript
#========================================================================
LPR = enscript -2r
# LPR = lpr
printout:
	$(LPR) $(SOURCES) $(INCLUDES) $(ABS)

#========================================================================
#  A standard cleanup target
#========================================================================
clean:
	rm -f core $(PROGRAM) $(OBJECTS) $(PROGRAM).1.gz

#========================================================================
# Generic Rule to install.  Note that I presume that ALL applications
# have a man page for documentation!  They'd better!
#========================================================================
install :
	(strip $(PROGRAM1);\
	strip $(PROGRAM2);\
	install -d $(PREFIX)/bin/$(PVM_ARCH); \
	install -d $(PREFIX)/share/man/man1; \
	install -m 755 $(PROGRAM1) $(PREFIX)/bin/$(PVM_ARCH); \
	install -m 755 $(PROGRAM2) $(PREFIX)/bin/$(PVM_ARCH); \
	gzip -c $(DIR).1 > $(DIR).1.gz; \
	install -m 644 $(DIR).1.gz $(PREFIX)/share/man/man1)

#========================================================================
# Another fairly advanced target.  You might want to make this project
# available on the web (with a page of its own.  Assuming that you have 
# rsync access from your development system(s) to your public_html
# directory, the following target automagically installs the i386 rpm,
# the src rpm, and the tarball into a directory named $(PROGRAM) on
# a path on your website, and also installs a project abstract (in html
# or php) into that directory and $(PROGRAM).php one directory up.
# The $(PROGRAM).php is intended to create a "standard presentation"
# page for the program and abstract along the lines of what you'd see
# on my website.  Of course you could do what you like, or install an
# html or other file instead of php if you prefer.  Still, I like it.
# I can automagically update any source I offer on the web with a simple
# "make installweb" from any system on which I'm working.
#========================================================================
installweb : $(TGZ) $(WRPM) $(WSRPM) $(PHP) $(ABS)
	(mkdir $(DIR);\
	rsync -avz $(DIR) login.phy.duke.edu:public_html/General/; \
	rsync -avz $(TGZ) login.phy.duke.edu:public_html/General/$(DIR)/; \
	rsync -avz $(WRPM) login.phy.duke.edu:public_html/General/$(DIR)/; \
	rsync -avz $(WSRPM) login.phy.duke.edu:public_html/General/$(DIR)/; \
	rsync -avz $(ABS) login.phy.duke.edu:public_html/General/$(DIR)/; \
	rsync -avz $(PHP) login.phy.duke.edu:public_html/General/;\
	rmdir $(DIR))



#========================================================================
# We give all generic rules below.  Currently we only need a rule for 
# objects.
#========================================================================
%.o:%.c $(INCLUDES)
	$(CC) -c $(CFLAGS) $<

