VERSION := 0.2.0 SOVERSION := 1 CC ?= cc AR ?= ar CLANG_TIDY ?= clang-tidy FORMAT ?= clang-format PREFIX ?= /usr/local LIBDIR ?= $(PREFIX)/lib INCLUDEDIR ?= $(PREFIX)/include BINDIR ?= $(PREFIX)/bin FEATURES := -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -D_DEFAULT_SOURCE WARNINGS := -Wall -Wextra -Wpedantic -Wshadow -Wstrict-prototypes \ -Wmissing-prototypes -Wold-style-definition -Wvla \ -Wpointer-arith -Wcast-qual -Wredundant-decls SAN := -fsanitize=address,undefined -fno-omit-frame-pointer \ -fno-sanitize-recover=all CPPFLAGS += -Iinclude -Isrc $(FEATURES) CFLAGS ?= -O2 -g CFLAGS += -std=c11 $(WARNINGS) $(EXTRA_CFLAGS) LDFLAGS += $(EXTRA_LDFLAGS) LDLIBS += -lcurl -lm BUILD := build LIB_SRC := src/client.c src/model.c src/util.c src/json.c src/csv.c LIB_OBJ := $(LIB_SRC:%.c=$(BUILD)/%.o) PIC_OBJ := $(LIB_SRC:%.c=$(BUILD)/%.pic.o) TEST_SRC := tests/test_cepis.c tests/test_server.c TEST_OBJ := $(TEST_SRC:%.c=$(BUILD)/%.o) ALL_SRC := $(LIB_SRC) src/cli.c $(TEST_SRC) ALL_HDR := include/cepis.h src/internal.h src/json.h src/csv.h \ tests/test_server.h STATIC := $(BUILD)/libcepis.a SHARED := $(BUILD)/libcepis.so.$(VERSION) CLI := $(BUILD)/cepis TESTS := $(BUILD)/test_cepis .DEFAULT_GOAL := help .PHONY: help build test lint format check clean memcheck sanitize install \ uninstall help: @echo 'Targets:' @echo ' build static and shared libraries, plus the cepis CLI' @echo ' test build and run the suite against a local HTTP server' @echo ' lint clang-format --dry-run + clang-tidy (read-only)' @echo ' format apply clang-format (writes)' @echo ' check lint, then test, then build' @echo ' memcheck run the suite under valgrind' @echo ' sanitize rebuild and run the suite under ASan + UBSan' @echo ' install install headers, libraries and the CLI under PREFIX' @echo ' clean remove $(BUILD)/' @echo @echo 'Override the compiler with e.g. make test CC=clang' build: $(STATIC) $(SHARED) $(CLI) $(BUILD)/%.o: %.c @mkdir -p $(dir $@) $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ $(BUILD)/%.pic.o: %.c @mkdir -p $(dir $@) $(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -c $< -o $@ $(STATIC): $(LIB_OBJ) @mkdir -p $(dir $@) $(AR) rcs $@ $(LIB_OBJ) $(SHARED): $(PIC_OBJ) @mkdir -p $(dir $@) $(CC) -shared -Wl,-soname,libcepis.so.$(SOVERSION) $(PIC_OBJ) \ $(LDFLAGS) $(LDLIBS) -o $@ ln -sf libcepis.so.$(VERSION) $(BUILD)/libcepis.so.$(SOVERSION) ln -sf libcepis.so.$(VERSION) $(BUILD)/libcepis.so $(CLI): $(BUILD)/src/cli.o $(STATIC) $(CC) $(BUILD)/src/cli.o $(STATIC) $(LDFLAGS) $(LDLIBS) -o $@ $(TESTS): $(TEST_OBJ) $(STATIC) $(CC) $(TEST_OBJ) $(STATIC) $(LDFLAGS) $(LDLIBS) -lpthread -o $@ test: $(TESTS) $(TESTS) # Read-only by design, so it is safe in CI and in a pre-commit hook: it reports # what `make format` would change without changing anything. lint: $(FORMAT) --dry-run --Werror $(ALL_SRC) $(ALL_HDR) $(CLANG_TIDY) --quiet $(ALL_SRC) -- $(CPPFLAGS) -std=c11 format: $(FORMAT) -i $(ALL_SRC) $(ALL_HDR) # The order matters: lint is the fastest to fail, build the slowest, so a # broken run reports the cheapest problem first. check: lint test build memcheck: $(TESTS) valgrind --error-exitcode=9 --leak-check=full --show-leak-kinds=definite,indirect \ --errors-for-leak-kinds=definite,indirect --track-origins=yes $(TESTS) # Rebuilt from scratch: the sanitizers change the ABI of the objects, so they # must not be mixed with objects from an ordinary build. sanitize: $(MAKE) clean $(MAKE) test EXTRA_CFLAGS='$(SAN)' EXTRA_LDFLAGS='$(SAN)' $(MAKE) clean install: build install -d $(DESTDIR)$(INCLUDEDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR) install -m 644 include/cepis.h $(DESTDIR)$(INCLUDEDIR)/ install -m 644 $(STATIC) $(DESTDIR)$(LIBDIR)/ install -m 755 $(SHARED) $(DESTDIR)$(LIBDIR)/ ln -sf libcepis.so.$(VERSION) $(DESTDIR)$(LIBDIR)/libcepis.so.$(SOVERSION) ln -sf libcepis.so.$(VERSION) $(DESTDIR)$(LIBDIR)/libcepis.so install -m 755 $(CLI) $(DESTDIR)$(BINDIR)/ uninstall: rm -f $(DESTDIR)$(INCLUDEDIR)/cepis.h rm -f $(DESTDIR)$(LIBDIR)/libcepis.a rm -f $(DESTDIR)$(LIBDIR)/libcepis.so* rm -f $(DESTDIR)$(BINDIR)/cepis clean: rm -rf $(BUILD)