# Makefile for single executable C++ project with auto-dependencies and
# multiple build options
# Copyright (C) 2000-2003 Marc Mongenet

###############################################################################
# PROJECT SPECIFIC DEFINITIONS
###############################################################################

# name of file to build
EXE = xgalaga++

# name of manual (leave empty if none)
MANUAL = xgalaga++.6x

# source files suffix (all source files must have the same suffix)
SOURCE_SUFFIX = cc

# C++ compiler
CXX = g++

# source files directory
srcdir = .

# build directory
builddir = .

# installation directories
installprefix = /usr
bindir = $(installprefix)/games
mandir = $(installprefix)/share/man/man6

# preprocessor options to find all included files
INC_PATH = -I$(srcdir) -I/usr/local/include

# libraries link options ('-lm' is common to link with the math library)
LNK_LIBS = -lm -lX11 -lXpm -L/usr/local/lib/

# other compilation options
# The high scores file is only writable by the executable and shared
# by all players.
HIGH_SCORES_FILE=/var/games/xgalaga++.scores
#HIGH_SCORES_FILE=.xgalaga++.scores

# This group is used for the executable and high scores file.
# The executable is setgid.
EXE_GROUP=games

COMPILE_OPTS = -DHIGH_SCORES_FILE=$(HIGH_SCORES_FILE)

# basic compiler warning options (for GOAL_EXE)
BWARN_OPTS = -Wall -ansi

# extented compiler warning options (for GOAL_DEBUG)
EWARN_OPTS = $(BWARN_OPTS) -pedantic -W\
	     -Wshadow -Wpointer-arith -Wcast-qual -Wcast-align\
	     -Wwrite-strings -Woverloaded-virtual -Winline

###############################################################################
# INTERNAL DEFINITIONS
# The following definitions are designed to be project neutral.
###############################################################################

# You may freely change the following goal names if you dislike them.
GOAL_DEBUG = debug
GOAL_PROF = prof
GOAL_EXE = all

# build options for GOAL_DEBUG (executable for debugging) goal
ifeq "$(MAKECMDGOALS)" "$(GOAL_DEBUG)"

 # specific options for debugging
 GOAL_OPTS = -g
 # compilation verification options
 WARN_OPTS = $(EWARN_OPTS)
 # optimization options
 OPTIMISE_OPTS =
 # dependencies must be up to date
 CHECK_DEPS = yes

else

 # build options for GOAL_PROF (executable for profiling) goal
 ifeq "$(MAKECMDGOALS)" "$(GOAL_PROF)"

  # specific options for profiling
  GOAL_OPTS = -pg
  # compilation verification options
  WARN_OPTS = $(BWARN_OPTS)
  # optimization options
  OPTIMISE_OPTS = -O
  # dependencies must be up to date
  CHECK_DEPS = yes

 else

  # build options for GOAL_EXE (optimized executable) goal
  ifeq "$(MAKECMDGOALS)" "$(GOAL_EXE)"

   # specific options for optimized executable
   GOAL_OPTS = -s
   # compilation verification options
   WARN_OPTS = $(BWARN_OPTS)
   # optimization options
   OPTIMISE_OPTS = -Os -fomit-frame-pointer
   # dependencies must be up to date
   CHECK_DEPS = yes

  else

   # Other goals do not require up to date dependencies.
   CHECK_DEPS = no

  endif
 endif
endif

# preprocessor options
CPPOPTS = $(INC_PATH)

# compiler options
CXXOPTS = $(GOAL_OPTS) $(COMPILE_OPTS) $(WARN_OPTS) $(OPTIMISE_OPTS)

# linker options
LDOPTS = $(GOAL_OPTS) $(LNK_LIBS)

# source files in this project
sources := $(wildcard $(srcdir)/*.$(SOURCE_SUFFIX))

# object files in this project
objs := $(notdir $(sources))
objs := $(addprefix $(builddir)/, $(objs))
objs := $(objs:.$(SOURCE_SUFFIX)=.o)

# executable with full path
exe = $(builddir)/$(EXE)

# This makefile creates and includes makefiles containing actual dependencies.
# For every source file a dependencies makefile is created and included.
# The deps variable contains the list of all dependencies makefiles.
deps_suffix = d
deps := $(objs:.o=.$(deps_suffix))

# To detect goal changes (for instance from GOAL_DEBUG to GOAL_EXE)
# between invocations, this makefile creates an empty file (the goal flag
# file) which suffix is the goal name.
goal_flag_file_prefix = $(builddir)/Last_make_goal_was_
goal_flag_file = $(goal_flag_file_prefix)$(MAKECMDGOALS)

###############################################################################
# TARGETS
###############################################################################

# Delete the target file of a rule if the command used to update it failed.
# Do that because the newly generated target file may be corrupted but appear
# up to date.
.DELETE_ON_ERROR:

# Clear default suffix list to disable all implicit rules.
.SUFFIXES:

# usage message for this makefile
.PHONY:	usage
usage:
	@echo "GOAL      EFFECT"
	@echo "----      ------"
	@echo "usage     print this message"
	@echo "list      list the source files"
	@echo "$(GOAL_EXE)       build the executable"
	@echo "$(GOAL_DEBUG)     build the executable with debug options"
	@echo "$(GOAL_PROF)      build the executable with profiling options"
	@echo "clean     remove all built files"
	@echo "install   install executable, manual, and high scores files"
	@echo "uninstall remove executable and manual files"

# If source files exist then build the EXE file.
.PHONY:	$(GOAL_EXE)
ifneq "$(strip $(sources))" ""
$(GOAL_EXE):	$(exe)
else
$(GOAL_EXE):
	@echo "No source file found."
endif

# GOAL_DEBUG and GOAL_PROF targets use the same rules than GOAL_EXE.
.PHONY:	$(GOAL_DEBUG)
$(GOAL_DEBUG):	$(GOAL_EXE)

.PHONY:	$(GOAL_PROF)
$(GOAL_PROF):	$(GOAL_EXE)

###############################################################################
# BUILDING
# Note: CPPFLAGS, CXXFLAGS or LDFLAGS are not used but may be specified by the
# user at make invocation.
###############################################################################

# linking
$(exe):	$(objs)
	$(CXX) $^ -o $@ $(LDOPTS) $(LDFLAGS)

# explicit definition of the implicit rule used to compile source files
$(builddir)/%.o:	$(srcdir)/%.$(SOURCE_SUFFIX)
	$(CXX) -c $< $(CPPOPTS) $(CXXOPTS) $(CPPFLAGS) $(CXXFLAGS) -o $@

# Rule to build our included dependencies makefiles.
# This rule is used by GNU Make because it automatically tries to (re)build
# obsolete or non-existent included makefiles.
# These files are created with one line of the form:
# 1.o 1.d: $(goal_flag_file) 1.cc 1.h 2.h 3.h g.h
# The implicit rule previously defined will be used for compilation.
# Note that the dependencies can be goal specific.
# The goal_flag_file is determined at run time because it must be the current
# goal and not the goal in use when the dependencies makefile was created.
$(builddir)/%.$(deps_suffix):	$(srcdir)/%.$(SOURCE_SUFFIX) $(goal_flag_file)
	$(SHELL) -ec '$(CXX) -MM $(CPPOPTS) $(CPPFLAGS) $< |\
	sed '\''s@\($*\)\.o[ :]*@$(builddir)/\1.o $@: $$(goal_flag_file) @g'\'' > $@;\
	[ -s $@ ] || rm -f $@'

# If dependencies have to be up to date then include dependencies makefiles.
ifeq "$(CHECK_DEPS)" "yes"
 ifneq "$(strip $(sources))" ""
  include $(deps)
 endif
endif

# Rule to produce the goal flag file.
# If the goal has changed then we must rebuild on a clean state because
# pre-processor DEFINE's may have changed.
$(goal_flag_file):
	rm -f $(exe) $(goal_flag_file_prefix)* $(objs) $(deps)
	touch $@

###############################################################################
# NON-BUILD TARGETS
###############################################################################

# List the source files
.PHONY:	list
list:
	@echo $(sources) | tr [:space:] \\n

# Remove all files that are normally created by building the program.
.PHONY:	clean
clean:
	rm -f $(exe) $(goal_flag_file_prefix)* $(objs) $(deps)

###############################################################################
# INSTALLATION TARGETS
###############################################################################

# Installation procedure
# Customized for XGalaga++
install:
	cp $(EXE) $(bindir)
	if [ -n "$(MANUAL)" ]; then cp $(MANUAL) $(mandir); fi
	if [ -n "$(EXE_GROUP)" ]; then chgrp $(EXE_GROUP) $(bindir)/$(EXE); fi
	chmod g+s $(bindir)/$(EXE)
	touch $(HIGH_SCORES_FILE)
	if [ -n "$(EXE_GROUP)" ]; then chgrp $(EXE_GROUP) $(HIGH_SCORES_FILE); fi
	chmod 664 $(HIGH_SCORES_FILE)

.PHONY:	uninstall
uninstall:
	rm $(bindir)/$(EXE)
	rm $(mandir)/$(MANUAL)
