1 # Copyright © Tavian Barnes <tavianator@tavianator.com>
2 # SPDX-License-Identifier: 0BSD
4 ifneq ($(wildcard .git),)
5 VERSION := $(shell git describe --always 2>/dev/null)
17 ARCH := $(shell uname -m)
28 MANDIR ?= $(PREFIX)/share/man
30 BIN := $(BUILDDIR)/bin
31 OBJ := $(BUILDDIR)/obj
38 -Wimplicit-fallthrough \
39 -Wmissing-declarations \
44 CFLAGS ?= $(DEFAULT_CFLAGS)
46 DEPFLAGS ?= -MD -MP -MF $(@:.o=.d)
55 -D_LARGEFILE64_SOURCE \
56 -D_FILE_OFFSET_BITS=64 \
58 -DBFS_VERSION=\"$(VERSION)\"
60 LOCAL_CFLAGS := -std=c17 -pthread
64 ASAN := $(filter asan,$(MAKECMDGOALS))
65 LSAN := $(filter lsan,$(MAKECMDGOALS))
66 MSAN := $(filter msan,$(MAKECMDGOALS))
67 TSAN := $(filter tsan,$(MAKECMDGOALS))
68 UBSAN := $(filter ubsan,$(MAKECMDGOALS))
71 LOCAL_CFLAGS += -fsanitize=address
76 LOCAL_CFLAGS += -fsanitize=leak
81 # msan needs all code instrumented
83 LOCAL_CFLAGS += -fsanitize=memory -fsanitize-memory-track-origins
88 # tsan needs all code instrumented
90 # https://github.com/google/sanitizers/issues/342
91 LOCAL_CPPFLAGS += -DBFS_USE_TARGET_CLONES=0
92 LOCAL_CFLAGS += -fsanitize=thread
97 LOCAL_CFLAGS += -fsanitize=undefined
102 LOCAL_CFLAGS += -fno-sanitize-recover=all
110 LOCAL_CPPFLAGS += -DBFS_USE_ONIGURUMA=1
112 ONIG_CONFIG := $(shell command -v onig-config 2>/dev/null)
114 ONIG_CFLAGS := $(shell $(ONIG_CONFIG) --cflags)
115 ONIG_LDLIBS := $(shell $(ONIG_CONFIG) --libs)
117 ONIG_LDLIBS := -lonig
120 LOCAL_CFLAGS += $(ONIG_CFLAGS)
121 LOCAL_LDLIBS += $(ONIG_LDLIBS)
122 endif # USE_ONIGURUMA
132 LOCAL_LDLIBS += -lacl
134 LOCAL_CPPFLAGS += -DBFS_USE_SYS_ACL_H=0
138 LOCAL_LDLIBS += -lattr
140 LOCAL_CPPFLAGS += -DBFS_USE_SYS_XATTR_H=0
144 LOCAL_LDLIBS += -lcap
146 LOCAL_CPPFLAGS += -DBFS_USE_SYS_CAPABILITY_H=0
149 LOCAL_LDFLAGS += -Wl,--as-needed
154 LOCAL_LDLIBS += -lutil
157 ifneq ($(filter gcov,$(MAKECMDGOALS)),)
158 LOCAL_CFLAGS += --coverage
159 # gcov only intercepts fork()/exec() with -std=gnu*
160 LOCAL_CFLAGS := $(patsubst -std=c%,-std=gnu%,$(LOCAL_CFLAGS))
163 ifneq ($(filter release,$(MAKECMDGOALS)),)
164 LOCAL_CPPFLAGS += -DNDEBUG
165 CFLAGS := $(DEFAULT_CFLAGS) -O3 -flto=auto
168 ALL_CPPFLAGS = $(LOCAL_CPPFLAGS) $(CPPFLAGS) $(EXTRA_CPPFLAGS)
169 ALL_CFLAGS = $(ALL_CPPFLAGS) $(LOCAL_CFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS)
170 ALL_LDFLAGS = $(ALL_CFLAGS) $(LOCAL_LDFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS)
171 ALL_LDLIBS = $(LOCAL_LDLIBS) $(LDLIBS) $(EXTRA_LDLIBS)
173 # Default make target
177 # Goals that are treated like flags by this makefile
178 FLAG_GOALS := asan lsan msan tsan ubsan gcov release
180 # These are the remaining non-flag goals
181 GOALS := $(filter-out $(FLAG_GOALS),$(MAKECMDGOALS))
183 # Build the default goal if only flag goals are specified
189 # Make sure that "make release" builds everything, but "make release obj/src/main.o" doesn't
190 $(FLAG_GOALS): $(FLAG_PREREQS)
192 .PHONY: $(FLAG_GOALS)
199 +$(CC) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
200 ifeq ($(OS) $(SANITIZE),FreeBSD y)
204 $(OBJ)/%.o: %.c $(OBJ)/FLAGS
206 $(CC) $(ALL_CFLAGS) -c $< -o $@
208 # Save the full set of flags to rebuild everything when they change
211 @echo $(CC) : $(ALL_CFLAGS) : $(ALL_LDFLAGS) : $(ALL_LDLIBS) >$@
212 .PHONY: $(OBJ)/FLAGS.new
214 # Only update obj/FLAGS if obj/FLAGS.new is different
215 $(OBJ)/FLAGS: $(OBJ)/FLAGS.new
216 @test -e $@ && cmp -s $@ $< && rm $< || mv $< $@
218 # All object files except the entry point
226 $(OBJ)/src/darray.o \
229 $(OBJ)/src/dstring.o \
237 $(OBJ)/src/printf.o \
238 $(OBJ)/src/pwcache.o \
242 $(OBJ)/src/xregex.o \
243 $(OBJ)/src/xspawn.o \
246 # The main executable
247 $(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS)
249 # Standalone unit tests
250 UNITS := alloc bfstd bit trie xtimegm
251 UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%)
252 UNIT_CHECKS := $(UNITS:%=check-%)
255 TEST_UTILS := $(BIN)/tests/mksock $(BIN)/tests/xtouch
257 TESTS := $(UNIT_TESTS) $(TEST_UTILS)
262 $(TESTS): $(BIN)/tests/%: $(OBJ)/tests/%.o $(LIBBFS)
264 # The different search strategies that we test
265 STRATEGIES := bfs dfs ids eds
266 STRATEGY_CHECKS := $(STRATEGIES:%=check-%)
268 # All the different checks we run
269 CHECKS := $(UNIT_CHECKS) $(STRATEGY_CHECKS)
272 .PHONY: check $(CHECKS)
274 $(UNIT_CHECKS): check-%: $(BIN)/tests/%
277 $(STRATEGY_CHECKS): check-%: $(BIN)/bfs $(TEST_UTILS)
278 ./tests/tests.sh --bfs="$(BIN)/bfs -S $*" $(TEST_FLAGS)
280 # Custom test flags for distcheck
281 DISTCHECK_FLAGS := -s TEST_FLAGS="--sudo --verbose=skipped"
284 +$(MAKE) -B asan ubsan check $(DISTCHECK_FLAGS)
286 +$(MAKE) -B msan ubsan check CC=clang $(DISTCHECK_FLAGS)
288 +$(MAKE) -B tsan ubsan check CC=clang $(DISTCHECK_FLAGS)
289 ifeq ($(OS) $(ARCH),Linux x86_64)
290 +$(MAKE) -B check EXTRA_CFLAGS="-m32" ONIG_CONFIG= $(DISTCHECK_FLAGS)
292 +$(MAKE) -B release check $(DISTCHECK_FLAGS)
293 +$(MAKE) -B check $(DISTCHECK_FLAGS)
294 +$(MAKE) check-install $(DISTCHECK_FLAGS)
298 $(RM) -r $(BIN) $(OBJ)
302 $(MKDIR) $(DESTDIR)$(PREFIX)/bin
303 $(INSTALL) -m755 $(BIN)/bfs $(DESTDIR)$(PREFIX)/bin/bfs
304 $(MKDIR) $(DESTDIR)$(MANDIR)/man1
305 $(INSTALL) -m644 docs/bfs.1 $(DESTDIR)$(MANDIR)/man1/bfs.1
306 $(MKDIR) $(DESTDIR)$(PREFIX)/share/bash-completion/completions
307 $(INSTALL) -m644 completions/bfs.bash $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
308 $(MKDIR) $(DESTDIR)$(PREFIX)/share/zsh/site-functions
309 $(INSTALL) -m644 completions/bfs.zsh $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_bfs
310 $(MKDIR) $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d
311 $(INSTALL) -m644 completions/bfs.fish $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/bfs.fish
315 $(RM) $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
316 $(RM) $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_bfs
317 $(RM) $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/bfs.fish
318 $(RM) $(DESTDIR)$(MANDIR)/man1/bfs.1
319 $(RM) $(DESTDIR)$(PREFIX)/bin/bfs
323 +$(MAKE) install DESTDIR=$(BUILDDIR)/pkg
324 +$(MAKE) uninstall DESTDIR=$(BUILDDIR)/pkg
325 $(BIN)/bfs $(BUILDDIR)/pkg -not -type d -print -exit 1
326 $(RM) -r $(BUILDDIR)/pkg
327 .PHONY: check-install
331 -include $(wildcard $(OBJ)/*/*.d)