summaryrefslogtreecommitdiffstats
path: root/Makefile
diff options
context:
space:
mode:
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile454
1 files changed, 227 insertions, 227 deletions
diff --git a/Makefile b/Makefile
index 1ea17a2..d89f3b6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,231 +1,231 @@
-############################################################################
-# bfs #
-# Copyright (C) 2015-2021 Tavian Barnes <tavianator@tavianator.com> #
-# #
-# Permission to use, copy, modify, and/or distribute this software for any #
-# purpose with or without fee is hereby granted. #
-# #
-# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES #
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF #
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR #
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES #
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN #
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF #
-# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #
-############################################################################
-
-ifeq ($(wildcard .git),)
-VERSION := 2.3
-else
-VERSION := $(shell git describe --always)
-endif
-
-ifndef OS
-OS := $(shell uname)
-endif
-
-ifndef ARCH
-ARCH := $(shell uname -m)
-endif
-
-CC ?= gcc
-INSTALL ?= install
-MKDIR ?= mkdir -p
-RM ?= rm -f
-
-DEFAULT_CFLAGS := \
- -g \
- -Wall \
- -Wmissing-declarations \
- -Wshadow \
- -Wsign-compare \
- -Wstrict-prototypes \
- -Wimplicit-fallthrough
-
-CFLAGS ?= $(DEFAULT_CFLAGS)
-LDFLAGS ?=
-DEPFLAGS ?= -MD -MP -MF $(@:.o=.d)
-
-DESTDIR ?=
-PREFIX ?= /usr
-MANDIR ?= $(PREFIX)/share/man
-
-LOCAL_CPPFLAGS := \
- -D__EXTENSIONS__ \
- -D_ATFILE_SOURCE \
- -D_BSD_SOURCE \
- -D_DARWIN_C_SOURCE \
- -D_DEFAULT_SOURCE \
- -D_FILE_OFFSET_BITS=64 \
- -D_GNU_SOURCE \
- -DBFS_VERSION=\"$(VERSION)\"
-
-LOCAL_CFLAGS := -std=c99
-LOCAL_LDFLAGS :=
-LOCAL_LDLIBS :=
-
-ASAN_CFLAGS := -fsanitize=address
-MSAN_CFLAGS := -fsanitize=memory -fsanitize-memory-track-origins
-UBSAN_CFLAGS := -fsanitize=undefined
-
-ifeq ($(OS),Linux)
-LOCAL_LDFLAGS += -Wl,--as-needed
-LOCAL_LDLIBS += -lacl -lcap -lattr -lrt
-
-# These libraries are not built with msan, so disable them
-MSAN_CFLAGS += -DBFS_HAS_SYS_ACL=0 -DBFS_HAS_SYS_CAPABILITY=0 -DBFS_HAS_SYS_XATTR=0
-
-DISTCHECK_FLAGS := TEST_FLAGS="--verbose --all --sudo"
-else
-DISTCHECK_FLAGS := TEST_FLAGS="--verbose"
-endif
-
-ifeq ($(OS),NetBSD)
-LOCAL_LDLIBS += -lutil
-endif
-
-ifneq ($(filter asan,$(MAKECMDGOALS)),)
-LOCAL_CFLAGS += $(ASAN_CFLAGS)
-SANITIZE := y
-endif
-
-ifneq ($(filter msan,$(MAKECMDGOALS)),)
-LOCAL_CFLAGS += $(MSAN_CFLAGS)
-SANITIZE := y
-endif
-
-ifneq ($(filter ubsan,$(MAKECMDGOALS)),)
-LOCAL_CFLAGS += $(UBSAN_CFLAGS)
-SANITIZE := y
-endif
-
-ifdef SANITIZE
-LOCAL_CFLAGS += -fno-sanitize-recover=all
-endif
-
-ifneq ($(filter gcov,$(MAKECMDGOALS)),)
-LOCAL_CFLAGS += --coverage
-endif
-
-ifneq ($(filter release,$(MAKECMDGOALS)),)
-CFLAGS := $(DEFAULT_CFLAGS) -O3 -flto -DNDEBUG
-endif
-
-ALL_CPPFLAGS = $(LOCAL_CPPFLAGS) $(CPPFLAGS)
-ALL_CFLAGS = $(ALL_CPPFLAGS) $(LOCAL_CFLAGS) $(CFLAGS) $(DEPFLAGS)
-ALL_LDFLAGS = $(ALL_CFLAGS) $(LOCAL_LDFLAGS) $(LDFLAGS)
-ALL_LDLIBS = $(LOCAL_LDLIBS) $(LDLIBS)
-
-# Save the full set of flags to rebuild everything when they change
-ALL_FLAGS := $(CC) : $(ALL_CFLAGS) : $(ALL_LDFLAGS) : $(ALL_LDLIBS)
-$(shell ./flags.sh $(ALL_FLAGS))
-
-# Goals that make binaries
-BIN_GOALS := bfs tests/mksock tests/trie tests/xtimegm
-
-# Goals that are treated like flags by this Makefile
-FLAG_GOALS := asan msan ubsan gcov release
-
-# These are the remaining non-flag goals
-GOALS := $(filter-out $(FLAG_GOALS),$(MAKECMDGOALS))
-
-# Build the default goal if only flag goals are specified
-FLAG_PREREQS :=
-ifndef GOALS
-FLAG_PREREQS += default
-endif
-
-# The different search strategies that we test
-STRATEGIES := bfs dfs ids eds
-STRATEGY_CHECKS := $(STRATEGIES:%=check-%)
-
-# All the different checks we run
-CHECKS := $(STRATEGY_CHECKS) check-trie check-xtimegm
+# Copyright © Tavian Barnes <tavianator@tavianator.com>
+# SPDX-License-Identifier: 0BSD
-default: bfs
+# To build bfs, run
+#
+# $ ./configure
+# $ make
-all: $(BIN_GOALS)
-
-bfs: \
- bar.o \
- bftw.o \
- color.o \
- ctx.o \
- darray.o \
- diag.o \
- dir.o \
- dstring.o \
- eval.o \
- exec.o \
- fsade.o \
- main.o \
- mtab.o \
- opt.o \
- parse.o \
- printf.o \
- pwcache.o \
- spawn.o \
- stat.o \
- time.o \
- trie.o \
- typo.o \
- util.o
-
-tests/mksock: tests/mksock.o
-tests/trie: trie.o tests/trie.o
-tests/xtimegm: time.o tests/xtimegm.o
-
-$(BIN_GOALS):
- +$(CC) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
-
-%.o: %.c .flags
- $(CC) $(ALL_CFLAGS) -c $< -o $@
-
-# Need a rule for .flags to convince make to apply the above pattern rule if
-# .flags didn't exist when make was run
-.flags:
-
-# Make sure that "make release" builds everything, but "make release main.o" doesn't
-$(FLAG_GOALS): $(FLAG_PREREQS)
- @:
-
-check: $(CHECKS)
-
-$(STRATEGY_CHECKS): check-%: bfs tests/mksock
- ./tests.sh --bfs="$(CURDIR)/bfs -S $*" $(TEST_FLAGS)
-
-check-trie check-xtimegm: check-%: tests/%
- $<
+# Utilities and GNU/BSD portability
+include build/prelude.mk
+# The default build target
+default: bfs
+.PHONY: default
+
+# Include the generated build config, if it exists
+-include gen/config.mk
+
+## Configuration phase (`./configure`)
+
+# bfs used to have flag-like targets (`make release`, `make asan ubsan`, etc.).
+# Direct users to the new configuration system.
+asan lsan msan tsan ubsan gcov lint release::
+ @printf 'error: `%s %s` is no longer supported. Use `./configure --enable-%s` instead.\n' \
+ "${MAKE}" $@ $@ >&2
+ @false
+
+# Print an error if `make` is run before `./configure`
+gen/config.mk::
+ @if ! [ -e $@ ]; then \
+ printf 'error: You must run `./configure` before `%s`.\n' "${MAKE}" >&2; \
+ false; \
+ fi
+
+## Build phase (`make`)
+
+# The main binary
+bfs: bin/bfs
+.PHONY: bfs
+
+# All binaries
+BINS := \
+ bin/bfs \
+ bin/tests/mksock \
+ bin/tests/units \
+ bin/tests/xspawnee \
+ bin/tests/xtouch
+
+all: ${BINS}
+.PHONY: all
+
+# The main binary
+bin/bfs: ${LIBBFS} obj/src/main.o
+
+${BINS}:
+ @${MKDIR} ${@D}
+ +${MSG} "[ LD ] $@" ${CC} ${CFLAGS} ${LDFLAGS} ${.ALLSRC} ${LDLIBS} -o $@
+ ${POSTLINK}
+
+# Get the .c file for a .o file
+CSRC = ${@:obj/%.o=%.c}
+
+# Rebuild when the configuration changes
+${OBJS}: gen/config.mk
+ @${MKDIR} ${@D}
+ ${MSG} "[ CC ] ${CSRC}" ${CC} ${CPPFLAGS} ${CFLAGS} -c ${CSRC} -o $@
+
+# Save the version number to this file, but only update version.c if it changes
+gen/version.c.new::
+ @${MKDIR} ${@D}
+ @printf 'const char bfs_version[] = "' >$@
+ @if [ "$$VERSION" ]; then \
+ printf '%s' "$$VERSION"; \
+ elif test -e src/../.git && command -v git >/dev/null 2>&1; then \
+ git -C src/.. describe --always --dirty; \
+ else \
+ echo "3.2"; \
+ fi | tr -d '\n' >>$@
+ @printf '";\n' >>$@
+
+gen/version.c: gen/version.c.new
+ @test -e $@ && cmp -s $@ ${.ALLSRC} && rm ${.ALLSRC} || mv ${.ALLSRC} $@
+
+obj/gen/version.o: gen/version.c
+
+## Test phase (`make check`)
+
+# Unit test binaries
+UTEST_BINS := \
+ bin/tests/units \
+ bin/tests/xspawnee
+
+# Integration test binaries
+ITEST_BINS := \
+ bin/tests/mksock \
+ bin/tests/xtouch
+
+# Build (but don't run) test binaries
+tests: ${UTEST_BINS} ${ITEST_BINS}
+.PHONY: tests
+
+# Run all the tests
+check: unit-tests integration-tests
+.PHONY: check
+
+# Run the unit tests
+unit-tests: ${UTEST_BINS}
+ ${MSG} "[TEST] tests/units" bin/tests/units
+.PHONY: unit-tests
+
+bin/tests/units: \
+ ${UNIT_OBJS} \
+ ${LIBBFS}
+
+bin/tests/xspawnee: \
+ obj/tests/xspawnee.o
+
+# The different flag combinations we check
+INTEGRATIONS := default dfs ids eds j1 j2 j3 s
+INTEGRATION_TESTS := ${INTEGRATIONS:%=check-%}
+
+# Check just `bfs`
+check-default: bin/bfs ${ITEST_BINS}
+ +${MSG} "[TEST] bfs" \
+ ./tests/tests.sh --make="${MAKE}" --bfs="bin/bfs" ${TEST_FLAGS}
+
+# Check the different search strategies
+check-dfs check-ids check-eds: bin/bfs ${ITEST_BINS}
+ +${MSG} "[TEST] bfs -S ${@:check-%=%}" \
+ ./tests/tests.sh --make="${MAKE}" --bfs="bin/bfs -S ${@:check-%=%}" ${TEST_FLAGS}
+
+# Check various flags
+check-j1 check-j2 check-j3 check-s: bin/bfs ${ITEST_BINS}
+ +${MSG} "[TEST] bfs -${@:check-%=%}" \
+ ./tests/tests.sh --make="${MAKE}" --bfs="bin/bfs -${@:check-%=%}" ${TEST_FLAGS}
+
+# Run the integration tests
+integration-tests: ${INTEGRATION_TESTS}
+.PHONY: integration-tests
+
+bin/tests/mksock: \
+ obj/tests/mksock.o \
+ ${LIBBFS}
+
+bin/tests/xtouch: \
+ obj/tests/xtouch.o \
+ ${LIBBFS}
+
+# `make distcheck` configurations
+DISTCHECKS := \
+ distcheck-asan \
+ distcheck-msan \
+ distcheck-tsan \
+ distcheck-m32 \
+ distcheck-release
+
+# Test multiple configurations
distcheck:
- +$(MAKE) -B asan ubsan check $(DISTCHECK_FLAGS)
-ifneq ($(OS),Darwin)
- +$(MAKE) -B msan check CC=clang $(DISTCHECK_FLAGS)
-ifeq ($(ARCH),x86_64)
- +$(MAKE) -B check CFLAGS="-m32" $(DISTCHECK_FLAGS)
-endif
-endif
- +$(MAKE) -B release check $(DISTCHECK_FLAGS)
- +$(MAKE) -B check $(DISTCHECK_FLAGS)
-
-clean:
- $(RM) $(BIN_GOALS) .flags *.[od] *.gcda *.gcno tests/*.[od] tests/*.gcda tests/*.gcno
-
-install:
- $(MKDIR) $(DESTDIR)$(PREFIX)/bin
- $(INSTALL) -m755 bfs $(DESTDIR)$(PREFIX)/bin/bfs
- $(MKDIR) $(DESTDIR)$(MANDIR)/man1
- $(INSTALL) -m644 bfs.1 $(DESTDIR)$(MANDIR)/man1/bfs.1
- $(MKDIR) $(DESTDIR)$(PREFIX)/share/bash-completion/completions
- $(INSTALL) -m644 completions/bfs.bash $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
-
-uninstall:
- $(RM) $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
- $(RM) $(DESTDIR)$(MANDIR)/man1/bfs.1
- $(RM) $(DESTDIR)$(PREFIX)/bin/bfs
-
-.PHONY: default all $(FLAG_GOALS) check $(CHECKS) distcheck clean install uninstall
-
-.SUFFIXES:
-
--include $(wildcard *.d)
+ @+${MAKE} -s distcheck-asan
+ @+test "$$(uname)" = Darwin || ${MAKE} -s distcheck-msan
+ @+${MAKE} -s distcheck-tsan
+ @+test "$$(uname)-$$(uname -m)" != Linux-x86_64 || ${MAKE} -s distcheck-m32
+ @+${MAKE} -s distcheck-release
+.PHONY: distcheck
+
+# Per-distcheck configuration
+DISTCHECK_CONFIG_asan := --enable-asan --enable-ubsan
+DISTCHECK_CONFIG_msan := --enable-msan --enable-ubsan CC=clang
+DISTCHECK_CONFIG_tsan := --enable-tsan --enable-ubsan CC=clang
+DISTCHECK_CONFIG_m32 := EXTRA_CFLAGS="-m32" PKG_CONFIG_LIBDIR=/usr/lib32/pkgconfig
+DISTCHECK_CONFIG_release := --enable-release
+
+${DISTCHECKS}::
+ @${MKDIR} $@
+ @+cd $@ \
+ && ../configure ${DISTCHECK_CONFIG_${@:distcheck-%=%}} \
+ && ${MAKE} -s check TEST_FLAGS="--sudo --verbose=skipped"
+
+## Packaging (`make install`)
+
+DEST_PREFIX := ${DESTDIR}${PREFIX}
+DEST_MANDIR := ${DESTDIR}${MANDIR}
+
+install::
+ ${Q}${MKDIR} ${DEST_PREFIX}/bin
+ ${MSG} "[INST] bin/bfs" \
+ ${INSTALL} -m755 bin/bfs ${DEST_PREFIX}/bin/bfs
+ ${Q}${MKDIR} ${DEST_MANDIR}/man1
+ ${MSG} "[INST] man/man1/bfs.1" \
+ ${INSTALL} -m644 docs/bfs.1 ${DEST_MANDIR}/man1/bfs.1
+ ${Q}${MKDIR} ${DEST_PREFIX}/share/bash-completion/completions
+ ${MSG} "[INST] completions/bfs.bash" \
+ ${INSTALL} -m644 completions/bfs.bash ${DEST_PREFIX}/share/bash-completion/completions/bfs
+ ${Q}${MKDIR} ${DEST_PREFIX}/share/zsh/site-functions
+ ${MSG} "[INST] completions/bfs.zsh" \
+ ${INSTALL} -m644 completions/bfs.zsh ${DEST_PREFIX}/share/zsh/site-functions/_bfs
+ ${Q}${MKDIR} ${DEST_PREFIX}/share/fish/vendor_completions.d
+ ${MSG} "[INST] completions/bfs.fish" \
+ ${INSTALL} -m644 completions/bfs.fish ${DEST_PREFIX}/share/fish/vendor_completions.d/bfs.fish
+
+uninstall::
+ ${MSG} "[ RM ] completions/bfs.bash" \
+ ${RM} ${DEST_PREFIX}/share/bash-completion/completions/bfs
+ ${MSG} "[ RM ] completions/bfs.zsh" \
+ ${RM} ${DEST_PREFIX}/share/zsh/site-functions/_bfs
+ ${MSG} "[ RM ] completions/bfs.fish" \
+ ${RM} ${DEST_PREFIX}/share/fish/vendor_completions.d/bfs.fish
+ ${MSG} "[ RM ] man/man1/bfs.1" \
+ ${RM} ${DEST_MANDIR}/man1/bfs.1
+ ${MSG} "[ RM ] bin/bfs" \
+ ${RM} ${DEST_PREFIX}/bin/bfs
+
+# Check that `make install` works and `make uninstall` removes everything
+check-install::
+ +${MAKE} install DESTDIR=pkg
+ +${MAKE} uninstall DESTDIR=pkg
+ bin/bfs pkg -not -type d -print -exit 1
+ ${RM} -r pkg
+
+## Cleanup (`make clean`)
+
+# Clean all build products
+clean::
+ ${MSG} "[ RM ] bin obj" \
+ ${RM} -r bin obj
+
+# Clean everything, including generated files
+distclean: clean
+ ${MSG} "[ RM ] gen" \
+ ${RM} -r gen ${DISTCHECKS}
+.PHONY: distclean