summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorMarkus Heiser <markus.heiser@darmarIT.de>2019-12-24 17:45:13 +0100
committerGitHub <noreply@github.com>2019-12-24 17:45:13 +0100
commitecb054a7a058a1f62a536e5cac88eed8926b107d (patch)
tree925594876f18580732d2c8a438ff8f3bea8d9092 /utils
parentcc8d4b958e274eb9e154db5c319d2e50da561d61 (diff)
parent5a0a66e9bc34af2b6404231efc7cf02f389bdfcb (diff)
Merge branch 'master' into patch-1
Diffstat (limited to 'utils')
-rw-r--r--utils/makefile.include128
-rw-r--r--utils/makefile.python290
-rw-r--r--utils/makefile.sphinx215
3 files changed, 633 insertions, 0 deletions
diff --git a/utils/makefile.include b/utils/makefile.include
new file mode 100644
index 000000000..716889c02
--- /dev/null
+++ b/utils/makefile.include
@@ -0,0 +1,128 @@
+# -*- coding: utf-8; mode: makefile-gmake -*-
+
+make-help:
+ @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build'
+ @echo ' make V=2 [targets] 2 => give reason for rebuild of target'
+
+quiet_cmd_common_clean = CLEAN $@
+ cmd_common_clean = \
+ rm -rf tests/build ;\
+ find . -name '*.orig' -exec rm -f {} + ;\
+ find . -name '*.rej' -exec rm -f {} + ;\
+ find . -name '*~' -exec rm -f {} + ;\
+ find . -name '*.bak' -exec rm -f {} + ;\
+
+FMT = cat
+ifeq ($(shell which fmt >/dev/null 2>&1; echo $$?), 0)
+FMT = fmt
+endif
+
+# MS-Windows
+#
+# For a minimal *make-environment*, I'am using the gnu-tools from:
+#
+# - GNU MCU Eclipse Windows Build Tools, which brings 'make', 'rm' etc.
+# https://github.com/gnu-mcu-eclipse/windows-build-tools/releases
+#
+# - git for Windows, which brings 'find', 'grep' etc.
+# https://git-scm.com/download/win
+
+
+# normpath
+#
+# System-dependent normalization of the path name
+#
+# usage: $(call normpath,/path/to/file)
+
+normpath = $1
+ifeq ($(OS),Windows_NT)
+ normpath = $(subst /,\,$1)
+endif
+
+
+# stolen from linux/Makefile
+#
+
+ifeq ("$(origin V)", "command line")
+ KBUILD_VERBOSE = $(V)
+endif
+ifndef KBUILD_VERBOSE
+ KBUILD_VERBOSE = 0
+endif
+
+ifeq ($(KBUILD_VERBOSE),1)
+ quiet =
+ Q =
+else
+ quiet=quiet_
+ Q = @
+endif
+
+# stolen from linux/scripts/Kbuild.include
+#
+
+# Convenient variables
+comma := ,
+quote := "
+#" this comment is only for emacs highlighting
+squote := '
+#' this comment is only for emacs highlighting
+empty :=
+space := $(empty) $(empty)
+space_escape := _-_SPACE_-_
+
+# Find any prerequisites that is newer than target or that does not exist.
+# PHONY targets skipped in both cases.
+any-prereq = $(filter-out $(PHONY),$?) $(filter-out $(PHONY) $(wildcard $^),$^)
+#
+###
+# why - tell why a a target got build
+# enabled by make V=2
+# Output (listed in the order they are checked):
+# (1) - due to target is PHONY
+# (2) - due to target missing
+# (3) - due to: file1.h file2.h
+# (4) - due to command line change
+# (5) - due to missing .cmd file
+# (6) - due to target not in $(targets)
+# (1) PHONY targets are always build
+# (2) No target, so we better build it
+# (3) Prerequisite is newer than target
+# (4) The command line stored in the file named dir/.target.cmd
+# differed from actual command line. This happens when compiler
+# options changes
+# (5) No dir/.target.cmd file (used to store command line)
+# (6) No dir/.target.cmd file and target not listed in $(targets)
+# This is a good hint that there is a bug in the kbuild file
+ifeq ($(KBUILD_VERBOSE),2)
+why = \
+ $(if $(filter $@, $(PHONY)),- due to target is PHONY, \
+ $(if $(wildcard $@), \
+ $(if $(strip $(any-prereq)),- due to: $(any-prereq), \
+ $(if $(arg-check), \
+ $(if $(cmd_$@),- due to command line change, \
+ $(if $(filter $@, $(targets)), \
+ - due to missing .cmd file, \
+ - due to $(notdir $@) not in $$(targets) \
+ ) \
+ ) \
+ ) \
+ ), \
+ - due to target missing \
+ ) \
+ )
+
+echo-why = $(call escsq, $(strip $(why)))
+endif
+#
+###
+# Escape single quote for use in echo statements
+escsq = $(subst $(squote),'\$(squote)',$1)
+#
+# echo command.
+# Short version is used, if $(quiet) equals `quiet_', otherwise full one.
+echo-cmd = $(if $($(quiet)cmd_$(1)),echo '$(call escsq,$($(quiet)cmd_$(1)))$(echo-why)';)
+#
+# printing commands
+cmd = @$(echo-cmd) $(cmd_$(1))
+
diff --git a/utils/makefile.python b/utils/makefile.python
new file mode 100644
index 000000000..4aa9d6b49
--- /dev/null
+++ b/utils/makefile.python
@@ -0,0 +1,290 @@
+# -*- coding: utf-8; mode: makefile-gmake -*-
+
+# list of python packages (folders) or modules (files) of this build
+PYOBJECTS ?=
+
+SITE_PYTHON ?=$(dir $(abspath $(lastword $(MAKEFILE_LIST))))site-python
+export PYTHONPATH := $(SITE_PYTHON):$$PYTHONPATH
+
+# folder where the python distribution takes place
+PYDIST ?= ./py_dist
+# folder where the python intermediate build files take place
+PYBUILD ?= ./py_build
+# python version to use
+PY ?=3
+PYTHON ?= python$(PY)
+PIP ?= pip$(PY)
+PIP_INST ?= --user
+
+# https://www.python.org/dev/peps/pep-0508/#extras
+#PY_SETUP_EXTRAS ?= \[develop,test\]
+PY_SETUP_EXTRAS ?=
+
+PYDEBUG ?= --pdb
+PYLINT_RC ?= .pylintrc
+
+TEST_FOLDER ?= ./tests
+TEST ?= .
+
+VTENV_OPTS = "--no-site-packages"
+PY_ENV = ./local/py$(PY)
+PY_ENV_BIN = $(PY_ENV)/bin
+PY_ENV_ACT = . $(PY_ENV_BIN)/activate
+
+ifeq ($(OS),Windows_NT)
+ PYTHON = python
+ PY_ENV_BIN = $(PY_ENV)/Scripts
+ PY_ENV_ACT = $(PY_ENV_BIN)/activate
+endif
+
+ifeq ($(PYTHON),python)
+ VIRTUALENV = virtualenv
+else
+ VIRTUALENV = virtualenv --python=$(PYTHON)
+endif
+
+ifeq ($(KBUILD_VERBOSE),1)
+ PIP_VERBOSE =
+ VIRTUALENV_VERBOSE =
+else
+ PIP_VERBOSE = "-q"
+ VIRTUALENV_VERBOSE = "-q"
+endif
+
+python-help::
+ @echo 'makefile.python:'
+ @echo ' pyenv | pyenv[un]install'
+ @echo ' build $(PY_ENV) & [un]install python objects'
+ @echo ' targts using pyenv $(PY_ENV):'
+ @echo ' pylint - run pylint *linting*'
+ @echo ' pytest - run *tox* test on python objects'
+ @echo ' pydebug - run tests within a PDB debug session'
+ @echo ' pybuild - build python packages'
+ @echo ' pyclean - clean intermediate python objects'
+ @echo ' targets using system users environment:'
+ @echo ' py[un]install - [un]install python objects in editable mode'
+ @echo ' upload-pypi - upload $(PYDIST)/* files to PyPi'
+ @echo 'options:'
+ @echo ' make PY=2 [targets] => to eval targets with python 2 ($(PY))'
+ @echo ' make PIP_INST= => to set/unset pip install options ($(PIP_INST))'
+ @echo ' make TEST=. => choose test from $(TEST_FOLDER) (default "." runs all)'
+ @echo ' make DEBUG= => target "debug": do not invoke PDB on errors'
+ @echo ' make PY_SETUP_EXTRAS => also install extras_require from setup.py \[develop,test\]'
+ @echo ' when using target "pydebug", set breakpoints within py-source by adding::'
+ @echo ' DEBUG()'
+
+# ------------------------------------------------------------------------------
+# OS requirements
+# ------------------------------------------------------------------------------
+
+PHONY += msg-python-exe python-exe
+msg-python-exe:
+ @echo "\n $(PYTHON) is required\n\n\
+ Make sure you have $(PYTHON) installed, grab it from\n\
+ https://www.python.org or install it from your package\n\
+ manager. On debian based OS these requirements are\n\
+ installed by::\n\n\
+ sudo -H apt-get install $(PYTHON)\n" | $(FMT)
+
+ifeq ($(shell which $(PYTHON) >/dev/null 2>&1; echo $$?), 1)
+python-exe: msg-python-exe
+ $(error The '$(PYTHON)' command was not found)
+else
+python-exe:
+ @:
+endif
+
+msg-pip-exe:
+ @echo "\n $(PIP) is required\n\n\
+ Make sure you have updated pip installed, grab it from\n\
+ https://pip.pypa.io or install it from your package\n\
+ manager. On debian based OS these requirements are\n\
+ installed by::\n\n\
+ sudo -H apt-get install python$(PY)-pip\n" | $(FMT)
+
+ifeq ($(shell which $(PIP) >/dev/null 2>&1; echo $$?), 1)
+pip-exe: msg-pip-exe
+ $(error The '$(PIP)' command was not found)
+else
+pip-exe:
+ @:
+endif
+
+PHONY += msg-virtualenv-exe virtualenv-exe
+msg-virtualenv-exe:
+ @echo "\n virtualenv is required\n\n\
+ Make sure you have an updated virtualenv installed, grab it from\n\
+ https://virtualenv.pypa.io/en/stable/installation/ or install it\n\
+ via pip by::\n\n\
+ pip install --user https://github.com/pypa/virtualenv/tarball/master\n" | $(FMT)
+
+ifeq ($(shell which virtualenv >/dev/null 2>&1; echo $$?), 1)
+virtualenv-exe: msg-virtualenv-exe
+ $(error The 'virtualenv' command was not found)
+else
+virtualenv-exe:
+ @:
+endif
+
+# ------------------------------------------------------------------------------
+# commands
+# ------------------------------------------------------------------------------
+
+# $2 path to folder with setup.py, this uses pip from the OS
+quiet_cmd_pyinstall = INSTALL $2
+ cmd_pyinstall = $(PIP) $(PIP_VERBOSE) install $(PIP_INST) -e $2$(PY_SETUP_EXTRAS)
+
+# $2 path to folder with setup.py, this uses pip from pyenv (not OS!)
+quiet_cmd_pyenvinstall = PYENV install $2
+ cmd_pyenvinstall = $(PY_ENV_BIN)/pip $(PIP_VERBOSE) install -e $2$(PY_SETUP_EXTRAS)
+
+# Uninstall the package. Since pip does not uninstall the no longer needed
+# depencies (something like autoremove) the depencies remain.
+
+# $2 package name to uninstall, this uses pip from the OS.
+quiet_cmd_pyuninstall = UNINSTALL $2
+ cmd_pyuninstall = $(PIP) $(PIP_VERBOSE) uninstall --yes $2
+
+# $2 path to folder with setup.py, this uses pip from pyenv (not OS!)
+quiet_cmd_pyenvuninstall = PYENV uninstall $2
+ cmd_pyenvuninstall = $(PY_ENV_BIN)/pip $(PIP_VERBOSE) uninstall --yes $2
+
+# $2 path to folder where virtualenv take place
+quiet_cmd_virtualenv = PYENV usage: $ source ./$@/bin/activate
+ cmd_virtualenv = \
+ if [ ! -d "./$(PY_ENV)" ];then \
+ $(VIRTUALENV) $(VIRTUALENV_VERBOSE) $(VTENV_OPTS) $2; \
+ else \
+ echo "PYENV using virtualenv from $2"; \
+ fi
+
+# $2 path to lint
+quiet_cmd_pylint = LINT $@
+ cmd_pylint = $(PY_ENV_BIN)/pylint --rcfile $(PYLINT_RC) $2
+
+quiet_cmd_pytest = TEST $@
+ cmd_pytest = $(PY_ENV_BIN)/tox -vv
+
+# setuptools, pip, easy_install its a mess full of cracks, a documentation hell
+# and broken by design ... all sucks, I really, really hate all this ... aaargh!
+#
+# About python packaging see `Python Packaging Authority`_. Most of the names
+# here are mapped to ``setup(<name1>=..., <name2>=...)`` arguments in
+# ``setup.py``. See `Packaging and distributing projects`_ about ``setup(...)``
+# arguments. If this is all new for you, start with `PyPI Quick and Dirty`_.
+#
+# Further read:
+#
+# - pythonwheels_
+# - setuptools_
+# - packaging_
+# - sdist_
+# - installing_
+#
+# .. _`Python Packaging Authority`: https://www.pypa.io
+# .. _`Packaging and distributing projects`: https://packaging.python.org/guides/distributing-packages-using-setuptools/
+# .. _`PyPI Quick and Dirty`: https://hynek.me/articles/sharing-your-labor-of-love-pypi-quick-and-dirty/
+# .. _pythonwheels: https://pythonwheels.com/
+# .. _setuptools: https://setuptools.readthedocs.io/en/latest/setuptools.html
+# .. _packaging: https://packaging.python.org/guides/distributing-packages-using-setuptools/#packaging-and-distributing-projects
+# .. _sdist: https://packaging.python.org/guides/distributing-packages-using-setuptools/#source-distributions
+# .. _bdist_wheel: https://packaging.python.org/guides/distributing-packages-using-setuptools/#pure-python-wheels
+# .. _installing: https://packaging.python.org/tutorials/installing-packages/
+#
+quiet_cmd_pybuild = BUILD $@
+ cmd_pybuild = $(PY_ENV_BIN)/$(PYTHON) setup.py \
+ sdist -d $(PYDIST) \
+ bdist_wheel --bdist-dir $(PYBUILD) -d $(PYDIST)
+
+quiet_cmd_pyclean = CLEAN $@
+# remove 'build' folder since bdist_wheel does not care the --bdist-dir
+ cmd_pyclean = \
+ rm -rf $(PYDIST) $(PYBUILD) ./local ./.tox *.egg-info ;\
+ find . -name '*.pyc' -exec rm -f {} + ;\
+ find . -name '*.pyo' -exec rm -f {} + ;\
+ find . -name __pycache__ -exec rm -rf {} +
+
+# ------------------------------------------------------------------------------
+# targets
+# ------------------------------------------------------------------------------
+
+# for installation use the pip from the OS!
+PHONY += pyinstall
+pyinstall: pip-exe
+ $(call cmd,pyinstall,.)
+
+PHONY += pyuninstall
+pyuninstall: pip-exe
+ $(call cmd,pyuninstall,$(PYOBJECTS))
+
+# for installation use the pip from PY_ENV (not the OS)!
+PHONY += pyenvinstall
+pyenvinstall: $(PY_ENV)
+ $(call cmd,pyenvinstall,.)
+
+PHONY += pyenvuninstall
+pyenvuninstall: $(PY_ENV)
+ $(call cmd,pyenvuninstall,$(PYOBJECTS))
+
+PHONY += pyclean
+pyclean:
+ $(call cmd,pyclean)
+
+# to build *local* environment, python and virtualenv from the OS is needed!
+pyenv: $(PY_ENV)
+$(PY_ENV): virtualenv-exe python-exe
+ $(call cmd,virtualenv,$(PY_ENV))
+ @$(PY_ENV_BIN)/pip install $(PIP_VERBOSE) -r requirements.txt
+
+PHONY += pylint-exe
+pylint-exe: $(PY_ENV)
+ @$(PY_ENV_BIN)/pip $(PIP_VERBOSE) install pylint
+
+PHONY += pylint
+pylint: pylint-exe
+ $(call cmd,pylint,$(PYOBJECTS))
+
+PHONY += pybuild
+pybuild: $(PY_ENV)
+ $(call cmd,pybuild)
+
+PHONY += pytest
+pytest: $(PY_ENV)
+ $(call cmd,pytest)
+
+PHONY += pydebug
+# set breakpoint with:
+# DEBUG()
+# e.g. to run tests in debug mode in emacs use:
+# 'M-x pdb' ... 'make pydebug'
+pydebug: $(PY_ENV)
+ DEBUG=$(DEBUG) $(PY_ENV_BIN)/pytest $(DEBUG) -v $(TEST_FOLDER)/$(TEST)
+
+# install / uninstall python objects into virtualenv (PYENV)
+pyenv-install: $(PY_ENV)
+ @$(PY_ENV_BIN)/pip $(PIP_VERBOSE) install -e .
+ @echo "ACTIVATE $(call normpath,$(PY_ENV_ACT)) "
+
+pyenv-uninstall: $(PY_ENV)
+ @$(PY_ENV_BIN)/pip $(PIP_VERBOSE) uninstall --yes .
+
+# runs python interpreter from ./local/py<N>/bin/python
+pyenv-python: pyenv-install
+ cd ./local; ../$(PY_ENV_BIN)/python -i
+
+# With 'dependency_links=' setuptools supports dependencies on packages hosted
+# on other reposetories then PyPi, see "Packages Not On PyPI" [1]. The big
+# drawback is, due to security reasons (I don't know where the security gate on
+# PyPi is), this feature is not supported by pip [2]. Thats why an upload to
+# PyPi is required and since uploads via setuptools is not recommended, we have
+# to imstall / use twine ... its really a mess.
+#
+# [1] http://python-packaging.readthedocs.io/en/latest/dependencies.html#packages-not-on-pypi
+# [2] https://github.com/pypa/pip/pull/1519
+
+# https://github.com/pypa/twine
+PHONY += upload-pypi
+upload-pypi: pyclean pybuild
+ @$(PY_ENV_BIN)/twine upload $(PYDIST)/*
+
+.PHONY: $(PHONY)
diff --git a/utils/makefile.sphinx b/utils/makefile.sphinx
new file mode 100644
index 000000000..5cbc5ebdd
--- /dev/null
+++ b/utils/makefile.sphinx
@@ -0,0 +1,215 @@
+# -*- coding: utf-8; mode: makefile-gmake -*-
+
+# You can set these variables from the command line.
+SPHINXOPTS ?=
+SPHINXBUILD ?= $(PY_ENV_BIN)/sphinx-build
+SPHINX_CONF ?= conf.py
+
+DOCS_FOLDER ?= docs
+DOCS_BUILD ?= build/docs
+DOCS_DIST ?= dist/docs
+GH_PAGES ?= gh-pages
+
+BOOKS_FOLDER ?= docs
+BOOKS_DIST ?= dist/books
+
+ifeq ($(KBUILD_VERBOSE),1)
+ SPHINX_VERBOSE = "-v"
+else
+ SPHINX_VERBOSE =
+endif
+
+## SPHINXVERS variable
+## ===================
+##
+## .. _requirement-specifiers: https://pip.pypa.io/en/stable/reference/pip_install/#requirement-specifiers
+##
+## Sphinx version to use, when building documentation. Set this when calling
+## build target. The default value is empty (install latest), to select a
+## specific version use a requirement-specifiers_. E.g. to build your target
+## 'doc' with a select sphinx-doc_ version 1.7.9::
+##
+## make SPHINXVERS='==1.7.9' docs
+##
+## To build with latest 1.7::
+##
+## make SPHINXVERS='>=1.7,<1.8' docs
+##
+SPHINXVERS ?=
+
+docs-help:
+ @echo 'makefile.sphinx:'
+ @echo ' docs-clean - clean intermediate doc objects'
+ @echo ' $(GH_PAGES) - create & upload github pages'
+ @echo ' sphinx-pdf - run sphinx latex & pdf targets'
+ echo ''
+ @echo ' books/{name}.html : build only the HTML of document {name}'
+ @echo ' valid values for books/{name}.html are:'
+ @echo ' $(BOOKS_HTML)' | $(FMT)
+ @echo ' books/{name}.pdf : build only the PDF of document {name}'
+ @echo ' valid values for books/{name}.pdf are:'
+ @echo ' $(BOOKS_PDF) ' | $(FMT)
+
+# ------------------------------------------------------------------------------
+# requirements
+# ------------------------------------------------------------------------------
+
+sphinx-doc: $(PY_ENV)
+ @echo "PYENV installing Sphinx$(SPHINXVERS)"
+ $(Q)$(PY_ENV_BIN)/pip install $(PIP_VERBOSE) 'Sphinx$(SPHINXVERS)'
+
+sphinx-live: $(PY_ENV)
+ @echo "PYENV installing Sphinx$(SPHINXVERS)"
+ $(Q)$(PY_ENV_BIN)/pip install $(PIP_VERBOSE) 'Sphinx$(SPHINXVERS)' sphinx-autobuild
+
+
+PHONY += msg-texlive texlive
+
+ifeq ($(shell which xelatex >/dev/null 2>&1; echo $$?), 1)
+texlive: msg-TeXLive
+ $(error The 'xelatex' command was not found)
+else
+texlive:
+ @:
+endif
+
+msg-texlive:
+ $(Q)echo "\n\
+The TeX/PDF output and the *math* extension require TexLive and latexmk:\n\n\
+ Make sure you have a updated TeXLive with XeTeX engine installed, grab it\n\
+ it from https://www.tug.org/texlive or install it from your package manager.\n\n\
+ Install latexmk from your package manager or visit https://ctan.org/pkg/latexmk\n\n\
+ Sphinx-doc produce (Xe)LaTeX files which might use additional TeX-packages\n\
+ and fonts. To process these LaTeX files, a TexLive installation with the\n\
+ additional packages is required. On debian based OS these requirements\n\
+ are installed by::\n\n\
+ sudo -H apt-get install\n\
+ latexmk\n\
+ texlive-base texlive-xetex texlive-latex-recommended\n\
+ texlive-extra-utils dvipng ttf-dejavu\n"
+
+# ------------------------------------------------------------------------------
+# commands
+# ------------------------------------------------------------------------------
+
+# $2 sphinx builder e.g. "html"
+# $3 path where configuration file (conf.py) is located
+# $4 sourcedir
+# $5 dest subfolder e.g. "man" for man pages at $(DOCS_DIST)/man
+
+quiet_cmd_sphinx = SPHINX $@ --> file://$(abspath $(DOCS_DIST)/$5)
+ cmd_sphinx = SPHINX_CONF=$(abspath $4/$(SPHINX_CONF))\
+ $(SPHINXBUILD) $(SPHINX_VERBOSE) $(SPHINXOPTS)\
+ -b $2 -c $3 -d $(DOCS_BUILD)/.doctrees $4 $(DOCS_DIST)/$5
+
+quiet_cmd_sphinx_autobuild = SPHINX $@ --> file://$(abspath $(DOCS_DIST)/$5)
+ cmd_sphinx_autobuild = PATH="$(PY_ENV_BIN):$(PATH)" $(PY_ENV_BIN)/sphinx-autobuild $(SPHINX_VERBOSE) --poll -B --host 0.0.0.0 --port 8080 $(SPHINXOPTS)\
+ -b $2 -c $3 -d $(DOCS_BUILD)/.doctrees $4 $(DOCS_DIST)/$5
+
+quiet_cmd_sphinx_clean = CLEAN $@
+ cmd_sphinx_clean = rm -rf $(DOCS_BUILD) $(DOCS_DIST) $(GH_PAGES)/* $(GH_PAGES)/.buildinfo
+
+# ------------------------------------------------------------------------------
+# targets
+# ------------------------------------------------------------------------------
+
+# build PDF of whole documentation in: $(DOCS_DIST)/pdf
+
+PHONY += sphinx-pdf
+sphinx-pdf: sphinx-latex
+ $(Q)cd $(DOCS_BUILD)/latex/; make all-pdf
+ $(Q)mkdir -p $(DOCS_DIST)/pdf
+ $(Q)cp $(DOCS_BUILD)/latex/*.pdf $(DOCS_DIST)/pdf
+ @echo "SPHINX *.pdf --> file://$(abspath $(DOCS_DIST)/pdf)"
+
+PHONY += sphinx-latex
+sphinx-latex: texlive sphinx-doc
+ $(SPHINXBUILD) $(SPHINX_VERBOSE) $(SPHINXOPTS)\
+ -b latex \
+ -c $(DOCS_FOLDER) \
+ -d $(DOCS_BUILD)/.doctrees \
+ $(DOCS_FOLDER) \
+ $(DOCS_BUILD)/latex
+
+# Sphinx projects, we call them *books* (what is more common). Books are
+# folders under $(BOOKS_FOLDER) containing a conf.py file. The HTML output goes
+# to folder $(BOOKS_DIST)/<name> while PDF is placed (BOOKS_DIST)/<name>/pdf
+
+BOOKS=$(patsubst $(BOOKS_FOLDER)/%/conf.py,books/%,$(wildcard $(BOOKS_FOLDER)/*/conf.py))
+
+# fine grained targets
+BOOKS_HTML = $(patsubst %,%.html,$(BOOKS))
+BOOKS_CLEAN = $(patsubst %,%.clean,$(BOOKS))
+BOOKS_LATEX = $(patsubst %,%.latex,$(BOOKS))
+BOOKS_PDF = $(patsubst %,%.pdf,$(BOOKS))
+BOOKS_LIVE = $(patsubst %,%.live,$(BOOKS))
+
+$(BOOKS_DIST):
+ mkdir -p $(BOOKS_DIST)
+
+PHONY += $(BOOKS_HTML)
+$(BOOKS_HTML): sphinx-doc | $(BOOKS_DIST)
+ SPHINX_CONF=$(patsubst books/%.html,%,$@)/conf.py \
+ $(SPHINXBUILD) $(SPHINX_VERBOSE) $(SPHINXOPTS)\
+ -b html \
+ -c $(DOCS_FOLDER) \
+ -d $(DOCS_BUILD)/books/$(patsubst books/%.html,%,$@)/.doctrees \
+ $(patsubst books/%.html,%,$@) \
+ $(BOOKS_DIST)/$(patsubst books/%.html,%,$@)
+ @echo "SPHINX $@ --> file://$(abspath $(BOOKS_DIST)/$(patsubst books/%.html,%,$@))"
+
+PHONY += $(BOOKS_HTML)
+$(BOOKS_LIVE): sphinx-live | $(BOOKS_DIST)
+ PATH="$(PY_ENV_BIN):$(PATH)" \
+ SPHINX_CONF=$(patsubst books/%.live,%,$@)/conf.py \
+ $(PY_ENV_BIN)/sphinx-autobuild --poll -B --host 0.0.0.0 --port 8080 $(SPHINX_VERBOSE) $(SPHINXOPTS)\
+ -b html \
+ -c $(DOCS_FOLDER) \
+ -d $(DOCS_BUILD)/books/$(patsubst books/%.live,%,$@)/.doctrees \
+ $(patsubst books/%.live,%,$@) \
+ $(BOOKS_DIST)/$(patsubst books/%.live,%,$@)
+
+$(BOOKS_PDF): %.pdf : %.latex
+ $(Q)cd $(DOCS_BUILD)/latex/$(patsubst books/%.pdf,%,$@); make all-pdf
+ $(Q)mkdir -p $(BOOKS_DIST)/$(patsubst books/%.pdf,%,$@)/pdf
+ $(Q)cp -v $(DOCS_BUILD)/latex/$(patsubst books/%.pdf,%,$@)/*.pdf $(BOOKS_DIST)/$(patsubst books/%.pdf,%,$@)/pdf
+ @echo "SPHINX $@ --> file://$(abspath $(BOOKS_DIST)/$(patsubst books/%.pdf,%,$@))/pdf"
+
+PHONY += $(BOOKS_LATEX)
+$(BOOKS_LATEX): sphinx-doc | $(BOOKS_DIST)
+ SPHINX_CONF=$(patsubst books/%.latex,%,$@)/conf.py \
+ $(SPHINXBUILD) $(SPHINX_VERBOSE) $(SPHINXOPTS)\
+ -b latex \
+ -c $(DOCS_FOLDER) \
+ -d $(DOCS_BUILD)/books/$(patsubst books/%.latex,%,$@)/.doctrees \
+ $(patsubst books/%.latex,%,$@) \
+ $(DOCS_BUILD)/latex/$(patsubst books/%.latex,%,$@)
+ @echo "SPHINX $@ --> file://$(abspath $(DOCS_BUILD)/latex/$(patsubst books/%.latex,%,$@))"
+
+$(BOOKS_CLEAN):
+ $(Q)rm -rf $(BOOKS_DIST)/$(patsubst books/%.clean,%,$@) \
+ $(DOCS_BUILD)/books/$(patsubst books/%.clean,%,$@) \
+ $(DOCS_BUILD)/latex/$(patsubst books/%.clean,%,$@)
+
+# github pages
+
+PHONY += $(GH_PAGES)
+$(GH_PAGES)::
+ $(MAKE) docs
+ [ -d "gh-pages/.git" ] || git clone $(GIT_URL) gh-pages
+ -cd $(GH_PAGES); git checkout gh-pages >/dev/null
+ -cd $(GH_PAGES); ls -A | grep -v '.git$$' | xargs rm -rf
+ cp -r $(DOCS_DIST)/* $(GH_PAGES)/
+ touch $(GH_PAGES)/.nojekyll
+ echo "<html><head><META http-equiv='refresh' content='0;URL=index.html'></head></html>" > $(GH_PAGES)/404.html
+ cd $(GH_PAGES);\
+ git add --all . ;\
+ git commit -m "gh-pages: updated" ;\
+ git push origin gh-pages
+
+
+PHONY += docs-clean
+docs-clean: $(BOOKS_CLEAN)
+ $(call cmd,sphinx_clean)
+
+.PHONY: $(PHONY)