-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMakefile
More file actions
127 lines (106 loc) · 4.74 KB
/
Copy pathMakefile
File metadata and controls
127 lines (106 loc) · 4.74 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# clibase - layered-architecture CLI template using sparcli.
#
# make build bin/clibase
# make run build and run it (pass arguments with ARGS=...)
# make test build and run the test suite
# make sanitize run the tests under AddressSanitizer/UBSan
# make compdb write compile_commands.json for clangd
# make clean remove build artefacts
#
# Strict mode (treat warnings as errors): make EXTRA_CXXFLAGS=-Werror
CXX ?= c++
# -Wno-missing-designated-field-initializers: sparcli's zero-init-friendly
# *Opts structs are meant to be brace-initialized with only the fields you
# set; the rest default to zero. This (non-default) warning is incompatible
# with that idiom (it even fires inside sparcli's own headers), so silence it.
CXXFLAGS ?= -std=c++26 -Wall -Wextra -Wpedantic -Wshadow \
-Wno-missing-designated-field-initializers
CXXFLAGS += $(EXTRA_CXXFLAGS)
CPPFLAGS += -Isrc
# sparcli is resolved through pkg-config by default. clibase needs a sparcli
# version that includes the framework modules (argument parser, logging, XDG
# paths) - i.e. the umbrella header must include args/sparcli_args.h. To
# build against a local checkout without installing, override both variables:
# make SPARCLI_CFLAGS=-I/path/to/sparcli/include \
# SPARCLI_LIBS=/path/to/sparcli/libsparcli.a
#
# sparcli is linked statically by default (the static archive from pkg-config's
# libdir): a dynamic link is fragile because the installed dylib's install_name
# need not match its install prefix, leaving the binary unable to locate it at
# run time. Pass SPARCLI_LIBS explicitly to link some other way.
SPARCLI_CFLAGS ?= $(shell pkg-config --cflags sparcli 2>/dev/null)
SPARCLI_LIBDIR := $(shell pkg-config --variable=libdir sparcli 2>/dev/null)
ifneq ($(strip $(SPARCLI_LIBDIR)),)
SPARCLI_LIBS ?= $(SPARCLI_LIBDIR)/libsparcli.a
endif
ifeq ($(strip $(SPARCLI_LIBS)),)
$(error sparcli not found via pkg-config. Install it (run `make install` in \
the sparcli repo) or pass SPARCLI_CFLAGS / SPARCLI_LIBS - see \
docs/development.md)
endif
# Include sparcli as a system header (-isystem) so that -Wpedantic and other
# strict warnings apply to this project's code only, not to sparcli's C
# headers (which legitimately use C99/C11 features that C++ flags as
# extensions).
CPPFLAGS += $(patsubst -I%,-isystem %,$(SPARCLI_CFLAGS))
BIN := bin/mdtask
# `.nosync` keeps the build trees out of file-syncing tools (iCloud, etc.).
BUILD ?= build.nosync
SANITIZE_BUILD := build-sanitize.nosync
SRC := $(shell find src -name '*.cpp')
OBJ := $(SRC:%.cpp=$(BUILD)/%.o)
# Application objects minus the entry point, reused by the test runner.
APP_OBJ := $(filter-out $(BUILD)/src/main.o,$(OBJ))
TEST_SRC := $(wildcard tests/*.cpp)
TEST_OBJ := $(TEST_SRC:%.cpp=$(BUILD)/%.o)
TEST_BIN := $(BUILD)/test_runner
DEPS := $(OBJ:.o=.d) $(TEST_OBJ:.o=.d)
.PHONY: all run test sanitize clean compdb
all: $(BIN)
$(BIN): $(OBJ)
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(OBJ) $(SPARCLI_LIBS) -o $@
# Pass arguments with ARGS, e.g. make run ARGS='add "Buy milk"'
run: $(BIN)
./$(BIN) $(ARGS)
# Test objects also need the test-only headers in tests/.
$(BUILD)/tests/%.o: CPPFLAGS += -Itests
$(BUILD)/%.o: %.cpp
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -MMD -MP -c $< -o $@
test: $(TEST_BIN)
./$(TEST_BIN)
$(TEST_BIN): $(APP_OBJ) $(TEST_OBJ)
@mkdir -p $(dir $@)
$(CXX) $(CXXFLAGS) $(APP_OBJ) $(TEST_OBJ) $(SPARCLI_LIBS) -o $@
# Sanitizer objects are incompatible with normal ones, so they get their own
# build directory - a plain `make` afterwards keeps working without a clean.
sanitize:
$(MAKE) test BUILD=$(SANITIZE_BUILD) \
EXTRA_CXXFLAGS="-fsanitize=address,undefined -g $(EXTRA_CXXFLAGS)"
# Generate compile_commands.json for clangd/editors - no external tools
# needed. It records the real compile flags (including the pkg-config include
# paths, so any sparcli install prefix is resolved without hard-coding it).
# clangd prefers this over compile_flags.txt. Re-run after changing flags or
# moving the sparcli install. compile_commands.json is machine-specific and
# git-ignored.
compdb:
@{ \
printf '[\n'; \
first=1; \
for f in $(SRC); do \
[ $$first = 1 ] && first=0 || printf ',\n'; \
printf ' {"directory": "%s", "file": "%s", "command": "%s %s %s -c %s"}' \
"$(CURDIR)" "$$f" "$(CXX)" "$(CXXFLAGS)" "$(CPPFLAGS)" "$$f"; \
done; \
for f in $(TEST_SRC); do \
printf ',\n'; \
printf ' {"directory": "%s", "file": "%s", "command": "%s %s %s -Itests -c %s"}' \
"$(CURDIR)" "$$f" "$(CXX)" "$(CXXFLAGS)" "$(CPPFLAGS)" "$$f"; \
done; \
printf '\n]\n'; \
} > compile_commands.json
@echo "wrote compile_commands.json"
clean:
rm -rf $(BUILD) $(SANITIZE_BUILD) bin
-include $(DEPS)