2 Makefile Template
tengel edited this page 2024-03-20 11:55:04 -05:00

Makefile Template

General

General boilerplate with a few common example variables and targets

# These can be overridden on the commandline
#  Example: make DESTDIR=${HOME}/.local PREFIX=/ install

PREFIX     ?= /usr/local
BINPREFIX  ?= $(PREFIX)/bin
SBINPREFIX ?= $(PREFIX)/sbin
LIBPREFIX  ?= $(PREFIX)/lib
MANPREFIX  ?= $(PREFIX)/share/man
DOCPREFIX  ?= $(PREFIX)/share/doc
ETCPREFIX  ?= /etc
VARPREFIX  ?= /var
DESTDIR    ?=

# Static variables

pkg_name   := "mything"
bin_name   := "mt"

# Use a dynamic file listing

doc_files  := $(shell ls docs/*.md)

# Targets

all:
install: install-main install-doc install-man
uninstall: uninstall-main uninstall-doc uninstall-man

install-main:
	@install -d -m 0755 "$(DESTDIR)$(BINPREFIX)"
	@install -D -p -m 0755 src/${bin_name} "$(DESTDIR)$(BINPREFIX)/${bin_name}"

install-doc:
	@install -d -m 0755 "$(DESTDIR)$(DOCPREFIX)/${pkg_name}"
	@install -p -m 0644 ${doc_files} "$(DESTDIR)$(DOCPREFIX)/${pkg_name}/"

install-man:
	@install -d -m 0755 "$(DESTDIR)$(MANPREFIX)/man8"
	@install -p -m 0644 "man/${bin_name}.8" "$(DESTDIR)$(MANPREFIX)/man8/"

uninstall-main:
	@rm -f "$(DESTDIR)$(BINPREFIX)/${bin_name}"

uninstall-doc:
	@rm -rf "$(DESTDIR)$(DOCPREFIX)/${pkg_name}"

uninstall-man:
	@rm -f "$(DESTDIR)$(MANPREFIX)/man8/${bin_name}.8"

builddir:
	@mkdir -p "./build"

tarball: builddir
	@rm -f "./build/${pkg_name}.tar.gz"
	@tar -zcf "./build/${pkg_name}.tar.gz" src/

test:
	@cd tests; ./testme.sh

shellcheck:
	$(shell shellcheck src/*.sh)

clean:
	@rm -rf ./build

# Make expects to "make files"; .PHONY means to use the internal target with
# that name instead of an external file which might happen to have the same
# name as a target

.PHONY: clean install uninstall test

External Data

Get the version from a comment header with ## Version: 0.0.1 format

version   := $(shell grep '^\#\# Version:' src/myfile.sh | cut -d' ' -f3)

Get the version from a source file with _VERSION="0.0.1" format (shell)

leftparen := (
version   := $(shell eval $$(grep ^_VERSION= src/myfile.sh); echo $$_VERSION| awk -F' \\$(leftparen)' '{print $$1}' | sed "s/ /-/g" )

Get the version from a source file with _version_ = "0.0.1" format (python)

version   := $(shell grep ^__version__ src/version.py | awk '{print $$3}')

External Programs

Examples of using ifdef and ifeq only if an external program is installed

YLINT  := $(shell command -v yamllint 2>/dev/null)

yamllint1:
ifndef YLINT
	$(error "Please install yamllint first.")
endif
	$(shell yamllint src/*.yaml)

yamllint2:
ifeq ($(strip $(YLINT)),)
	$(error "Please install yamllint first.")
endif
	$(shell yamllint src/*.yaml)

Examples of common Python tasks

# If the user passes in PYTHON=... use that, otherwise look for 'python'
# then look for 'python3' in the $PATH, if still not found use 'python'

PYTHON  ?= $(shell command -v python 2>/dev/null)
ifeq ($(strip $(PYTHON)),)
PYTHON  := $(shell command -v python3 2>/dev/null)
endif
ifeq ($(strip $(PYTHON)),)
PYTHON   = python
endif

# Based on which python we found, set up variables related to it

ifneq (,$(findstring python3,$(PYTHON)))
PYSHORT  = python3
PYRPMS   = python3-virtualenv python3-setuptools python3-pyyaml
else
PYSHORT  = python
PYRPMS   = python-virtualenv python-setuptools PyYAML
endif

pyvenv:
	@sudo yum -y -q install $(PYRPMS) 1>/dev/null
	@virtualenv -q --system-site-packages --no-pip --no-setuptools pyvenv

install-python: install-main
    sed -i "1s/python/${PYSHORT}/" "$(DESTDIR)$(BINPREFIX)/${bin_name}"