1 | # meli - Makefile |
2 | # |
3 | # Copyright 2017-2020 Manos Pitsidianakis |
4 | # |
5 | # This file is part of meli. |
6 | # |
7 | # meli is free software: you can redistribute it and/or modify |
8 | # it under the terms of the GNU General Public License as published by |
9 | # the Free Software Foundation, either version 3 of the License, or |
10 | # (at your option) any later version. |
11 | # |
12 | # meli is distributed in the hope that it will be useful, |
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | # GNU General Public License for more details. |
16 | # |
17 | # You should have received a copy of the GNU General Public License |
18 | # along with meli. If not, see <http://www.gnu.org/licenses/>. |
19 | .POSIX: |
20 | .SUFFIXES: |
21 | CARGO_TARGET_DIR ?= target |
22 | CARGO_BIN ?= cargo |
23 | TAGREF_BIN ?= tagref |
24 | CARGO_ARGS ?= |
25 | RUSTFLAGS ?= -D warnings -W unreachable-pub -W rust-2021-compatibility |
26 | CARGO_SORT_BIN = cargo-sort |
27 | CARGO_HACK_BIN = cargo-hack |
28 | PRINTF = /usr/bin/printf |
29 | |
30 | # Options |
31 | PREFIX ?= /usr/local |
32 | EXPANDED_PREFIX := `cd ${PREFIX} && pwd -P` |
33 | BINDIR ?= ${EXPANDED_PREFIX}/bin |
34 | MANDIR ?= ${EXPANDED_PREFIX}/share/man |
35 | |
36 | # Installation parameters |
37 | DOCS_SUBDIR ?= meli/docs/ |
38 | MANPAGES ?= meli.1 meli.conf.5 meli-themes.5 meli.7 |
39 | FEATURES != [ -z "$${MELI_FEATURES}" ] && ($(PRINTF) -- '--all-features') || ($(PRINTF) -- '--features %s' "$${MELI_FEATURES}") |
40 | |
41 | MANPATHS != ACCUM="";for m in `manpath 2> /dev/null | tr ':' ' '`; do if [ -d "$${m}" ]; then REAL_PATH=`cd $${m} && pwd` ACCUM="$${ACCUM}:$${REAL_PATH}";fi;done;echo $${ACCUM}'\c' | sed 's/^://' |
42 | VERSION = `grep -m1 version meli/Cargo.toml | head -n1 | cut -d'"' -f 2 | head -n1` |
43 | MIN_RUSTC = `grep -m1 rust-version meli/Cargo.toml | head -n1 | cut -d'"' -f 2 | head -n1` |
44 | GIT_COMMIT = `git show-ref -s --abbrev HEAD` |
45 | DATE = `date -I` |
46 | |
47 | # Output parameters |
48 | BOLD ?= `[ -z $${TERM} ] && echo "" || tput bold` |
49 | UNDERLINE ?= `[ -z $${TERM} ] && echo "" || tput smul` |
50 | ANSI_RESET ?= `[ -z $${TERM} ] && echo "" || tput sgr0` |
51 | CARGO_COLOR ?= `[ -z $${NO_COLOR+x} ] && echo "" || echo "--color=never "` |
52 | RED ?= `[ -z $${NO_COLOR+x} ] && ([ -z $${TERM} ] && echo "" || tput setaf 1) || echo ""` |
53 | GREEN ?= `[ -z $${NO_COLOR+x} ] && ([ -z $${TERM} ] && echo "" || tput setaf 2) || echo ""` |
54 | YELLOW ?= `[ -z $${NO_COLOR+x} ] && ([ -z $${TERM} ] && echo "" || tput setaf 3) || echo ""` |
55 | |
56 | .PHONY: meli |
57 | meli: check-deps |
58 | ${CARGO_BIN} build ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" ${FEATURES} --release --bin meli |
59 | |
60 | .PHONY: help |
61 | help: |
62 | @echo "For a quick start, build and install locally:\n\n${BOLD}${GREEN}make PREFIX=~/.local install${ANSI_RESET}\n" |
63 | @echo "Available subcommands:" |
64 | @echo " - ${BOLD}meli${ANSI_RESET} (builds meli with optimizations in \$$CARGO_TARGET_DIR)" |
65 | @echo " - ${BOLD}install${ANSI_RESET} (installs binary in \$$BINDIR and documentation to \$$MANDIR)" |
66 | @echo " - ${BOLD}uninstall${ANSI_RESET}" |
67 | @echo "\nSecondary subcommands:" |
68 | @echo " - ${BOLD}clean${ANSI_RESET} (cleans build artifacts)" |
69 | @echo " - ${BOLD}check-deps${ANSI_RESET} (checks dependencies)" |
70 | @echo " - ${BOLD}install-bin${ANSI_RESET} (installs binary to \$$BINDIR)" |
71 | @echo " - ${BOLD}install-doc${ANSI_RESET} (installs manpages to \$$MANDIR)" |
72 | @echo " - ${BOLD}help${ANSI_RESET} (prints this information)" |
73 | |
74 | @echo " - ${BOLD}dist${ANSI_RESET} (creates release tarball named meli-"${VERSION}".tar.gz in this directory)" |
75 | @echo " - ${BOLD}deb-dist${ANSI_RESET} (builds debian package in the parent directory)" |
76 | @echo " - ${BOLD}distclean${ANSI_RESET} (cleans distribution build artifacts)" |
77 | @echo " - ${BOLD}build-rustdoc${ANSI_RESET} (builds rustdoc documentation for all packages in \$$CARGO_TARGET_DIR)" |
78 | @echo "\nENVIRONMENT variables of interest:" |
79 | @$(PRINTF) "* MELI_FEATURES " |
80 | @[ -z $${MELI_FEATURES+x} ] && echo "unset" || echo "= ${UNDERLINE}"$${MELI_FEATURES}${ANSI_RESET} |
81 | @$(PRINTF) "* PREFIX " |
82 | @[ -z ${EXPANDED_PREFIX} ] && echo "unset" || echo "= ${UNDERLINE}"${EXPANDED_PREFIX}${ANSI_RESET} |
83 | @$(PRINTF) "* BINDIR = %s\n" "${UNDERLINE}${BINDIR}${ANSI_RESET}" |
84 | @$(PRINTF) "* MANDIR " |
85 | @[ -z ${MANDIR} ] && echo "unset" || echo "= ${UNDERLINE}"${MANDIR}${ANSI_RESET} |
86 | @$(PRINTF) "* MANPATH = " |
87 | @[ $${MANPATH+x} ] && echo ${UNDERLINE}$${MANPATH}${ANSI_RESET} || echo "unset" |
88 | @echo "* (cleaned) output of manpath(1) = ${UNDERLINE}${MANPATHS}${ANSI_RESET}" |
89 | @$(PRINTF) "* NO_MAN " |
90 | @[ $${NO_MAN+x} ] && echo "set" || echo "unset" |
91 | @$(PRINTF) "* NO_COLOR " |
92 | @[ $${NO_COLOR+x} ] && echo "set" || echo "unset" |
93 | @echo "* CARGO_BIN = ${UNDERLINE}${CARGO_BIN}${ANSI_RESET}" |
94 | @$(PRINTF) "* CARGO_ARGS " |
95 | @[ -z $${CARGO_ARGS+x} ] && echo "unset" || echo "= ${UNDERLINE}"$${CARGO_ARGS}${ANSI_RESET} |
96 | @$(PRINTF) "* AUTHOR (for deb-dist) " |
97 | @[ -z $${AUTHOR+x} ] && echo "unset" || echo "= ${UNDERLINE}"$${AUTHOR}${ANSI_RESET} |
98 | @echo "* MIN_RUSTC = ${UNDERLINE}${MIN_RUSTC}${ANSI_RESET}" |
99 | @echo "* VERSION = ${UNDERLINE}${VERSION}${ANSI_RESET}" |
100 | @echo "* GIT_COMMIT = ${UNDERLINE}${GIT_COMMIT}${ANSI_RESET}" |
101 | @#@echo "* CARGO_COLOR = ${CARGO_COLOR}" |
102 | |
103 | .PHONY: check |
104 | check: check-tagrefs |
105 | RUSTFLAGS='${RUSTFLAGS}' ${CARGO_BIN} check ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" ${FEATURES} --all --tests --examples --benches --bins |
106 | |
107 | .PHONY: fmt |
108 | fmt: |
109 | $(CARGO_BIN) +nightly fmt --all || $(CARGO_BIN) fmt --all |
110 | @OUT=$$($(CARGO_SORT_BIN) melib -w 2>&1 && $(CARGO_SORT_BIN) meli -w 2>&1) || $(PRINTF) "WARN: %s cargo-sort failed or binary not found in PATH.\n" "$$OUT" |
111 | |
112 | .PHONY: lint |
113 | lint: |
114 | RUSTFLAGS='${RUSTFLAGS}' $(CARGO_BIN) clippy --no-deps ${FEATURES} --all --tests --examples --benches --bins |
115 | |
116 | .PHONY: test |
117 | test: test-docs |
118 | RUSTFLAGS='${RUSTFLAGS}' ${CARGO_BIN} test ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" ${FEATURES} --all --tests --examples --benches --bins |
119 | |
120 | .PHONY: test-docs |
121 | test-docs: |
122 | RUSTFLAGS='${RUSTFLAGS}' ${CARGO_BIN} test ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" ${FEATURES} --all --doc |
123 | |
124 | .PHONY: test-feature-permutations |
125 | test-feature-permutations: |
126 | $(CARGO_HACK_BIN) hack --feature-powerset |
127 | |
128 | .PHONY: check-deps |
129 | check-deps: |
130 | @(if ! echo ${MIN_RUSTC}\\n`${CARGO_BIN} --version | grep ^cargo | cut -d ' ' -f 2` | sort -CV; then echo "rust version >= ${RED}${MIN_RUSTC}${ANSI_RESET} required, found: `which ${CARGO_BIN}` `${CARGO_BIN} --version | cut -d ' ' -f 2`" \ |
131 | "\nYour options:\n - Set CARGO_BIN to a supported version\n - Install a supported version from your distribution's package manager\n - Install a supported version from ${UNDERLINE}https://rustup.rs/${ANSI_RESET}" ; exit 1; fi) |
132 | |
133 | |
134 | .PHONY: clean |
135 | clean: |
136 | -rm -rf ./${CARGO_TARGET_DIR}/ |
137 | |
138 | .PHONY: distclean |
139 | distclean: |
140 | rm -f meli-${VERSION}.tar.gz |
141 | rm -rf .pc # rm debian stuff |
142 | |
143 | .PHONY: uninstall |
144 | uninstall: |
145 | rm -f $(DESTDIR)${BINDIR}/meli |
146 | for MANPAGE in ${MANPAGES}; do \ |
147 | SECTION=`echo $${MANPAGE} | rev | cut -d "." -f 1`; \ |
148 | MANPAGEPATH="${DESTDIR}${MANDIR}/man$${SECTION}/$${MANPAGE}.gz"; \ |
149 | rm -f "$${MANAGEPATH}" |
150 | ; done |
151 | |
152 | .PHONY: install-doc |
153 | install-doc: |
154 | @(if [ -z $${NO_MAN+x} ]; then \ |
155 | echo " - ${BOLD}Installing manpages to ${ANSI_RESET}${DESTDIR}${MANDIR}:" ; \ |
156 | for MANPAGE in ${MANPAGES}; do \ |
157 | SECTION=`echo $${MANPAGE} | rev | cut -d "." -f 1`; \ |
158 | mkdir -p $(DESTDIR)${MANDIR}/man$${SECTION} ; \ |
159 | MANPAGEPATH=${DESTDIR}${MANDIR}/man$${SECTION}/$${MANPAGE}.gz; \ |
160 | echo " * installing $${MANPAGE} → ${GREEN}$${MANPAGEPATH}${ANSI_RESET}"; \ |
161 | gzip -n < ${DOCS_SUBDIR}$${MANPAGE} > $${MANPAGEPATH} \ |
162 | ; done ; \ |
163 | (case ":${MANPATHS}:" in \ |
164 | *:${DESTDIR}${MANDIR}:*) echo "\c";; \ |
165 | *) echo "\n${RED}${BOLD}WARNING${ANSI_RESET}: ${UNDERLINE}Path ${DESTDIR}${MANDIR} is not contained in your MANPATH variable or the output of \`manpath\` command.${ANSI_RESET} \`man\` might fail finding the installed manpages. Consider adding it if necessary.\nMANPATH variable / output of \`manpath\`: ${MANPATHS}" ;; \ |
166 | esac) ; \ |
167 | else echo "NO_MAN is defined, so no documentation is going to be installed." ; fi) |
168 | |
169 | .PHONY: install-bin |
170 | install-bin: meli |
171 | mkdir -p $(DESTDIR)${BINDIR} |
172 | @echo " - ${BOLD}Installing binary to ${ANSI_RESET}${GREEN}${DESTDIR}${BINDIR}/meli${ANSI_RESET}" |
173 | @case ":${PATH}:" in \ |
174 | *:${DESTDIR}${BINDIR}:*) echo "\n";; \ |
175 | *) echo "\n${RED}${BOLD}WARNING${ANSI_RESET}: ${UNDERLINE}Path ${DESTDIR}${BINDIR} is not contained in your PATH variable.${ANSI_RESET} Consider adding it if necessary.\nPATH variable: ${PATH}";; \ |
176 | esac |
177 | mkdir -p $(DESTDIR)${BINDIR} |
178 | rm -f $(DESTDIR)${BINDIR}/meli |
179 | cp ./${CARGO_TARGET_DIR}/release/meli $(DESTDIR)${BINDIR}/meli |
180 | chmod 755 $(DESTDIR)${BINDIR}/meli |
181 | |
182 | |
183 | .PHONY: install |
184 | .NOTPARALLEL: yes |
185 | install: meli install-bin install-doc |
186 | @(if [ -z $${NO_MAN+x} ]; then \ |
187 | $(PRINTF) "\n You're ready to go. You might want to read the \"STARTING WITH meli\" section in the manpage (\`man meli\`)" ;\ |
188 | $(PRINTF) "\n or the tutorial in meli(7) (\`man 7 meli\`).\n" ;\ |
189 | fi) |
190 | @$(PRINTF) " - Report bugs in the mailing list or git issue tracker ${UNDERLINE}https://git.meli-email.org${ANSI_RESET}\n" |
191 | @$(PRINTF) " - If you have a specific feature or workflow you want to use, you can post in the mailing list or git issue tracker.\n" |
192 | |
193 | .PHONY: dist |
194 | dist: |
195 | git archive --format=tar.gz --prefix=meli-${VERSION}/ HEAD >meli-${VERSION}.tar.gz |
196 | @echo meli-${VERSION}.tar.gz |
197 | |
198 | AUTHOR ?= grep -m1 authors meli/Cargo.toml | head -n1 | cut -d'"' -f 2 | head -n1 |
199 | .PHONY: deb-dist |
200 | deb-dist: |
201 | @$(PRINTF) "Override AUTHOR environment variable to set package metadata.\n" |
202 | dpkg-buildpackage -b -rfakeroot -us -uc --build-by="${AUTHOR}" --release-by="${AUTHOR}" |
203 | @echo ${BOLD}${GREEN}Generated${ANSI_RESET} ../meli_${VERSION}-1_`dpkg --print-architecture`.deb |
204 | |
205 | .PHONY: build-rustdoc |
206 | build-rustdoc: |
207 | RUSTDOCFLAGS="--crate-version ${VERSION}_${GIT_COMMIT}_${DATE}" ${CARGO_BIN} doc ${CARGO_ARGS} ${CARGO_COLOR}--target-dir="${CARGO_TARGET_DIR}" --all-features --no-deps --workspace --document-private-items --open |
208 | |
209 | .PHONY: check-tagrefs |
210 | check-tagrefs: |
211 | @(if ! command -v "$(TAGREF_BIN)" > /dev/null;\ |
212 | then \ |
213 | $(PRINTF) "Warning: tagref binary not in PATH.\n" 1>&2;\ |
214 | exit;\ |
215 | else \ |
216 | $(TAGREF_BIN);\ |
217 | fi) |
218 | |
219 | .PHONY: test-makefile |
220 | test-makefile: |
221 | @$(PRINTF) "Checking that current version is detected. " |
222 | @([ ! -z "${VERSION}" ] && $(PRINTF) "${GREEN}OK${ANSI_RESET}\n") || $(PRINTF) "${RED}ERROR${ANSI_RESET}\nVERSION env var is empty, check its definition.\n" 1>&2 |
223 | @$(PRINTF) "Checking that 'date -I' works on this platform. " |
224 | @export DATEVAL=$$(printf "%s" ${DATE} | wc -c | tr -d "[:blank:]" 2>&1); ([ "$${DATEVAL}" = "10" ] && $(PRINTF) "${GREEN}OK${ANSI_RESET}\n") || $(PRINTF) "${RED}ERROR${ANSI_RESET}\n'date -I' does not produce a YYYY-MM-DD output on this platform.\n" 1>&2 |
225 | @$(PRINTF) "Checking that the git commit SHA can be detected. " |
226 | @([ ! -z "$(GIT_COMMIT)" ] && $(PRINTF) "${GREEN}OK${ANSI_RESET}\n") || $(PRINTF) "${YELLOW}WARN${ANSI_RESET}\nGIT_COMMIT env var is empty.\n" 1>&2 |
227 | |
228 | # Checking if mdoc changes produce new lint warnings from mandoc(1) compared to HEAD version: |
229 | # |
230 | # example invocation: `mandoc_lint meli.1` |
231 | # |
232 | # with diff(1) |
233 | # ============ |
234 | #function mandoc_lint () { |
235 | #diff <(mandoc -T lint <(git show HEAD:./meli/docs/$1) 2> /dev/null | cut -d':' -f 3-) <(mandoc -T lint ./meli/docs/$1 2> /dev/null | cut -d':' -f 3-) |
236 | #} |
237 | # |
238 | # with sdiff(1) (side by side) |
239 | # ============================ |
240 | # |
241 | #function mandoc_lint () { |
242 | #sdiff <(mandoc -T lint <(git show HEAD:./meli/docs/$1) 2> /dev/null | cut -d':' -f 3-) <(mandoc -T lint ./meli/docs/$1 2> /dev/null | cut -d':' -f 3-) |
243 | #} |
244 | # |
245 | # with delta(1) |
246 | # ============= |
247 | # |
248 | #function mandoc_lint () { |
249 | #delta --side-by-side <(mandoc -T lint <(git show HEAD:./meli/docs/$1) 2> /dev/null | cut -d':' -f 3-) <(mandoc -T lint ./meli/docs/$1 2> /dev/null | cut -d':' -f 3-) |
250 | #} |