]> Sergey Matveev's repositories - bfs.git/blob - GNUmakefile
dstring: New dchar typedef for dynamic strings
[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.2
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
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 endif
130
131 ifdef USE_ACL
132 LOCAL_LDLIBS += -lacl
133 else
134 LOCAL_CPPFLAGS += -DBFS_USE_SYS_ACL_H=0
135 endif
136
137 ifdef USE_ATTR
138 LOCAL_LDLIBS += -lattr
139 else
140 LOCAL_CPPFLAGS += -DBFS_USE_SYS_XATTR_H=0
141 endif
142
143 ifdef USE_LIBCAP
144 LOCAL_LDLIBS += -lcap
145 else
146 LOCAL_CPPFLAGS += -DBFS_USE_SYS_CAPABILITY_H=0
147 endif
148
149 LOCAL_LDFLAGS += -Wl,--as-needed
150 LOCAL_LDLIBS += -lrt
151 endif # Linux
152
153 ifeq ($(OS),NetBSD)
154 LOCAL_LDLIBS += -lutil
155 endif
156
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))
161 endif
162
163 ifneq ($(filter release,$(MAKECMDGOALS)),)
164 LOCAL_CPPFLAGS += -DNDEBUG
165 CFLAGS := $(DEFAULT_CFLAGS) -O3 -flto=auto
166 endif
167
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)
172
173 # Default make target
174 bfs: $(BIN)/bfs
175 .PHONY: bfs
176
177 # Goals that are treated like flags by this makefile
178 FLAG_GOALS := asan lsan msan tsan ubsan gcov release
179
180 # These are the remaining non-flag goals
181 GOALS := $(filter-out $(FLAG_GOALS),$(MAKECMDGOALS))
182
183 # Build the default goal if only flag goals are specified
184 FLAG_PREREQS :=
185 ifndef GOALS
186 FLAG_PREREQS += bfs
187 endif
188
189 # Make sure that "make release" builds everything, but "make release obj/src/main.o" doesn't
190 $(FLAG_GOALS): $(FLAG_PREREQS)
191         @:
192 .PHONY: $(FLAG_GOALS)
193
194 all: bfs tests
195 .PHONY: all
196
197 $(BIN)/%:
198         @$(MKDIR) $(@D)
199         +$(CC) $(ALL_LDFLAGS) $^ $(ALL_LDLIBS) -o $@
200 ifeq ($(OS) $(SANITIZE),FreeBSD y)
201         elfctl -e +noaslr $@
202 endif
203
204 $(OBJ)/%.o: %.c $(OBJ)/FLAGS
205         @$(MKDIR) $(@D)
206         $(CC) $(ALL_CFLAGS) -c $< -o $@
207
208 # Save the full set of flags to rebuild everything when they change
209 $(OBJ)/FLAGS.new:
210         @$(MKDIR) $(@D)
211         @echo $(CC) : $(ALL_CFLAGS) : $(ALL_LDFLAGS) : $(ALL_LDLIBS) >$@
212 .PHONY: $(OBJ)/FLAGS.new
213
214 # Only update obj/FLAGS if obj/FLAGS.new is different
215 $(OBJ)/FLAGS: $(OBJ)/FLAGS.new
216         @test -e $@ && cmp -s $@ $< && rm $< || mv $< $@
217
218 # All object files except the entry point
219 LIBBFS := \
220     $(OBJ)/src/alloc.o \
221     $(OBJ)/src/bar.o \
222     $(OBJ)/src/bfstd.o \
223     $(OBJ)/src/bftw.o \
224     $(OBJ)/src/color.o \
225     $(OBJ)/src/ctx.o \
226     $(OBJ)/src/darray.o \
227     $(OBJ)/src/diag.o \
228     $(OBJ)/src/dir.o \
229     $(OBJ)/src/dstring.o \
230     $(OBJ)/src/eval.o \
231     $(OBJ)/src/exec.o \
232     $(OBJ)/src/fsade.o \
233     $(OBJ)/src/ioq.o \
234     $(OBJ)/src/mtab.o \
235     $(OBJ)/src/opt.o \
236     $(OBJ)/src/parse.o \
237     $(OBJ)/src/printf.o \
238     $(OBJ)/src/pwcache.o \
239     $(OBJ)/src/stat.o \
240     $(OBJ)/src/trie.o \
241     $(OBJ)/src/typo.o \
242     $(OBJ)/src/xregex.o \
243     $(OBJ)/src/xspawn.o \
244     $(OBJ)/src/xtime.o
245
246 # The main executable
247 $(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS)
248
249 # Standalone unit tests
250 UNITS := alloc bfstd bit trie xtimegm
251 UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%)
252 UNIT_CHECKS := $(UNITS:%=check-%)
253
254 # Testing utilities
255 TEST_UTILS := $(BIN)/tests/mksock $(BIN)/tests/xtouch
256
257 TESTS := $(UNIT_TESTS) $(TEST_UTILS)
258
259 tests: $(TESTS)
260 .PHONY: tests
261
262 $(TESTS): $(BIN)/tests/%: $(OBJ)/tests/%.o $(LIBBFS)
263
264 # The different search strategies that we test
265 STRATEGIES := bfs dfs ids eds
266 STRATEGY_CHECKS := $(STRATEGIES:%=check-%)
267
268 # All the different checks we run
269 CHECKS := $(UNIT_CHECKS) $(STRATEGY_CHECKS)
270
271 check: $(CHECKS)
272 .PHONY: check $(CHECKS)
273
274 $(UNIT_CHECKS): check-%: $(BIN)/tests/%
275         $<
276
277 $(STRATEGY_CHECKS): check-%: $(BIN)/bfs $(TEST_UTILS)
278         ./tests/tests.sh --bfs="$(BIN)/bfs -S $*" $(TEST_FLAGS)
279
280 # Custom test flags for distcheck
281 DISTCHECK_FLAGS := -s TEST_FLAGS="--sudo --verbose=skipped"
282
283 distcheck:
284         +$(MAKE) -B asan ubsan check $(DISTCHECK_FLAGS)
285 ifneq ($(OS),Darwin)
286         +$(MAKE) -B msan ubsan check CC=clang $(DISTCHECK_FLAGS)
287 endif
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)
291 endif
292         +$(MAKE) -B release check $(DISTCHECK_FLAGS)
293         +$(MAKE) -B check $(DISTCHECK_FLAGS)
294         +$(MAKE) check-install $(DISTCHECK_FLAGS)
295 .PHONY: distcheck
296
297 clean:
298         $(RM) -r $(BIN) $(OBJ)
299 .PHONY: clean
300
301 install:
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
312 .PHONY: install
313
314 uninstall:
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
320 .PHONY: uninstall
321
322 check-install:
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
328
329 .SUFFIXES:
330
331 -include $(wildcard $(OBJ)/*/*.d)