Newer
Older
Handbook / makefile-templates / Makefile.handbook
################################################################################
#
# Makefile for DBCOURSES handbooks. Revamped completely from old
# monolithic version to a "many-makefiles" model. Each major sub-unit of
# the handbook has its own makefile, and is called recursively from here.
# This makes management of the whole process a bit more complex, but a lot
# more flexible. It's now possible, for example, to build many of the
# files for a single tutorial by going into that tutorial's directory and
# running a make there. The old scheme was also wont to rebuild lots of
# extraneous stuff when only one file changed (especially with graphics).
# This does not appear to be (and should not) be a problem with the new
# scheme.
#
################################################################################


SHELL=/bin/sh


################################################################################
#
# Get path to current Makefile so we can set up self-deleting temporary
# directory. Note that this MUST happen before the first include!
#
MAKEFILE:=$(CURDIR)/$(lastword $(MAKEFILE_LIST))


################################################################################
#
# Given that we print out our own messages, I see no point in splurging
# "Entering...leaving directory" messages all over the screen. It's hard
# enough to figure out what's going on already :)
#
MAKEFLAGS=--no-print-directory


################################################################################
#
# Required Environment Variables
#
# TEACHING_SHARED
#	This variable specifies the path to the top level of the teaching
#	shared directory hierarchy (e.g., /path/to/Teaching/Shared).
#
TEACHING_SHARED?=$(error The required environment variable TEACHING_SHARED has not been defined. It should point to the root level of the shared teaching directory (e.g., /path/to/Teaching/Shared))
#
# ALL_PAPERS_ROOT
#	This variable specifies the path to the top level directory for all
#	papers taught, i.e., the directory that contains the individual paper
#	directory hierarchies. For example, /path/to/Teaching/2005.
#
ALL_PAPERS_ROOT?=$(error The required environment variable ALL_PAPERS_ROOT has not been defined. It should point to the root level of the current teaching directory hierarchy (e.g., /path/to/Teaching/2005))
#
# HANDBOOK_INSTALL_ROOT
#	This variable specifies the path to the top level directory on the web
#	server, under which the files for this paper will be installed (that is,
#	the directory that contains the individual paper directory hierarchies).
#	For example, \\INFO-NTS-12\DBCourses$ (this may require munging).
#
HANDBOOK_INSTALL_ROOT?=$(error The required environment variable HANDBOOK_INSTALL_ROOT has not been defined. It should point to the root level of the directory hierarchy on the web server (e.g., \\INFO-NTS-12\DBCourses$))


################################################################################
#
# Set up paths to makefile include directories.
#
# GLOBAL_HANDBOOK_INCLUDE is the global include directory in the "Shared"
# hierarchy, and is defined relative to the root of that hierarchy.
#
# LOCAL_HANDBOOK_INCLUDE is the local include directory for this
# particular paper, and is defined relative to the current execution
# directory. We are assuming a fixed directory structure here! We can't
# really do this as an environment variable because the full path will be
# different for each paper, and we can't use the variables from
# paper_variables.make to set the path, because that file is in the
# include directory! <head spins> We will, however, allow for the
# possibility of someone wanting to define this as an environment variable
# by making it a conditional assignment.
#
GLOBAL_HANDBOOK_INCLUDE?=$(TEACHING_SHARED)/Authoring/Handbook/make-includes

export LOCAL_HANDBOOK_INCLUDE?=$(shell pwd)/make-includes


################################################################################
#
# Include local system-specific configuration.
#
include $(GLOBAL_HANDBOOK_INCLUDE)/local_configuration.make


################################################################################
#
# Set up global, self-deleting temporary directory. The first time through,
# TEMPDIR will be undefined, so the first part of the if will create the
# variable, then recursively call the makefile again with the appropriate
# targets, passing the temporary directory as an argument.
#
ifndef TEMPDIR

.PHONY: all

all:
	@TEMPDIR=$(shell $(MKTEMP) -d); \
	trap 'rm -rf "$$TEMPDIR"' EXIT; \
	$(MAKE) -f $(MAKEFILE) --no-print-directory TEMPDIR=$$TEMPDIR all

%:
	@TEMPDIR=$(shell $(MKTEMP) -d); \
	trap 'rm -rf "$$TEMPDIR"' EXIT; \
	$(MAKE) -f $(MAKEFILE) --no-print-directory TEMPDIR=$$TEMPDIR $@


################################################################################
#
# Normal makefile follows.
#
else


################################################################################
#
# Include standard make environment variables.
#
include $(GLOBAL_HANDBOOK_INCLUDE)/standard_environment.make


################################################################################
#
# Include variables defining the current paper.
#
include $(LOCAL_HANDBOOK_INCLUDE)/paper_variables.make


################################################################################
#
# Directories for the major sections. Add to as necessary. Sections should
# be listed in the order that they will appear in the handbook. Remember to
# exclude CVS directories (doh!).
#
SECTION_DIRS:=$(shell $(FIND) sections -mindepth 1 -maxdepth 1 -type d -not -name CVS)


################################################################################
#
# Run one-time initialisation stuff.
#
# Ensure that the patterns files exist. If they don't, copy the originals
# across from the shared directory and abort the run so that the user can
# edit them appropriately.
#
CHECK_ANSWERS_PATTERNS:=$(shell ($(TEST) -f $(LOCAL_HANDBOOK_INCLUDE)/answers.patterns) || ($(CP) $(TEACHING_SHARED)/Authoring/Handbook/makefile-templates/answers.patterns $(LOCAL_HANDBOOK_INCLUDE); $(ECHO) "answers"))
CHECK_QUESTIONS_PATTERNS:=$(shell ($(TEST) -f $(LOCAL_HANDBOOK_INCLUDE)/questions.patterns) || ($(CP) $(TEACHING_SHARED)/Authoring/Handbook/makefile-templates/questions.patterns $(LOCAL_HANDBOOK_INCLUDE); $(ECHO) "questions"))
CHECK_INSTALL_PATTERNS:=$(shell ($(TEST) -f $(LOCAL_HANDBOOK_INCLUDE)/install.patterns) || ($(CP) $(TEACHING_SHARED)/Authoring/Handbook/makefile-templates/install.patterns $(LOCAL_HANDBOOK_INCLUDE); $(ECHO) "install"))
CHECK_ALL_PATTERNS:=$(CHECK_ANSWERS_PATTERNS) $(CHECK_QUESTIONS_PATTERNS) $(CHECK_INSTALL_PATTERNS)

ifneq "$(strip $(CHECK_ALL_PATTERNS))" ""
$(error Patterns files have been restored from defaults ($(CHECK_ALL_PATTERNS)), please check them before continuing)
endif
#
# Delete the marker file that indicates that we've already initialised the
# sub-sections by removing their "content checked" marker files. There's
# only one of these, so it's much easier to deal with :)
#
# Note: NOINIT should _not_ be exported to this sub-make, to ensure that
# the sub-makefile's one-time initialisation is executed.
#
CLEANUP_MARKER_FILES:=$(foreach d,$(SECTION_DIRS),$(shell $(MAKE) -C $d init-clean))


################################################################################
#
# Load in patterns for which items to install. In particular, we are looking
# for the value "handbook_root" to appear in either QUESTION_INSTALL_PATTERNS
# or ANSWER_INSTALL_PATTERNS. This tells us whether to install links for the
# questions and answers versions of the handbook, respectively. Yes, this is
# a hack!
#
# *_INSTALL_PATTERNS defines the patterns for installing on the web server.
#
QUESTION_INSTALL_PATTERNS:=
ANSWER_INSTALL_PATTERNS:=

#
# Load in the install patterns from the local make-includes directory.
#
include $(LOCAL_HANDBOOK_INCLUDE)/install.patterns


################################################################################
#
# Lists of LaTeX files to be \input into the master LaTeX document. Just
# build a single list for everything; we can extract the sections we want
# at the time using make's filter function, as the sections have distinct
# names. These are statically defined rather than using a find command,
# because the files may not exist at the time the find command is
# executed. This Would Be Non-Useful.
#
QUESTION_TEX_INPUTS:=$(foreach d,$(SECTION_DIRS),$d/question-manifest.tex)
ANSWER_TEX_INPUTS:=$(foreach d,$(SECTION_DIRS),$d/answer-manifest.tex)

LATEX_INCLUDES:=$(shell $(FIND) latex-includes -name "*.tex")


################################################################################
#
# Additional options for the coursehandbook document class to set up
# the details of the paper. These get included in a call to the
# \papersetup macro in the template file (including the options
# directly into the \documentclass is problematic --- see
# coursehandbook.cls for details). The values are set in
# latex-includes/paper_variables.make.
#
PAPER_OPTIONS:=subjectcode=$(SUBJECT_CODE),papernumber=$(PAPER_NUMBER),papertitle=$(PAPER_TITLE),paperyear=$(PAPER_YEAR),paperperiod=$(PAPER_PERIOD),authors=$(HANDBOOK_AUTHORS)


################################################################################
#
# Directory to install files into on web server.
#
INSTALL_DIRECTORY:=$(HANDBOOK_INSTALL_ROOT)/$(SUBJECT_CODE)$(PAPER_NUMBER)/Handbook


################################################################################
#
# Files to be installed on web server.
#
QUESTION_INSTALL_FILES:=handbook.pdf handbook-2up.pdf $(wildcard *.png)

ANSWER_INSTALL_FILES:= handbook-answers.pdf handbook-answers-2up.pdf \
	$(wildcard *.png)

# Sorting gets rid of any duplicates (e.g., the PNG files).
INSTALL_FILES:=$(sort $(QUESTION_INSTALL_FILES) $(ANSWER_INSTALL_FILES))


################################################################################
#
# Lists of files for cleaning up.
#
WEB_CLEAN_FILES:=*.png
PRINT_CLEAN_FILES:=handbook.tex handbook-answers.tex \
	*.pdf *.ps *.dvi *.aux *.log *.toc *.idx *.ind *.tex~ *.out
ALL_CLEAN_FILES:=$(WEB_CLEAN_FILES) $(PRINT_CLEAN_FILES)


################################################################################
#
# List of possible targets.
#
TARGETS:=all targets debug install \
	web web-questions web-answers \
	print print-questions print-answers \
	questions answers \
	section-questions section-answers \
	question-pdfs answer-pdfs \
	clean web-clean print-clean

.PHONY: $(TARGETS)


################################################################################
#
# Build everything.
#
all: web print


################################################################################
#
# Build questions/answers only.
#
questions: web-questions print-questions

answers: web-answers print-answers


################################################################################
#
# Build web version only. NOINIT and SECTION should be exported to all
# these sub-makes.
#
web: general-graphics web-questions web-answers

web-questions:
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d web-questions NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)

web-answers:
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d web-answers NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)


################################################################################
#
# Build print version only. NOINIT and SECTION should be exported to all
# these sub-makes.
#
print: general-graphics print-questions print-answers

print-questions: section-questions handbook.pdf handbook-2up.pdf question-pdfs

section-questions:
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d print-questions NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)

handbook.tex: handbook_template.tex $(QUESTION_TEX_INPUTS) $(LOCAL_HANDBOOK_INCLUDE)/questions.patterns $(LATEX_INCLUDES)
	@$(ANNOUNCE) "Generating $@"
	@$(ECHO) "% THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT!" > $@
	@$(ECHO) >> $@
	@$(PERL) -p -e "s|\<\@SHOWANSWERS\@\>|hideanswers|;" \
		-e "s|\<\@PAPEROPTIONS\@\>|$(PAPER_OPTIONS)|;" \
		$(foreach sect,$(SECTION_DIRS),-e "s|\<\@SECTION\[$(notdir $(sect))\]\@\>|\\\\input{$(basename $(filter $(sect)/%,$(QUESTION_TEX_INPUTS)))}|;") $< >> $@

question-pdfs:
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d question-pdfs NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)

#
# Answers
#
print-answers: section-answers handbook-answers.pdf handbook-answers-2up.pdf answer-pdfs

section-answers:
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d print-answers NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)

handbook-answers.tex: handbook_template.tex $(ANSWER_TEX_INPUTS) $(LOCAL_HANDBOOK_INCLUDE)/answers.patterns $(LATEX_INCLUDES)
	@$(ANNOUNCE) "Generating $@"
	@$(ECHO) "% THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT!" > $@
	@$(ECHO) >> $@
	@$(PERL) -p -e "s|\<\@SHOWANSWERS\@\>|showanswers|;" \
		-e "s|\<\@PAPEROPTIONS\@\>|$(PAPER_OPTIONS)|;" \
		$(foreach sect,$(SECTION_DIRS),-e "s|\<\@SECTION\[$(notdir $(sect))\]\@\>|\\\\input{$(basename $(filter $(sect)/%,$(ANSWER_TEX_INPUTS)))}|;") $< >> $@

answer-pdfs:
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d answer-pdfs NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)

#
# Generic rules for print version.
#
%.pdf: %.tex
	@$(ANNOUNCE) "pdflatex $< (pass 1)"
	$(PDFLATEX) --jobname=$(basename $<) '\def\LaTeXOptions{12pt,a4paper}\input{$<}'
	@$(ANNOUNCE) "pdflatex $< (pass 2)"
	$(PDFLATEX) --jobname=$(basename $<) '\def\LaTeXOptions{12pt,a4paper}\input{$<}'

%-2up.pdf: %.pdf
	@$(ANNOUNCE) "Generating $@"
	$(PDFNUP) --nup 2x1 --outfile $@ $<


################################################################################
#
# Build any general graphics that are used throughout the handbook. This uses
# the standard makefile for a content directory, but the only files in this
# directory are graphics files.
#
general-graphics:
	@if $(MAKE) -C graphics general-graphics BUILD_DIR=$(CURDIR); then $(TRUE); else exit 1; fi


################################################################################
#
# Deploy the appropriate files into a shared folder, which is then synchronised
# with Blackboard. This relies on the environment variable HANDBOOK_INSTALL_ROOT
# being defined, and (assuming that this variable points to a directory on the
# network) the appropriate share has been mounted.
#
# See build_document_rules.make for an explanation of why the install
# uses a foreach.
#
install: questions answers
	@$(SITECOPY) --catchup Blackboard$(PAPER_NUMBER)
	@$(ANNOUNCE) "Deploying handbook files to Blackboard --- make sure that you have the share mounted!"
	@$(TEST) -d $(HANDBOOK_INSTALL_ROOT)
	@$(MKDIR_P) $(INSTALL_DIRECTORY)
	@$(foreach d,$(SECTION_DIRS),if $(MAKE) -C $d $@ NOINIT=x SECTION=$(notdir $(d)); then $(TRUE); else exit 1; fi;)
	@$(ANNOUNCE) "Deploying files into $(INSTALL_DIRECTORY)"
	@$(foreach f,$(QUESTION_INSTALL_FILES),if $(TEST) ! -f $(INSTALL_DIRECTORY)/$(f) -o $(f) -nt $(INSTALL_DIRECTORY)/$(f); then $(ECHO) "Deploying $(f)"; $(CP) $(f) $(INSTALL_DIRECTORY); fi;)
	@$(foreach f,$(ANSWER_INSTALL_FILES),if $(TEST) ! -f $(INSTALL_DIRECTORY)/$(f) -o $(f) -nt $(INSTALL_DIRECTORY)/$(f); then $(ECHO) "Deploying $(f)"; $(CP) $(f) $(INSTALL_DIRECTORY); fi;)
	@$(ANNOUNCE) "Synchronising with Blackboard"
	@$(SITECOPY) --update Blackboard$(PAPER_NUMBER)


################################################################################
#
# Clean up all generated files.
# "web-clean" and "print-clean" only clean up files for the web and print
# versions, respectively. Note that "clean" isn't dependent on either
# "web-clean" or "print-clean", to ensure that the correct target is
# used when calling the sub-makefile.
#
clean:
	@$(foreach d,$(SECTION_DIRS),$(MAKE) -C $d $@;)
ifneq ($(strip $(ALL_CLEAN_FILES)),)
	-$(RM) -f $(ALL_CLEAN_FILES)
	@$(MAKE) -C graphics clean BUILD_DIR=$(CURDIR)
endif

web-clean:
	@$(foreach d,$(SECTION_DIRS),$(MAKE) -C $d $@;)
ifneq ($(strip $(WEB_CLEAN_FILES)),)
	-$(RM) -f $(WEB_CLEAN_FILES)
endif

print-clean:
	@$(foreach d,$(SECTION_DIRS),$(MAKE) -C $d $@;)
ifneq ($(strip $(PRINT_CLEAN_FILES)),)
	-$(RM) -f $(PRINT_CLEAN_FILES)
endif


################################################################################
#
# Debugging information, mostly lists of the generated variables.
#
debug:
	@$(ANNOUNCE) Externally defined variables
	@$(ECHO) "TEACHING_SHARED = [$(TEACHING_SHARED)]"
	@$(ECHO) "HANDBOOK_INSTALL_ROOT = [$(HANDBOOK_INSTALL_ROOT)]"
	@$(ANNOUNCE) Internally defined variables
	@$(ECHO) "GLOBAL_HANDBOOK_INCLUDE = [$(GLOBAL_HANDBOOK_INCLUDE)]"
	@$(ECHO) "LOCAL_HANDBOOK_INCLUDE = [$(LOCAL_HANDBOOK_INCLUDE)]"
	@$(ECHO) "SECTION_DIRS = [$(SECTION_DIRS)]"
	@$(ECHO) "QUESTION_TEX_INPUTS = [$(QUESTION_TEX_INPUTS)]"
	@$(ECHO) "ANSWER_TEX_INPUTS = [$(ANSWER_TEX_INPUTS)]"
	@$(ECHO) "LATEX_INCLUDES = [$(LATEX_INCLUDES)]"
	@$(ECHO) "INSTALL_DIRECTORY = [$(INSTALL_DIRECTORY)]"
	@$(ECHO) "INSTALL_FILES = [$(INSTALL_FILES)]"
	@$(ECHO) "QUESTION_INSTALL_FILES = [$(QUESTION_INSTALL_FILES)]"
	@$(ECHO) "ANSWER_INSTALL_FILES = [$(ANSWER_INSTALL_FILES)]"
	@$(ECHO) "QUESTION_INSTALL_PATTERNS = [$(QUESTION_INSTALL_PATTERNS)]"
	@$(ECHO) "ANSWER_INSTALL_PATTERNS = [$(ANSWER_INSTALL_PATTERNS)]"
	@$(ECHO) "WEB_CLEAN_FILES = [$(WEB_CLEAN_FILES)]"
	@$(ECHO) "PRINT_CLEAN_FILES = [$(PRINT_CLEAN_FILES)]"
	@$(ECHO) "ALL_CLEAN_FILES = [$(ALL_CLEAN_FILES)]"
	@$(ECHO) "SUBJECT_CODE = [$(SUBJECT_CODE)]"
	@$(ECHO) "PAPER_NUMBER = [$(PAPER_NUMBER)]"
	@$(ECHO) "PAPER_TITLE = [$(PAPER_TITLE)]"
	@$(ECHO) "PAPER_YEAR = [$(PAPER_YEAR)]"
	@$(ECHO) "PAPER_PERIOD = [$(PAPER_PERIOD)]"
	@$(ECHO) "HANDBOOK_AUTHORS = [$(HANDBOOK_AUTHORS)]"
	@$(ECHO) "PAPER_OPTIONS = [$(PAPER_OPTIONS)]"
ifdef TEMPDIR
	@$(ECHO) "TEMPDIR = [$(TEMPDIR)]"
endif


################################################################################
#
# Print out the list of targets. Handy for when you forget!
#
targets:
	@$(ECHO) $(TARGETS)


endif