#====================================================================== # $Id: Makefile 1132 2006-05-19 18:33:32Z gvwilson $ # # +< # This Makefile rebuilds everything in the Software Carpentry course # project. To see what targets are available, type 'make help'. Note # that this Makefile depends upon the GNU Make extensions, so it will # probably only run with gmake. # # Most course content is in ``.swc`` files, which use a home-grown # XML dialect to mark up slides, lecture notes, exercises, and so on. # Customization is done by copying ``conf/platform_template.mk`` and # ``conf/config_template.mk`` to create ``platform.mk`` and # ``config.mk``, and then making changes there. To change which # lectures are included, and what order they're in, edit the # ``LECTURES`` variable in the ``config.mk`` file. # # To delete bibliography, glossary, and external link entries that are # not referenced in the included lectures, set ``DELETE_ENTRIES`` to # ``-D``. # # To add site-specific content (e.g., for Euphoric State University): # # * Create a ``sites/esu`` directory # * Add ``.swc`` files # * Edit the definition of ``SITES`` in ``config.mk`` # # The major output of this Makefile is the ``web`` directory, which # contains the course notes in ready-to-view HTML. The positions # of files in this directory exactly mirrors their positions in the # project as a whole, i.e. relative links should always continue to # work. # # The build also creates a "unified" file in the ``web/lec`` # directory. This file contains all of the course lecture content in # a single page for easy printing and searching. # # PDF versions of the lecture notes are created in the ``pdf`` # directory, but only on demand. These files can only be created on # machines where Prince has been installed. # # Another significant output is the ``docs`` directory. It contains # wiki-formatted documentation on the SWC build system and tools; # these are saved under version control so that they can be viewed # on systems that aren't set up to build the course, and so that any # changes in them can be highlighted. # >+ #====================================================================== # Platform specification file. PLATFORM = ./platform.mk # Configuration file. CONFIG = ./config.mk # +< # This Makefile only runs if it can find the files ``platform.mk`` and # ``config.mk``. If these file do not, an error message is printed # and the build stops. # >+ ifeq ($(wildcard ${PLATFORM}),) $(error ${PLATFORM} cannot be found: copy and edit ./conf/platform_template.mk) else include ${PLATFORM} endif ifeq ($(wildcard ${CONFIG}),) $(error ${CONFIG} cannot be found: copy and edit ./conf/config_template.mk) else include ${CONFIG} endif #---------------------------------------------------------------------- # General definitions #---------------------------------------------------------------------- # +< # Setting ``VERBOSE`` before invoking Make will pass the ``-v`` flag # to scripts and utilities. # >+ ifdef VERBOSE VERBOSE_FLAG = -v endif # What to delete when tidying up. TIDY_JUNK := \ $(wildcard tmp) \ $(foreach dir,. ./* ./*/* ./*/*/*, \ $(wildcard ${dir}/*~) \ $(wildcard ${dir}/*.pyc) \ $(wildcard ${dir}/Thumbs.db) \ ) # Extra stuff to delete when *really* cleaning up. CLEAN_JUNK := \ ${TIDY_JUNK} \ $(wildcard web) \ $(wildcard ./release.tgz) # Utilities. UTILS := \ ./Makefile \ ./conf/config_template.mk \ ./conf/platform_template.mk \ $(wildcard ./util/*.py) \ $(wildcard ./util/*.xsl) # Wiki documentation files. WIKI_DOCS := $(foreach fname,$(subst ./,./docs/,${UTILS}),${fname}.wiki) # Name of file that records information used to link lectures together. LINKAGES := ./tmp/linkages.tmp.py # The lecture source files. LECTURES_SRC := $(foreach lec,${LECTURES},./lec/${lec}.swc) # The site-specific files to include. SITE_SRC := \ $(foreach sitedir,${SITES}, \ $(wildcard ${sitedir}/*.swc) \ $(wildcard ${sitedir}/*/*.swc) \ ) # The .swc files to translate... LICENSE_SRC := ./license.swc PAGES_SRC := \ ./index.swc \ ${LICENSE_SRC} \ ${LECTURES_SRC} \ ${SITE_SRC} # ...the temporary files that will be fed to XSLT... PAGES_TMP := $(subst ./,./tmp/,${PAGES_SRC}) # ...and the output pages. PAGES_WEB := $(subst .swc,.html,$(subst ./tmp/,./web/,${PAGES_TMP})) # The unified temporary page... UNIFIED_TMP := ./tmp/lec/unified.swc # ...and the corresponding output page. UNIFIED_WEB := ./web/lec/unified.html # Graphics files and outputs. GFX_SUFFIX := gif jpg png GFX_SRC := \ $(foreach fmt,$(GFX_SUFFIX),\ $(wildcard ./img/*.${fmt}) \ $(foreach lecdir,${LECTURES}, \ $(wildcard ./lec/img/${lecdir}/*.${fmt}) \ ) \ $(foreach sitedir,${SITES}, \ $(wildcard ./sites/${sitedir}/img/*.${fmt}) \ ) \ ) GFX_WEB := $(subst ./,./web/,${GFX_SRC}) # Miscellaneous support files (not transformed, just copied) and outputs. MISC_SRC := ./LICENSE.txt ./swc.dtd ./swc.css ./print.css MISC_WEB := $(subst ./,./web/,${MISC_SRC}) # All the text source (things to check for line endings). TEXT_SRC := ./Makefile ./tests/*/Makefile ${PAGES_SRC} ${MISC_SRC} # All the source files (text and otherwise)... ALL_SRC := ${TEXT_SRC} ${GFX_SRC} # ...and all files needed for the web site. ALL_WEB := ${PAGES_WEB} ${UNIFIED_WEB} ${MISC_WEB} ${GFX_WEB} # PDF versions of web pages. ALL_PDF := \ $(subst ./web/,./pdf/,$(subst .html,.pdf,${PAGES_WEB})) \ $(subst ./web/,./pdf/,$(subst .html,.pdf,${UNIFIED_WEB})) # Included source files. INC_SRC := \ $(foreach base,./lec/inc ./lec/tbl ./tests ${sites},\ $(wildcard ${base}/*/*.cmd) \ $(wildcard ${base}/*/*.csv) \ $(wildcard ${base}/*/*.err) \ $(wildcard ${base}/*/*.mk) \ $(wildcard ${base}/*/*.out) \ $(wildcard ${base}/*/*.py) \ $(wildcard ${base}/*/*.sql) \ $(wildcard ${base}/*/*.tbl) \ $(wildcard ${base}/*/*.txt) \ ) #---------------------------------------------------------------------- # General targets. #---------------------------------------------------------------------- # +<'''all''': By default, display options.>+ all : help # +<'''help''': Display options.>+ help : @echo "== Show help. ==" @echo "all : By default, display options." @echo "help : Display options." @echo @echo "== Make web site HTML pages. ==" @echo "web : Make course web pages." @echo @echo "== Installation. ==" @echo "install : Install files for viewing." @echo "release : Make a source release for people without SVN access." @echo @echo "== Validation. ==" @echo "finddos : Look for source files with Windows line endings." @echo "fixdos : Convert Windows line endings to Unix line endings." @echo "validate : Validate the source files." @echo @echo "== Tests. ==" @echo "settings : Display settings for debugging." @echo "linkages : Make the linkages file." @echo "tmpfiles : Make intermediate .swc files for inspection." @echo @echo "== Wiki. ==" @echo "docs : Make wiki-formatted project documentation." @echo "syllabus : Make a wiki-formatted syllabus." @echo @echo "== Housekeeping. ==" @echo "tidy : Clean up byproducts of build." @echo "clean : Delete everything made by the build." @echo "count : Count the number of words in the source files (roughly)." @echo "words : produce a concordance of the lecture notes." @echo "properties : show SVN properties of all source files." @echo "scdtd : Reverse-engineer the DTD of the .swc files." @echo "entities : Create a page showing all of the character entities." @echo "images : Make a page showing all images, with paths." @echo "tickets : list tickets from database." #---------------------------------------------------------------------- # Dependencies. #---------------------------------------------------------------------- # +< # This Makefile uses ``depend.mk``, which is built by running # ``make depend`` or ``make fakedepend``. If no such file exists, # a warning is printed, but the build continues. # # Note that ``depend.mk`` is included here, rather than at the top # of the Makefile, so that its targets will not supercede the # ``all`` target. # >+ DEPEND = ./depend.mk ifneq ($(wildcard ${DEPEND}),) include ${DEPEND} else ifeq (${MAKECMDGOALS},depend) # don't print a warning if asked to make dependencies else ifeq (${MAKECMDGOALS},) # don't print a warning if printing help else $(warning ${DEPEND} cannot be found: run 'make depend') endif endif endif # +< # '''depend''': build ``depend.mk``, which describes the exact # dependencies between ``.swc`` files and the things they include. # >+ depend : @${PYTHON} util/depend.py -o ${DEPEND} -v ${PAGES_SRC} # +< # '''fakedepend''': build a version of ``depend.mk`` that only # includes dependencies on files that actually exist. # >+ fakedepend : @${PYTHON} util/depend.py -E -o ${DEPEND} -v ${PAGES_SRC} #---------------------------------------------------------------------- # Make web site HTML pages. #---------------------------------------------------------------------- # +< # '''web''': Make course web pages in the ``web`` directory. This # is done by preprocessing copies of the ``.swc`` files in the # ``tmp`` directory, and then running XSLT on them. # >+ web : ${ALL_WEB} # Specific rule for making unified web page from .swc files. ${UNIFIED_WEB} : ${UNIFIED_TMP} ./tmp/swc.dtd @mkdir -p $(dir $@) ${XSL} util/unified.xsl $< > $@ # Generic rule for making web pages from .swc files. web/%.html : tmp/%.swc ./tmp/swc.dtd @mkdir -p $(dir $@) ${XSL} util/individual.xsl $< > $@ # Rule for making unified .swc file from individual pages. ${UNIFIED_TMP} : ${PAGES_TMP} @mkdir -p $(dir $@) ${PYTHON} util/unify.py -L ${LINKAGES} ${PAGES_TMP} > $@ # Need to have the DTD file in the temporary directory to keep xsltproc happy. ./tmp/swc.dtd : ./swc.dtd @mkdir -p $(dir $@) @cp $< $@ # +< # The rule to transform human-editable ``.swc`` files into files ready # for XSLTing is a little complicated. For details, see the # documentation on ``util/preprocess.py``. # >+ tmp/%.swc : ./%.swc ${LINKAGES} @mkdir -p $(dir $@) ${PYTHON} util/preprocess.py ${VERBOSE_FLAG} \ ${DELETE_ENTRIES} \ -L ${LINKAGES} \ -r input:install_url:value=${INSTALL_URL} \ -i $< \ -o $@ # +< # Before preprocessing the ``.swc`` files, the build extracts # information about cross-linkages, glossary references, figure and # table numbers, etc., and puts it in ``tmp/linkages.tmp.py``. The # build only overwrites this file if it needs to, so that the whole # build doesn't have to run every time a minor change is made to a # single file. For more information, see the documentation on # ``util/linkages.py``. # >+ ${LINKAGES} : ${PAGES_SRC} @mkdir -p $(dir $@) @${PYTHON} util/linkages.py ${VERBOSE_FLAG} \ -B ./lec/bib.swc \ -o $@ \ -l "${LICENSE_SRC} ${LECTURES_SRC}" \ -s "${SITE_SRC}" #---------------------------------------------------------------------- # Make other web site content. #---------------------------------------------------------------------- web/%.css : ./%.css @mkdir -p $(dir $@) cp $< $@ web/%.dtd : ./%.dtd @mkdir -p $(dir $@) cp $< $@ web/%.gif : ./%.gif @mkdir -p $(dir $@) cp $< $@ web/%.jpg : ./%.jpg @mkdir -p $(dir $@) cp $< $@ web/%.png : ./%.png @mkdir -p $(dir $@) cp $< $@ web/%.txt : ./%.txt @mkdir -p $(dir $@) cp $< $@ #---------------------------------------------------------------------- # Make PDF files (requires Prince to be installed). #---------------------------------------------------------------------- pdf : ${ALL_PDF} ./pdf/%.pdf : ./web/%.html @mkdir -p $(dir $@) ${PRINCE} $< $@ #---------------------------------------------------------------------- # Installation. #---------------------------------------------------------------------- # +< # '''install''': Install files for viewing. This requires the caller # to have set the ``INSTALL_DIR`` and ``INSTALL_USER`` variables # from the command line, or in ``config.mk``. The first is the # absolute path of the installation directory (which is created), and # the second determines who will own the installed files. # >+ install : mkdir -p ${INSTALL_DIR} cd ./web; cp --parents `find . -type f -print` ${INSTALL_DIR} cd ./web; tar zcf ${INSTALL_DIR}/sc-html.tgz `find . -type f -print` cd ./web; zip ${INSTALL_DIR}/sc-html.zip `find . -type f -print` chown -R ${INSTALL_USER} ${INSTALL_DIR} chmod a+rx `find ${INSTALL_DIR} -type d -print` chmod a+r `find ${INSTALL_DIR} -type f -print` chmod a-x `find ${INSTALL_DIR} -type f -print` # +< # '''install_pdf''': Install PDF files. # >+ install_pdf : mkdir -p ${INSTALL_DIR} tar zcf ${INSTALL_DIR}/sc-pdf.tgz `find pdf -name '*.pdf' -print | fgrep -v swc.pdf` zip ${INSTALL_DIR}/sc-pdf.zip `find pdf -name '*.pdf' -print | fgrep -v swc.pdf` cp pdf/swc.pdf ${INSTALL_DIR} # +< # '''install_src''': Install example source. # FIXME: needs to be smarter about what files to install (e.g., the # contents of the ``assets`` directory, and where to look for them. # >+ install_src : tar zcvf ${INSTALL_DIR}/sc-src.tgz `find lec/src -type f -print | fgrep -v .svn` zip ${INSTALL_DIR}/sc-src.zip `find lec/src -type f -print | fgrep -v .svn` #---------------------------------------------------------------------- # Validation. #---------------------------------------------------------------------- # +<'''finddos''': Look for source files with Windows line endings.>+ finddos : @${PYTHON} util/dos2unix.py ${TEXT_SRC} ${UTILS} ${WIKI_DOCS} ${INC_SRC} # +<'''fixdos''': Convert Windows line endings to Unix line endings.>+ fixdos : @${PYTHON} util/dos2unix.py -f ${TEXT_SRC} ${UTILS} ${WIKI_DOCS} ${INC_SRC} # +< # '''validate''': Validate the source files by checking the conditions # described in the documentation for ``util/validate.py``. # >+ validate : ${LINKAGES} @${PYTHON} util/validate.py ${VERBOSE_FLAG} \ ${DELETE_ENTRIES} \ -L ${LINKAGES} \ ${PAGES_SRC} \ | sed -e 's:\\:/:g' # +< # '''validiff''': Look for changes in validation. # >+ validiff : ${LINKAGES} @${PYTHON} util/validate.py ${VERBOSE_FLAG} \ ${DELETE_ENTRIES} \ -L ${LINKAGES} \ ${PAGES_SRC} \ | sed -e 's:\\:/:g' \ | diff -w - util/validate.out # +< # '''camelcase''': look for camel case words. # >+ camelcase : @${PYTHON} util/camelcase.py ${TEXT_SRC} ${INC_SRC} ${UTILS} | diff -b - util/camelcase.txt # +< # '''keywords''': look for Subversion keyword property on files. # >+ keywords : @${PYTHON} util/props.py svn:keywords ${TEXT_SRC} ${INC_SRC} ${UTILS} #---------------------------------------------------------------------- # Tests. #---------------------------------------------------------------------- # +< # '''settings''': Display settings for debugging. # >+ settings : @echo '== Tools ==' @echo 'PYTHON:' ${PYTHON} @echo 'PRINCE:' ${PRINCE} @echo 'XSL:' ${XSL} @echo 'SQLITE:' ${SQLITE} @echo @echo '== Configuration ==' @echo 'LECTURES:' ${LECTURES} @echo 'SITES:' ${SITES} @echo 'SITES_SC_SRC:' ${SITES_SC_SRC} @echo 'DELETE_ENTRIES:' ${DELETE_ENTRIES} @echo 'DB_PATH:' ${DB_PATH} @echo 'LINKAGES:' ${LINKAGES} @echo 'FRIB:' ${FRIB} @echo @echo '== Pages ==' @echo 'LECTURES_SRC:' ${LECTURES_SRC} @echo 'PAGES_SRC:' ${PAGES_SRC} @echo 'PAGES_TMP:' ${PAGES_TMP} @echo 'PAGES_WEB:' ${PAGES_WEB} @echo @echo '== Graphics ==' @echo 'GFX_SUFFIX:' ${GFX_SUFFIX} @echo 'GFX_SRC:' ${GFX_SRC} @echo 'GFX_WEB:' ${GFX_WEB} @echo @echo '== Misc ==' @echo 'MISC_SRC:' ${MISC_SRC} @echo 'MISC_WEB:' ${MISC_WEB} @echo @echo '== All source files ==' @echo 'ALL_SRC:' ${ALL_SRC} @echo @echo '== All web files ==' @echo 'ALL_WEB:' ${ALL_WEB} @echo @echo '== All PDF files ==' @echo 'ALL_PDF:' ${ALL_PDF} @echo @echo '== Included source ==' @echo 'INC_SRC:' ${INC_SRC} @echo @echo '== Utilities ==' @echo 'UTILS:' ${UTILS} @echo @echo '== Wiki documentation ==' @echo 'WIKI_DOCS:' ${WIKI_DOCS} @echo @echo '== Others ==' @echo 'TIDY_JUNK:' ${TIDY_JUNK} @echo 'CLEAN_JUNK:' ${CLEAN_JUNK} # +< # '''linkages''': Make the linkages file ``tmp/linkages.tmp.py`` so # that it can be inspected during debugging. # >+ linkages : ${LINKAGES} # +< # '''tmpfiles''': Make intermediate ``.swc`` files for inspection. # >+ tmpfiles : ${PAGES_TMP} #---------------------------------------------------------------------- # Wiki. #---------------------------------------------------------------------- # +<'''docs''': Make wiki-formatted project documentation.>+ docs : ${WIKI_DOCS} docs/%.wiki : % ${PYTHON} util/docs.py $< > $@ # +<'''syllabus''': Make a wiki-formatted syllabus.>+ syllabus : ${LINKAGES} @${PYTHON} util/wiki.py -s ${LINKAGES} #---------------------------------------------------------------------- # Housekeeping. #---------------------------------------------------------------------- # +<'''tidy''': Clean up byproducts of build.>+ tidy : @rm -rf ${TIDY_JUNK} # +<'''clean''': Delete everything made by the build.>+ clean : @rm -rf ${CLEAN_JUNK} # +< # '''count''': Count the number of words in the source files (roughly). # >+ count : @echo 'source lines:' `cat ${INC_SRC} | wc -l` @${PYTHON} util/count.py ${PAGES_SRC} # +<'''words''': produce a concordance of the lecture notes.>+ words : @${PYTHON} util/count.py -t ${PAGES_SRC} # +<'''properties''': show SVN properties of all source files.>+ properties : @svn propget svn:keywords ${ALL_SRC} $(wildcard util/*.py) # +< # '''scdtd''': Reverse-engineer the DTD of the .swc files. # >+ scdtd : @python util/revdtd.py -c ${PAGES_SRC} @echo @python util/revdtd.py -p ${PAGES_SRC} @echo @python util/revdtd.py -a ${PAGES_SRC} # +< # '''entities''': Create a page showing all of the character entities. # >+ entities : @mkdir -p ./tmp @${PYTHON} util/fixentities.py -t ./swc.dtd > ./tmp/entities.html # +< # '''tickets''': list tickets from database in wiki format. This will # only work when run on the Trac host machine. # >+ tickets : @${SQLITE} -separator ' ' ${DB_PATH} "select id, component, summary from ticket where status in ('new', 'assigned', 'reopened') order by id" \ | ${PYTHON} util/wiki.py -t