]> Sergey Matveev's repositories - bfs.git/blob - GNUmakefile
Skip mtab
[bfs.git] / GNUmakefile
1 # Copyright © Tavian Barnes <tavianator@tavianator.com>
2 # SPDX-License-Identifier: 0BSD
3
4 ifneq ($(wildcard .git),)
5 VERSION := $(shell git describe --always 2>/dev/null)
6 endif
7
8 ifndef VERSION
9 VERSION := 3.0.4
10 endif
11
12 ifndef OS
13 OS := $(shell uname)
14 endif
15
16 ifndef ARCH
17 ARCH := $(shell uname -m)
18 endif
19
20 CC ?= gcc
21 INSTALL ?= install
22 MKDIR ?= mkdir -p
23 RM ?= rm -f
24
25 export BUILDDIR ?= .
26 DESTDIR ?=
27 PREFIX ?= /usr
28 MANDIR ?= $(PREFIX)/share/man
29
30 BIN := $(BUILDDIR)/bin
31 OBJ := $(BUILDDIR)/obj
32
33 DEFAULT_CFLAGS := \
34     -g \
35     -Wall \
36     -Wformat=2 \
37     -Werror=implicit \
38     -Wimplicit-fallthrough \
39     -Wmissing-declarations \
40     -Wshadow \
41     -Wsign-compare \
42     -Wstrict-prototypes
43
44 CFLAGS ?= $(DEFAULT_CFLAGS)
45 LDFLAGS ?=
46 DEPFLAGS ?= -MD -MP -MF $(@:.o=.d)
47
48 LOCAL_CPPFLAGS := \
49     -D__EXTENSIONS__ \
50     -D_ATFILE_SOURCE \
51     -D_BSD_SOURCE \
52     -D_DARWIN_C_SOURCE \
53     -D_DEFAULT_SOURCE \
54     -D_GNU_SOURCE \
55     -D_LARGEFILE64_SOURCE \
56     -D_FILE_OFFSET_BITS=64 \
57     -D_TIME_BITS=64 \
58     -DBFS_VERSION=\"$(VERSION)\"
59
60 LOCAL_CFLAGS := -std=c17 -pthread -static
61 LOCAL_LDFLAGS :=
62 LOCAL_LDLIBS :=
63
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))
69
70 ifdef ASAN
71 LOCAL_CFLAGS += -fsanitize=address
72 SANITIZE := y
73 endif
74
75 ifdef LSAN
76 LOCAL_CFLAGS += -fsanitize=leak
77 SANITIZE := y
78 endif
79
80 ifdef MSAN
81 # msan needs all code instrumented
82 NOLIBS := y
83 LOCAL_CFLAGS += -fsanitize=memory -fsanitize-memory-track-origins
84 SANITIZE := y
85 endif
86
87 ifdef TSAN
88 # tsan needs all code instrumented
89 NOLIBS := y
90 # https://github.com/google/sanitizers/issues/342
91 LOCAL_CPPFLAGS += -DBFS_USE_TARGET_CLONES=0
92 LOCAL_CFLAGS += -fsanitize=thread
93 SANITIZE := y
94 endif
95
96 ifdef UBSAN
97 LOCAL_CFLAGS += -fsanitize=undefined
98 SANITIZE := y
99 endif
100
101 ifdef SANITIZE
102 LOCAL_CFLAGS += -fno-sanitize-recover=all
103 endif
104
105 ifndef NOLIBS
106 USE_ONIGURUMA := y
107 endif
108
109 ifdef USE_ONIGURUMA
110 LOCAL_CPPFLAGS += -DBFS_USE_ONIGURUMA=1
111
112 ONIG_CONFIG := $(shell command -v onig-config 2>/dev/null)
113 ifdef ONIG_CONFIG
114 ONIG_CFLAGS := $(shell $(ONIG_CONFIG) --cflags)
115 ONIG_LDLIBS := $(shell $(ONIG_CONFIG) --libs)
116 else
117 ONIG_LDLIBS := -lonig
118 endif
119
120 LOCAL_CFLAGS += $(ONIG_CFLAGS)
121 LOCAL_LDLIBS += $(ONIG_LDLIBS)
122 endif # USE_ONIGURUMA
123
124 ifeq ($(OS),Linux)
125 ifndef NOLIBS
126 USE_ACL := y
127 USE_ATTR := y
128 USE_LIBCAP := y
129 USE_LIBURING := y
130 endif
131
132 ifdef USE_ACL
133 LOCAL_LDLIBS += -lacl
134 else
135 LOCAL_CPPFLAGS += -DBFS_USE_SYS_ACL_H=0
136 endif
137
138 ifdef USE_ATTR
139 LOCAL_LDLIBS += -lattr
140 else
141 LOCAL_CPPFLAGS += -DBFS_USE_SYS_XATTR_H=0
142 endif
143
144 ifdef USE_LIBCAP
145 LOCAL_LDLIBS += -lcap
146 else
147 LOCAL_CPPFLAGS += -DBFS_USE_SYS_CAPABILITY_H=0
148 endif
149
150 ifdef USE_LIBURING
151 LOCAL_CPPFLAGS += -DBFS_USE_LIBURING=1
152 LOCAL_LDLIBS += -luring
153 endif
154
155 LOCAL_LDFLAGS += -Wl,--as-needed
156 LOCAL_LDLIBS += -lrt
157 endif # Linux
158
159 ifeq ($(OS),NetBSD)
160 LOCAL_LDLIBS += -lutil
161 endif
162
163 ifneq ($(filter gcov,$(MAKECMDGOALS)),)
164 LOCAL_CFLAGS += --coverage
165 # gcov only intercepts fork()/exec() with -std=gnu*
166 LOCAL_CFLAGS := $(patsubst -std=c%,-std=gnu%,$(LOCAL_CFLAGS))
167 endif
168
169 ifneq ($(filter lint,$(MAKECMDGOALS)),)
170 LOCAL_CPPFLAGS += \
171     -D_FORTIFY_SOURCE=3 \
172     -DBFS_LINT
173 LOCAL_CFLAGS += -Werror -O2
174 endif
175
176 ifneq ($(filter release,$(MAKECMDGOALS)),)
177 LOCAL_CPPFLAGS += -DNDEBUG
178 CFLAGS := $(DEFAULT_CFLAGS) -O3 -flto=auto
179 endif
180
181 ALL_CPPFLAGS = $(LOCAL_CPPFLAGS) $(CPPFLAGS) $(EXTRA_CPPFLAGS)
182 ALL_CFLAGS = $(ALL_CPPFLAGS) $(LOCAL_CFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) $(DEPFLAGS)
183 ALL_LDFLAGS = $(ALL_CFLAGS) $(LOCAL_LDFLAGS) $(LDFLAGS) $(EXTRA_LDFLAGS)
184 ALL_LDLIBS = $(LOCAL_LDLIBS) $(LDLIBS) $(EXTRA_LDLIBS)
185
186 # Default make target
187 bfs: $(BIN)/bfs
188 .PHONY: bfs
189
190 # Goals that are treated like flags by this makefile
191 FLAG_GOALS := asan lsan msan tsan ubsan gcov lint release
192
193 # These are the remaining non-flag goals
194 GOALS := $(filter-out $(FLAG_GOALS),$(MAKECMDGOALS))
195
196 # Build the default goal if only flag goals are specified
197 FLAG_PREREQS :=
198 ifndef GOALS
199 FLAG_PREREQS += bfs
200 endif
201
202 # Make sure that "make release" builds everything, but "make release obj/src/main.o" doesn't
203 $(FLAG_GOALS): $(FLAG_PREREQS)
204         @:
205 .PHONY: $(FLAG_GOALS)
206
207 all: bfs tests
208 .PHONY: all
209
210 $(BIN)/%:
211         @$(MKDIR) $(@D)
212         +$(CC) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
213 ifeq ($(OS) $(SANITIZE),FreeBSD y)
214         elfctl -e +noaslr $@
215 endif
216
217 $(OBJ)/%.o: %.c $(OBJ)/FLAGS
218         @$(MKDIR) $(@D)
219         $(CC) $(ALL_CFLAGS) -c $< -o $@
220
221 # Save the full set of flags to rebuild everything when they change
222 $(OBJ)/FLAGS.new:
223         @$(MKDIR) $(@D)
224         @echo $(CC) : $(ALL_CFLAGS) : $(ALL_LDFLAGS) : $(ALL_LDLIBS) >$@
225 .PHONY: $(OBJ)/FLAGS.new
226
227 # Only update obj/FLAGS if obj/FLAGS.new is different
228 $(OBJ)/FLAGS: $(OBJ)/FLAGS.new
229         @test -e $@ && cmp -s $@ $< && rm $< || mv $< $@
230
231 # All object files except the entry point
232 LIBBFS := \
233     $(OBJ)/src/alloc.o \
234     $(OBJ)/src/bar.o \
235     $(OBJ)/src/bfstd.o \
236     $(OBJ)/src/bftw.o \
237     $(OBJ)/src/color.o \
238     $(OBJ)/src/ctx.o \
239     $(OBJ)/src/darray.o \
240     $(OBJ)/src/diag.o \
241     $(OBJ)/src/dir.o \
242     $(OBJ)/src/dstring.o \
243     $(OBJ)/src/eval.o \
244     $(OBJ)/src/exec.o \
245     $(OBJ)/src/fsade.o \
246     $(OBJ)/src/ioq.o \
247     $(OBJ)/src/mtab.o \
248     $(OBJ)/src/opt.o \
249     $(OBJ)/src/parse.o \
250     $(OBJ)/src/printf.o \
251     $(OBJ)/src/pwcache.o \
252     $(OBJ)/src/stat.o \
253     $(OBJ)/src/thread.o \
254     $(OBJ)/src/trie.o \
255     $(OBJ)/src/typo.o \
256     $(OBJ)/src/xregex.o \
257     $(OBJ)/src/xspawn.o \
258     $(OBJ)/src/xtime.o
259
260 # The main executable
261 $(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS)
262
263 # Standalone unit tests
264 UNITS := alloc bfstd bit trie xtimegm
265 UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%)
266 UNIT_CHECKS := $(UNITS:%=check-%)
267
268 # Testing utilities
269 TEST_UTILS := $(BIN)/tests/mksock $(BIN)/tests/xtouch
270
271 TESTS := $(UNIT_TESTS) $(TEST_UTILS)
272
273 tests: $(TESTS)
274 .PHONY: tests
275
276 $(TESTS): $(BIN)/tests/%: $(OBJ)/tests/%.o $(LIBBFS)
277
278 # The different search strategies that we test
279 STRATEGIES := bfs dfs ids eds
280 STRATEGY_CHECKS := $(STRATEGIES:%=check-%)
281
282 # All the different checks we run
283 CHECKS := $(UNIT_CHECKS) $(STRATEGY_CHECKS)
284
285 check: $(CHECKS)
286 .PHONY: check $(CHECKS)
287
288 $(UNIT_CHECKS): check-%: $(BIN)/tests/%
289         $<
290
291 JOBS := $(filter -j%,$(MAKEFLAGS))
292 ifndef JOBS
293         JOBS := -j1
294 endif
295
296 $(STRATEGY_CHECKS): check-%: $(BIN)/bfs $(TEST_UTILS)
297         ./tests/tests.sh $(JOBS) --bfs="$(BIN)/bfs -S $*" $(TEST_FLAGS)
298
299 # Custom test flags for distcheck
300 DISTCHECK_FLAGS := -s TEST_FLAGS="--sudo --verbose=skipped"
301
302 distcheck:
303         +$(MAKE) -B asan ubsan check $(DISTCHECK_FLAGS)
304 ifneq ($(OS),Darwin)
305         +$(MAKE) -B msan ubsan check CC=clang $(DISTCHECK_FLAGS)
306 endif
307         +$(MAKE) -B tsan ubsan check CC=clang $(DISTCHECK_FLAGS)
308 ifeq ($(OS) $(ARCH),Linux x86_64)
309         +$(MAKE) -B check EXTRA_CFLAGS="-m32" ONIG_CONFIG= USE_LIBURING= $(DISTCHECK_FLAGS)
310 endif
311         +$(MAKE) -B release check $(DISTCHECK_FLAGS)
312         +$(MAKE) -B check $(DISTCHECK_FLAGS)
313         +$(MAKE) check-install $(DISTCHECK_FLAGS)
314 .PHONY: distcheck
315
316 clean:
317         $(RM) -r $(BIN) $(OBJ)
318 .PHONY: clean
319
320 install:
321         $(MKDIR) $(DESTDIR)$(PREFIX)/bin
322         $(INSTALL) -m755 $(BIN)/bfs $(DESTDIR)$(PREFIX)/bin/bfs
323         $(MKDIR) $(DESTDIR)$(MANDIR)/man1
324         $(INSTALL) -m644 docs/bfs.1 $(DESTDIR)$(MANDIR)/man1/bfs.1
325         $(MKDIR) $(DESTDIR)$(PREFIX)/share/bash-completion/completions
326         $(INSTALL) -m644 completions/bfs.bash $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
327         $(MKDIR) $(DESTDIR)$(PREFIX)/share/zsh/site-functions
328         $(INSTALL) -m644 completions/bfs.zsh $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_bfs
329         $(MKDIR) $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d
330         $(INSTALL) -m644 completions/bfs.fish $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/bfs.fish
331 .PHONY: install
332
333 uninstall:
334         $(RM) $(DESTDIR)$(PREFIX)/share/bash-completion/completions/bfs
335         $(RM) $(DESTDIR)$(PREFIX)/share/zsh/site-functions/_bfs
336         $(RM) $(DESTDIR)$(PREFIX)/share/fish/vendor_completions.d/bfs.fish
337         $(RM) $(DESTDIR)$(MANDIR)/man1/bfs.1
338         $(RM) $(DESTDIR)$(PREFIX)/bin/bfs
339 .PHONY: uninstall
340
341 check-install:
342         +$(MAKE) install DESTDIR=$(BUILDDIR)/pkg
343         +$(MAKE) uninstall DESTDIR=$(BUILDDIR)/pkg
344         $(BIN)/bfs $(BUILDDIR)/pkg -not -type d -print -exit 1
345         $(RM) -r $(BUILDDIR)/pkg
346 .PHONY: check-install
347
348 .SUFFIXES:
349
350 -include $(wildcard $(OBJ)/*/*.d)