~rjarry/aerc-devel

This thread contains a patchset. You're looking at the original emails, but you may wish to use the patch review UI. Review patch
3 3

[RFC PATCH aerc v5] mk: deprecate BSD make in favor of GNU make

Details
Message ID
<20230804214517.87640-2-robin@jarry.cc>
DKIM signature
missing
Download raw message
Patch: +212 -223
Being portable between BSD and GNU make is a nightmare. It restricts
features to a very minimal surface and in turn requires a lot of code
duplication and manual updating of file lists.

Worse, aerc's makefile relies on the shell assignment operator (!=)
which has been supported by BSD make 2.2 since 1997 but GNU make 4.0
since 2013. Unfortunately, MacOS runs GNU make 3.8 which does not have
that feature. Reducing the feature set even more.

Stop that nonsense and remove BSD make compatibility. The majority of
aerc's users either run a GNU Linux distribution or MacOS. For those who
run any *BSD variant, it is easy for them to install GNU make (gmake) if
they don't have it installed already.

Use GNU make constructs to generate build and install rules dynamically
based on source files discovery.

Signed-off-by: Robin Jarry <robin@jarry.cc>
---

Notes:
    v5 (RFC)
    
    * Drop BSD make compatibility. Only support GNU make.
    
    NB: CI will fail on OpenBSD because gmake is not installed and the
    builds command will run with BSD make.

 .builds/openbsd.yml |   8 +-
 CHANGELOG.md        |   5 +
 GNUmakefile         | 200 +++++++++++++++++++++++++++++++++++++++
 Makefile            | 221 +-------------------------------------------
 README.md           |   1 +
 5 files changed, 212 insertions(+), 223 deletions(-)
 create mode 100644 GNUmakefile

diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml
index 811fbf7ab6e4..5ef3d46366d2 100644
--- a/.builds/openbsd.yml
+++ b/.builds/openbsd.yml
@@ -4,6 +4,8 @@ packages:
  - go
  - gnupg
  - scdoc
  - base64
  - gmake
sources:
  - "https://git.sr.ht/~rjarry/aerc"
environment:
@@ -11,8 +13,8 @@ environment:
tasks:
  - build: |
      cd aerc
      make
      gmake
  - install: |
      cd aerc
      make install
      make checkinstall
      gmake install
      gmake checkinstall
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3c7c3764fa25..13f5bc07d070 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -40,6 +40,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
  distro binaries which have the same name as aerc builtin filters (e.g.
  `/usr/bin/colorize`).

### Deprecated

- Aerc can no longer be compiled and installed with BSD make. GNU make must be
  used instead.

## [0.15.2](https://git.sr.ht/~rjarry/aerc/refs/0.15.2) - 2023-05-11

### Fixed
diff --git a/GNUmakefile b/GNUmakefile
new file mode 100644
index 000000000000..6edda0a22cf7
--- /dev/null
+++ b/GNUmakefile
@@ -0,0 +1,200 @@
# variables that can be changed by users
#
VERSION ?= `git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 0.15.2`
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
SHAREDIR ?= $(PREFIX)/share/aerc
LIBEXECDIR ?= $(PREFIX)/libexec/aerc
MANDIR ?= $(PREFIX)/share/man
GO ?= go
GOFLAGS ?= `contrib/goflags.sh`
BUILD_OPTS ?= -trimpath
GO_LDFLAGS :=
GO_LDFLAGS += -X main.Version=$(VERSION)
GO_LDFLAGS += -X main.Flags=$$(echo -- $(GOFLAGS) | base64 | tr -d '\r\n')
GO_LDFLAGS += -X git.sr.ht/~rjarry/aerc/config.shareDir=$(SHAREDIR)
GO_LDFLAGS += -X git.sr.ht/~rjarry/aerc/config.libexecDir=$(LIBEXECDIR)
GO_LDFLAGS += $(GO_EXTRA_LDFLAGS)
CC ?= cc
CFLAGS ?= -O2 -g

# internal variables used for automatic rules generation with macros
gosrc = $(shell find * -type f -name '*.go') go.mod go.sum
man1 = $(subst .scd,,$(notdir $(wildcard doc/*.1.scd)))
man5 = $(subst .scd,,$(notdir $(wildcard doc/*.5.scd)))
man7 = $(subst .scd,,$(notdir $(wildcard doc/*.7.scd)))
docs = $(man1) $(man5) $(man7)
cfilters = $(subst .c,,$(notdir $(wildcard filters/*.c)))
filters = $(filter-out filters/vectors filters/test.sh filters/%.c,$(wildcard filters/*))
gofumpt_tag = v0.5.0

# Dependencies are added to "all" dynamically with macros
.PHONY: all
all: aerc
	@:

aerc: $(gosrc)
	$(GO) build $(BUILD_OPTS) $(GOFLAGS) -ldflags "$(GO_LDFLAGS)" -o aerc

.PHONY: dev
dev:
	rm aerc
	$(MAKE) aerc BUILD_OPTS="-trimpath -race"
	GORACE="log_path=race.log strip_path_prefix=git.sr.ht/~rjarry/aerc/" ./aerc

.PHONY: fmt
fmt:
	$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -w .

linters.so: contrib/linters.go
	$(GO) build -buildmode=plugin -o linters.so contrib/linters.go

.PHONY: lint
lint: linters.so
	@contrib/check-whitespace `git ls-files ':!:filters/vectors'` && \
		echo white space ok.
	@$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -d . | grep ^ \
		&& echo The above files need to be formatted, please run make fmt && exit 1 \
		|| echo all files formatted.
	$(GO) run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2 run \
		$$(echo $(GOFLAGS) | sed s/-tags=/--build-tags=/)

.PHONY: vulncheck
vulncheck:
	$(GO) run golang.org/x/vuln/cmd/govulncheck@latest ./...

.PHONY: tests
tests: $(cfilters)
	$(GO) test $(GOFLAGS) ./...
	filters/test.sh

.PHONY: debug
debug: aerc.debug
	@echo 'Run `./aerc.debug` and use this command in another terminal to attach a debugger:'
	@echo '    dlv attach $$(pidof aerc.debug)'

aerc.debug: $(gosrc)
	$(GO) build $(GOFLAGS) -gcflags=*=-N -gcflags=*=-l -ldflags="$(GO_LDFLAGS)" -o aerc.debug

.PHONY: doc
doc: $(docs)
	@:

.PHONY: clean
clean:
	$(RM) $(docs) aerc $(cfilters)

# Dependencies are added dynamically to the install rule with macros
.PHONY: install
install:
	@:

.PHONY: checkinstall
checkinstall:
	$(DESTDIR)$(BINDIR)/aerc -v
	for m in $(man1); do test -e $(DESTDIR)$(MANDIR)/man1/$$m || exit; done
	for m in $(man5); do test -e $(DESTDIR)$(MANDIR)/man5/$$m || exit; done
	for m in $(man7); do test -e $(DESTDIR)$(MANDIR)/man7/$$m || exit; done

RMDIR_IF_EMPTY:=sh -c '! [ -d $$0 ] || ls -1qA $$0 | grep -q . || rmdir $$0'

.PHONY: uninstall
uninstall:
	$(RM) $(DESTDIR)$(BINDIR)/aerc
	$(RM) $(DESTDIR)$(BINDIR)/carddav-query
	for m in $(man1); do $(RM) $(DESTDIR)$(MANDIR)/man1/$$m; done
	for m in $(man5); do $(RM) $(DESTDIR)$(MANDIR)/man5/$$m; done
	for m in $(man7); do $(RM) $(DESTDIR)$(MANDIR)/man7/$$m; done
	$(RM) -r $(DESTDIR)$(SHAREDIR)
	$(RM) -r $(DESTDIR)$(LIBEXECDIR)
	${RMDIR_IF_EMPTY} $(DESTDIR)$(BINDIR)
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man1
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man5
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man7
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)
	$(RM) $(DESTDIR)$(PREFIX)/share/applications/aerc.desktop
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(PREFIX)/share/applications

.PHONY: gitconfig
gitconfig:
	git config format.subjectPrefix "PATCH aerc"
	git config sendemail.to "~rjarry/aerc-devel@lists.sr.ht"
	@mkdir -p .git/hooks
	@rm -f .git/hooks/sendemail-validate*
	@if grep -q GIT_SENDEMAIL_FILE_COUNTER `git --exec-path`/git-send-email 2>/dev/null; then \
		ln -svf ../../contrib/sendemail-validate .git/hooks/sendemail-validate && \
		git config sendemail.validate true; \
	fi

.PHONY: check-patches
check-patches:
	@contrib/check-patches origin/master..

# Generate build and install rules for one man page
#
# $1: man page name (e.g: aerc.1)
#
define install_man
$1: doc/$1.scd
	scdoc < $$< > $$@

$1_section = $$(subst .,,$$(suffix $1))
$1_install_dir = $$(DESTDIR)$$(MANDIR)/man$$($1_section)

$$($1_install_dir)/$1: $1
	@mkdir -p $$(@D)
	install -m644 $$< $$@

all: $1
install: $$($1_install_dir)/$1
endef

# Generate build and install rules for one filter
#
# $1: filter source path or name
#
define install_filter
ifneq ($(wildcard filters/$1.c),)
$1: filters/$1.c
	$$(CC) $$(CFLAGS) $$(LDFLAGS) -o $$@ $$<

all: $1
endif

$1_install_dir = $$(DESTDIR)$$(LIBEXECDIR)/filters

$$($1_install_dir)/$$(notdir $1): $1
	@mkdir -p $$(@D)
	install -m755 $$< $$@

install: $$($1_install_dir)/$$(notdir $1)
endef

# Generate install rules for any file
#
# $1: source file
# $2: mode
# $3: target dir
#
define install_file
$3/$$(notdir $1): $1
	@mkdir -p $$(@D)
	install -m$2 $$< $$@

install: $3/$$(notdir $1)
endef

# Call macros to generate build&install rules
$(foreach m,$(docs),\
	$(eval $(call install_man,$m)))
$(foreach f,$(filters) $(cfilters),\
	$(eval $(call install_filter,$f)))
$(foreach f,$(wildcard config/*.conf),\
	$(eval $(call install_file,$f,644,$(DESTDIR)$(SHAREDIR))))
$(foreach s,$(wildcard stylesets/*),\
	$(eval $(call install_file,$s,644,$(DESTDIR)$(SHAREDIR)/stylesets)))
$(foreach t,$(wildcard templates/*),\
	$(eval $(call install_file,$t,644,$(DESTDIR)$(SHAREDIR)/templates)))
$(eval $(call install_file,contrib/aerc.desktop,644,$(DESTDIR)$(PREFIX)/share/applications))
$(eval $(call install_file,aerc,755,$(DESTDIR)$(BINDIR)))
$(eval $(call install_file,contrib/carddav-query,755,$(DESTDIR)$(BINDIR)))
diff --git a/Makefile b/Makefile
index acd8a7288e7b..8b7ec97f7b92 100644
--- a/Makefile
+++ b/Makefile
@@ -1,220 +1 @@
.POSIX:
.SUFFIXES:
.SUFFIXES: .1 .5 .7 .1.scd .5.scd .7.scd

VERSION?=`git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 0.15.2`
VPATH=doc
PREFIX?=/usr/local
BINDIR?=$(PREFIX)/bin
SHAREDIR?=$(PREFIX)/share/aerc
LIBEXECDIR?=$(PREFIX)/libexec/aerc
MANDIR?=$(PREFIX)/share/man
GO?=go
GOFLAGS?=`contrib/goflags.sh`
BUILD_OPTS?=-trimpath
# ignore environment variable
GO_LDFLAGS:=
GO_LDFLAGS+=-X main.Version=$(VERSION)
GO_LDFLAGS+=-X main.Flags=$$(echo -- $(GOFLAGS) | base64 | tr -d '\r\n')
GO_LDFLAGS+=-X git.sr.ht/~rjarry/aerc/config.shareDir=$(SHAREDIR)
GO_LDFLAGS+=-X git.sr.ht/~rjarry/aerc/config.libexecDir=$(LIBEXECDIR)
GO_LDFLAGS+=$(GO_EXTRA_LDFLAGS)

GOSRC!=find * -type f -name '*.go'
GOSRC+=go.mod go.sum

DOCS := \
	aerc.1 \
	aerc-search.1 \
	aerc-accounts.5 \
	aerc-binds.5 \
	aerc-config.5 \
	aerc-imap.5 \
	aerc-jmap.5 \
	aerc-maildir.5 \
	aerc-sendmail.5 \
	aerc-notmuch.5 \
	aerc-smtp.5 \
	aerc-tutorial.7 \
	aerc-templates.7 \
	aerc-stylesets.7 \
	carddav-query.1

all: aerc wrap colorize $(DOCS)

aerc: $(GOSRC)
	$(GO) build $(BUILD_OPTS) $(GOFLAGS) -ldflags "$(GO_LDFLAGS)" -o aerc

CC?=cc
CFLAGS?=-O2 -g

wrap: filters/wrap.c
	$(CC) $(CFLAGS) $(LDFLAGS) -o wrap filters/wrap.c

colorize: filters/colorize.c
	$(CC) $(CFLAGS) $(LDFLAGS) -o colorize filters/colorize.c

.PHONY: dev
dev:
	$(MAKE) aerc BUILD_OPTS="-trimpath -race"
	GORACE="log_path=race.log strip_path_prefix=git.sr.ht/~rjarry/aerc/" ./aerc

gofumpt_tag = v0.5.0

.PHONY: fmt
fmt:
	$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -w .

linters.so: contrib/linters.go
	$(GO) build -buildmode=plugin -o linters.so contrib/linters.go

.PHONY: lint
lint: linters.so
	@contrib/check-whitespace `git ls-files ':!:filters/vectors'` && \
		echo white space ok.
	@$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -d . | grep ^ \
		&& echo The above files need to be formatted, please run make fmt && exit 1 \
		|| echo all files formatted.
	$(GO) run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2 run \
		$$(echo $(GOFLAGS) | sed s/-tags=/--build-tags=/)

.PHONY: vulncheck
vulncheck:
	$(GO) run golang.org/x/vuln/cmd/govulncheck@latest ./...

.PHONY: tests
tests: wrap colorize
	$(GO) test $(GOFLAGS) ./...
	filters/test.sh

.PHONY: debug
debug: aerc.debug
	@echo 'Run `./aerc.debug` and use this command in another terminal to attach a debugger:'
	@echo '    dlv attach $$(pidof aerc.debug)'

aerc.debug: $(GOSRC)
	$(GO) build $(GOFLAGS) -gcflags=*=-N -gcflags=*=-l -ldflags="$(GO_LDFLAGS)" -o aerc.debug

.1.scd.1:
	scdoc < $< > $@

.5.scd.5:
	scdoc < $< > $@

.7.scd.7:
	scdoc < $< > $@

doc: $(DOCS)

# Exists in GNUMake but not in NetBSD make and others.
RM?=rm -f

clean:
	$(RM) $(DOCS) aerc wrap colorize

install: $(DOCS) aerc wrap colorize
	@# `install -D` is not supported on all platforms (macos install(1)
	@# dates back to the middle ages and does not have this flag).
	@# The folders must be created manually first.
	mkdir -m755 -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR)/man1 $(DESTDIR)$(MANDIR)/man5 $(DESTDIR)$(MANDIR)/man7 \
		$(DESTDIR)$(SHAREDIR)/templates $(DESTDIR)$(SHAREDIR)/stylesets \
		$(DESTDIR)$(PREFIX)/share/applications $(DESTDIR)$(LIBEXECDIR)/filters
	install -m755 aerc $(DESTDIR)$(BINDIR)/aerc
	install -m755 contrib/carddav-query $(DESTDIR)$(BINDIR)/carddav-query
	install -m644 aerc.1 $(DESTDIR)$(MANDIR)/man1/aerc.1
	install -m644 carddav-query.1 $(DESTDIR)$(MANDIR)/man1/carddav-query.1
	install -m644 aerc-search.1 $(DESTDIR)$(MANDIR)/man1/aerc-search.1
	install -m644 aerc-accounts.5 $(DESTDIR)$(MANDIR)/man5/aerc-accounts.5
	install -m644 aerc-binds.5 $(DESTDIR)$(MANDIR)/man5/aerc-binds.5
	install -m644 aerc-config.5 $(DESTDIR)$(MANDIR)/man5/aerc-config.5
	install -m644 aerc-imap.5 $(DESTDIR)$(MANDIR)/man5/aerc-imap.5
	install -m644 aerc-jmap.5 $(DESTDIR)$(MANDIR)/man5/aerc-jmap.5
	install -m644 aerc-maildir.5 $(DESTDIR)$(MANDIR)/man5/aerc-maildir.5
	install -m644 aerc-sendmail.5 $(DESTDIR)$(MANDIR)/man5/aerc-sendmail.5
	install -m644 aerc-notmuch.5 $(DESTDIR)$(MANDIR)/man5/aerc-notmuch.5
	install -m644 aerc-smtp.5 $(DESTDIR)$(MANDIR)/man5/aerc-smtp.5
	install -m644 aerc-tutorial.7 $(DESTDIR)$(MANDIR)/man7/aerc-tutorial.7
	install -m644 aerc-templates.7 $(DESTDIR)$(MANDIR)/man7/aerc-templates.7
	install -m644 aerc-stylesets.7 $(DESTDIR)$(MANDIR)/man7/aerc-stylesets.7
	install -m644 config/accounts.conf $(DESTDIR)$(SHAREDIR)/accounts.conf
	install -m644 config/aerc.conf $(DESTDIR)$(SHAREDIR)/aerc.conf
	install -m644 config/binds.conf $(DESTDIR)$(SHAREDIR)/binds.conf
	install -m755 filters/calendar $(DESTDIR)$(LIBEXECDIR)/filters/calendar
	install -m755 filters/hldiff $(DESTDIR)$(LIBEXECDIR)/filters/hldiff
	install -m755 filters/html $(DESTDIR)$(LIBEXECDIR)/filters/html
	install -m755 filters/html-unsafe $(DESTDIR)$(LIBEXECDIR)/filters/html-unsafe
	install -m755 filters/plaintext $(DESTDIR)$(LIBEXECDIR)/filters/plaintext
	install -m755 filters/show-ics-details.py $(DESTDIR)$(LIBEXECDIR)/filters/show-ics-details.py
	install -m755 colorize $(DESTDIR)$(LIBEXECDIR)/filters/colorize
	install -m755 wrap $(DESTDIR)$(LIBEXECDIR)/filters/wrap
	install -m644 templates/new_message $(DESTDIR)$(SHAREDIR)/templates/new_message
	install -m644 templates/quoted_reply $(DESTDIR)$(SHAREDIR)/templates/quoted_reply
	install -m644 templates/forward_as_body $(DESTDIR)$(SHAREDIR)/templates/forward_as_body
	install -m644 stylesets/default $(DESTDIR)$(SHAREDIR)/stylesets/default
	install -m644 stylesets/dracula $(DESTDIR)$(SHAREDIR)/stylesets/dracula
	install -m644 stylesets/nord $(DESTDIR)$(SHAREDIR)/stylesets/nord
	install -m644 stylesets/pink $(DESTDIR)$(SHAREDIR)/stylesets/pink
	install -m644 stylesets/blue $(DESTDIR)$(SHAREDIR)/stylesets/blue
	install -m644 stylesets/solarized $(DESTDIR)$(SHAREDIR)/stylesets/solarized
	install -m644 contrib/aerc.desktop $(DESTDIR)$(PREFIX)/share/applications/aerc.desktop

.PHONY: checkinstall
checkinstall:
	$(DESTDIR)$(BINDIR)/aerc -v
	test -e $(DESTDIR)$(MANDIR)/man1/aerc.1
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-accounts.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-binds.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-config.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-imap.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-jmap.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-notmuch.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-sendmail.5
	test -e $(DESTDIR)$(MANDIR)/man5/aerc-smtp.5
	test -e $(DESTDIR)$(MANDIR)/man7/aerc-tutorial.7
	test -e $(DESTDIR)$(MANDIR)/man7/aerc-templates.7

RMDIR_IF_EMPTY:=sh -c '! [ -d $$0 ] || ls -1qA $$0 | grep -q . || rmdir $$0'

uninstall:
	$(RM) $(DESTDIR)$(BINDIR)/aerc
	$(RM) $(DESTDIR)$(BINDIR)/carddav-query
	$(RM) $(DESTDIR)$(MANDIR)/man1/aerc.1
	$(RM) $(DESTDIR)$(MANDIR)/man1/aerc-search.1
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-accounts.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-binds.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-config.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-imap.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-jmap.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-maildir.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-sendmail.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-notmuch.5
	$(RM) $(DESTDIR)$(MANDIR)/man5/aerc-smtp.5
	$(RM) $(DESTDIR)$(MANDIR)/man7/aerc-tutorial.7
	$(RM) $(DESTDIR)$(MANDIR)/man7/aerc-templates.7
	$(RM) $(DESTDIR)$(MANDIR)/man7/aerc-stylesets.7
	$(RM) -r $(DESTDIR)$(SHAREDIR)
	$(RM) -r $(DESTDIR)$(LIBEXECDIR)
	${RMDIR_IF_EMPTY} $(DESTDIR)$(BINDIR)
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man1
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man5
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man7
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)
	$(RM) $(DESTDIR)$(PREFIX)/share/applications/aerc.desktop
	$(RMDIR_IF_EMPTY) $(DESTDIR)$(PREFIX)/share/applications

.PHONY: gitconfig
gitconfig:
	git config format.subjectPrefix "PATCH aerc"
	git config sendemail.to "~rjarry/aerc-devel@lists.sr.ht"
	@mkdir -p .git/hooks
	@rm -f .git/hooks/sendemail-validate*
	@if grep -q GIT_SENDEMAIL_FILE_COUNTER `git --exec-path`/git-send-email 2>/dev/null; then \
		ln -svf ../../contrib/sendemail-validate .git/hooks/sendemail-validate && \
		git config sendemail.validate true; \
	fi

.PHONY: check-patches
check-patches:
	@contrib/check-patches origin/master..

.PHONY: all doc clean install uninstall debug
.error ERROR: please compile and install using GNU make (gmake)
diff --git a/README.md b/README.md
index 242fb99da868..727e8eae02e3 100644
--- a/README.md
+++ b/README.md
@@ -72,6 +72,7 @@ Install the dependencies:
  older versions may be dropped at any time due to incompatibilities or newer
  required language features.)*
- [scdoc](https://git.sr.ht/~sircmpwn/scdoc)
- GNU make (on \*BSD, `make` commands must be replaced by `gmake`).

Then compile aerc:

-- 
2.41.0

[aerc/patches] build failed

builds.sr.ht <builds@sr.ht>
Details
Message ID
<CUK3CDJ9DU51.E5YIL6O4IVWF@cirno2>
In-Reply-To
<20230804214517.87640-2-robin@jarry.cc> (view parent)
DKIM signature
missing
Download raw message
aerc/patches: FAILED in 4m48s

[mk: deprecate BSD make in favor of GNU make][0] v5 from [Robin Jarry][1]

[0]: https://lists.sr.ht/~rjarry/aerc-devel/patches/43344
[1]: robin@jarry.cc

✓ #1035458 SUCCESS aerc/patches/alpine-edge.yml https://builds.sr.ht/~rjarry/job/1035458
✗ #1035459 FAILED  aerc/patches/openbsd.yml     https://builds.sr.ht/~rjarry/job/1035459
Details
Message ID
<CUKIOSE5MBM7.31BBJWJGMQ0L3@hades.moritz.sh>
In-Reply-To
<20230804214517.87640-2-robin@jarry.cc> (view parent)
DKIM signature
missing
Download raw message
On Fri Aug 4, 2023 at 11:45 PM CEST, Robin Jarry wrote:
> Being portable between BSD and GNU make is a nightmare. It restricts
> features to a very minimal surface and in turn requires a lot of code
> duplication and manual updating of file lists.
>
> Worse, aerc's makefile relies on the shell assignment operator (!=)
> which has been supported by BSD make 2.2 since 1997 but GNU make 4.0
> since 2013. Unfortunately, MacOS runs GNU make 3.8 which does not have
> that feature. Reducing the feature set even more.
>
> Stop that nonsense and remove BSD make compatibility. The majority of
> aerc's users either run a GNU Linux distribution or MacOS. For those who
> run any *BSD variant, it is easy for them to install GNU make (gmake) if
> they don't have it installed already.
>
> Use GNU make constructs to generate build and install rules dynamically
> based on source files discovery.
>
> Signed-off-by: Robin Jarry <robin@jarry.cc>
> ---
>
> Notes:
>     v5 (RFC)
>     
>     * Drop BSD make compatibility. Only support GNU make.
>     
>     NB: CI will fail on OpenBSD because gmake is not installed and the
>     builds command will run with BSD make.
>
>  .builds/openbsd.yml |   8 +-
>  CHANGELOG.md        |   5 +
>  GNUmakefile         | 200 +++++++++++++++++++++++++++++++++++++++
>  Makefile            | 221 +-------------------------------------------
>  README.md           |   1 +
>  5 files changed, 212 insertions(+), 223 deletions(-)
>  create mode 100644 GNUmakefile
>
> diff --git a/GNUmakefile b/GNUmakefile

Why the renaming?

> new file mode 100644
> index 000000000000..6edda0a22cf7
> --- /dev/null
> +++ b/GNUmakefile
> @@ -0,0 +1,200 @@
> +# variables that can be changed by users
> +#
> +VERSION ?= `git describe --long --abbrev=12 --tags --dirty 2>/dev/null || echo 0.15.2`
> +PREFIX ?= /usr/local
> +BINDIR ?= $(PREFIX)/bin
> +SHAREDIR ?= $(PREFIX)/share/aerc
> +LIBEXECDIR ?= $(PREFIX)/libexec/aerc
> +MANDIR ?= $(PREFIX)/share/man
> +GO ?= go
> +GOFLAGS ?= `contrib/goflags.sh`
> +BUILD_OPTS ?= -trimpath
> +GO_LDFLAGS :=
> +GO_LDFLAGS += -X main.Version=$(VERSION)
> +GO_LDFLAGS += -X main.Flags=$$(echo -- $(GOFLAGS) | base64 | tr -d '\r\n')
> +GO_LDFLAGS += -X git.sr.ht/~rjarry/aerc/config.shareDir=$(SHAREDIR)
> +GO_LDFLAGS += -X git.sr.ht/~rjarry/aerc/config.libexecDir=$(LIBEXECDIR)
> +GO_LDFLAGS += $(GO_EXTRA_LDFLAGS)
> +CC ?= cc
> +CFLAGS ?= -O2 -g
> +
> +# internal variables used for automatic rules generation with macros
> +gosrc = $(shell find * -type f -name '*.go') go.mod go.sum
> +man1 = $(subst .scd,,$(notdir $(wildcard doc/*.1.scd)))
> +man5 = $(subst .scd,,$(notdir $(wildcard doc/*.5.scd)))
> +man7 = $(subst .scd,,$(notdir $(wildcard doc/*.7.scd)))
> +docs = $(man1) $(man5) $(man7)
> +cfilters = $(subst .c,,$(notdir $(wildcard filters/*.c)))
> +filters = $(filter-out filters/vectors filters/test.sh filters/%.c,$(wildcard filters/*))
> +gofumpt_tag = v0.5.0
> +
> +# Dependencies are added to "all" dynamically with macros
> +.PHONY: all
> +all: aerc
> +	@:
> +
> +aerc: $(gosrc)
> +	$(GO) build $(BUILD_OPTS) $(GOFLAGS) -ldflags "$(GO_LDFLAGS)" -o aerc
> +
> +.PHONY: dev
> +dev:
> +	rm aerc

This should probably have a - modifier

> +	$(MAKE) aerc BUILD_OPTS="-trimpath -race"
> +	GORACE="log_path=race.log strip_path_prefix=git.sr.ht/~rjarry/aerc/" ./aerc
> +
> +.PHONY: fmt
> +fmt:
> +	$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -w .
> +
> +linters.so: contrib/linters.go
> +	$(GO) build -buildmode=plugin -o linters.so contrib/linters.go
> +
> +.PHONY: lint
> +lint: linters.so
> +	@contrib/check-whitespace `git ls-files ':!:filters/vectors'` && \
> +		echo white space ok.
> +	@$(GO) run mvdan.cc/gofumpt@$(gofumpt_tag) -d . | grep ^ \
> +		&& echo The above files need to be formatted, please run make fmt && exit 1 \
> +		|| echo all files formatted.
> +	$(GO) run github.com/golangci/golangci-lint/cmd/golangci-lint@v1.51.2 run \
> +		$$(echo $(GOFLAGS) | sed s/-tags=/--build-tags=/)
> +
> +.PHONY: vulncheck
> +vulncheck:
> +	$(GO) run golang.org/x/vuln/cmd/govulncheck@latest ./...
> +
> +.PHONY: tests
> +tests: $(cfilters)
> +	$(GO) test $(GOFLAGS) ./...
> +	filters/test.sh
> +
> +.PHONY: debug
> +debug: aerc.debug
> +	@echo 'Run `./aerc.debug` and use this command in another terminal to attach a debugger:'
> +	@echo '    dlv attach $$(pidof aerc.debug)'
> +
> +aerc.debug: $(gosrc)
> +	$(GO) build $(GOFLAGS) -gcflags=*=-N -gcflags=*=-l -ldflags="$(GO_LDFLAGS)" -o aerc.debug
> +
> +.PHONY: doc
> +doc: $(docs)
> +	@:
> +
> +.PHONY: clean
> +clean:
> +	$(RM) $(docs) aerc $(cfilters)
> +
> +# Dependencies are added dynamically to the install rule with macros
> +.PHONY: install
> +install:
> +	@:
> +
> +.PHONY: checkinstall
> +checkinstall:
> +	$(DESTDIR)$(BINDIR)/aerc -v
> +	for m in $(man1); do test -e $(DESTDIR)$(MANDIR)/man1/$$m || exit; done
> +	for m in $(man5); do test -e $(DESTDIR)$(MANDIR)/man5/$$m || exit; done
> +	for m in $(man7); do test -e $(DESTDIR)$(MANDIR)/man7/$$m || exit; done
> +
> +RMDIR_IF_EMPTY:=sh -c '! [ -d $$0 ] || ls -1qA $$0 | grep -q . || rmdir $$0'
> +
> +.PHONY: uninstall
> +uninstall:
> +	$(RM) $(DESTDIR)$(BINDIR)/aerc
> +	$(RM) $(DESTDIR)$(BINDIR)/carddav-query
> +	for m in $(man1); do $(RM) $(DESTDIR)$(MANDIR)/man1/$$m; done
> +	for m in $(man5); do $(RM) $(DESTDIR)$(MANDIR)/man5/$$m; done
> +	for m in $(man7); do $(RM) $(DESTDIR)$(MANDIR)/man7/$$m; done
> +	$(RM) -r $(DESTDIR)$(SHAREDIR)
> +	$(RM) -r $(DESTDIR)$(LIBEXECDIR)
> +	${RMDIR_IF_EMPTY} $(DESTDIR)$(BINDIR)
> +	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man1
> +	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man5
> +	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)/man7
> +	$(RMDIR_IF_EMPTY) $(DESTDIR)$(MANDIR)
> +	$(RM) $(DESTDIR)$(PREFIX)/share/applications/aerc.desktop
> +	$(RMDIR_IF_EMPTY) $(DESTDIR)$(PREFIX)/share/applications
> +
> +.PHONY: gitconfig
> +gitconfig:
> +	git config format.subjectPrefix "PATCH aerc"
> +	git config sendemail.to "~rjarry/aerc-devel@lists.sr.ht"
> +	@mkdir -p .git/hooks
> +	@rm -f .git/hooks/sendemail-validate*
> +	@if grep -q GIT_SENDEMAIL_FILE_COUNTER `git --exec-path`/git-send-email 2>/dev/null; then \
> +		ln -svf ../../contrib/sendemail-validate .git/hooks/sendemail-validate && \
> +		git config sendemail.validate true; \
> +	fi
> +
> +.PHONY: check-patches
> +check-patches:
> +	@contrib/check-patches origin/master..
> +
> +# Generate build and install rules for one man page
> +#
> +# $1: man page name (e.g: aerc.1)
> +#
> +define install_man
> +$1: doc/$1.scd
> +	scdoc < $$< > $$@

No need for a macro here. a simple substitution is enough:
	DOC_TARGETS := $(patsubst doc/%.scd,%.gz,$(wildcard doc/*.scd))
	.PHONY: docs
	docs: $(DOC_TARGETS)
	%.gz: doc/%.scd
		scdoc < $< | gzip > $@

Manpage compression being optional, obviously

> +
> +$1_section = $$(subst .,,$$(suffix $1))
> +$1_install_dir = $$(DESTDIR)$$(MANDIR)/man$$($1_section)
> +
> +$$($1_install_dir)/$1: $1
> +	@mkdir -p $$(@D)
> +	install -m644 $$< $$@
> +
> +all: $1
> +install: $$($1_install_dir)/$1
> +endef
> +
> +# Generate build and install rules for one filter
> +#
> +# $1: filter source path or name
> +#
> +define install_filter
> +ifneq ($(wildcard filters/$1.c),)
> +$1: filters/$1.c
> +	$$(CC) $$(CFLAGS) $$(LDFLAGS) -o $$@ $$<
> +
> +all: $1
> +endif
> +
> +$1_install_dir = $$(DESTDIR)$$(LIBEXECDIR)/filters
> +
> +$$($1_install_dir)/$$(notdir $1): $1
> +	@mkdir -p $$(@D)
> +	install -m755 $$< $$@
> +
> +install: $$($1_install_dir)/$$(notdir $1)
> +endef
> +
> +# Generate install rules for any file
> +#
> +# $1: source file
> +# $2: mode
> +# $3: target dir
> +#
> +define install_file
> +$3/$$(notdir $1): $1
> +	@mkdir -p $$(@D)
> +	install -m$2 $$< $$@
> +
> +install: $3/$$(notdir $1)
> +endef
> +
> +# Call macros to generate build&install rules
> +$(foreach m,$(docs),\
> +	$(eval $(call install_man,$m)))
> +$(foreach f,$(filters) $(cfilters),\
> +	$(eval $(call install_filter,$f)))
> +$(foreach f,$(wildcard config/*.conf),\
> +	$(eval $(call install_file,$f,644,$(DESTDIR)$(SHAREDIR))))
> +$(foreach s,$(wildcard stylesets/*),\
> +	$(eval $(call install_file,$s,644,$(DESTDIR)$(SHAREDIR)/stylesets)))
> +$(foreach t,$(wildcard templates/*),\
> +	$(eval $(call install_file,$t,644,$(DESTDIR)$(SHAREDIR)/templates)))
> +$(eval $(call install_file,contrib/aerc.desktop,644,$(DESTDIR)$(PREFIX)/share/applications))
> +$(eval $(call install_file,aerc,755,$(DESTDIR)$(BINDIR)))
> +$(eval $(call install_file,contrib/carddav-query,755,$(DESTDIR)$(BINDIR)))

This is why Make is by some considered one of the dark arts… I think our
Makefile should also follow the general "no magic" rule.

-- 
Moritz Poldrack
https://moritz.sh
Details
Message ID
<a16bd98e-ef41-440f-8e69-21f49f59ee59@app.fastmail.com>
In-Reply-To
<CUKIOSE5MBM7.31BBJWJGMQ0L3@hades.moritz.sh> (view parent)
DKIM signature
missing
Download raw message
Moritz Poldrack, Aug 05 2023:
> Why the renaming?

To make sure BSD make users get an explicit message about the gmake requirement. gmake will use GNUmakefile in priority.

>> +	rm aerc
>
> This should probably have a - modifier

Or I should use $(RM). Good catch.

>> +# Generate build and install rules for one man page
>> +#
>> +# $1: man page name (e.g: aerc.1)
>> +#
>> +define install_man
>> +$1: doc/$1.scd
>> +	scdoc < $$< > $$@
>
> No need for a macro here. a simple substitution is enough:
> 	DOC_TARGETS := $(patsubst doc/%.scd,%.gz,$(wildcard doc/*.scd))
> 	.PHONY: docs
> 	docs: $(DOC_TARGETS)
> 	%.gz: doc/%.scd
> 		scdoc < $< | gzip > $@
>
> Manpage compression being optional, obviously

The macro does more than only taking care of building. It also installs in the correct folder. No way to do this dynamically otherwise.

> This is why Make is by some considered one of the dark arts… I think our
> Makefile should also follow the general "no magic" rule.

I'll be fine with maintaining this as long as it works and does not require constant updates because someone forgot to install whatever new man page, filter, template or styleset. This is not my first time with GNU make ;)
Reply to thread Export thread (mbox)