summaryrefslogtreecommitdiffstats
path: root/Makefile
diff options
context:
space:
mode:
Diffstat (limited to 'Makefile')
-rw-r--r--Makefile140
1 files changed, 140 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e649642
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,140 @@
+VERSION := 0.1.0
+
+ifeq ($(origin FC),default)
+FC := gfortran
+endif
+FC ?= gfortran
+CC ?= cc
+AR ?= ar
+FPRETTIFY ?= fprettify
+PREFIX ?= /usr/local
+LIBDIR ?= $(PREFIX)/lib
+INCLUDEDIR ?= $(PREFIX)/include/cepis
+BINDIR ?= $(PREFIX)/bin
+
+BUILD := build
+
+CURL_CFLAGS := $(shell pkg-config --cflags libcurl 2>/dev/null)
+CURL_LIBS := $(shell pkg-config --libs libcurl 2>/dev/null || echo -lcurl)
+
+WARNINGS := -Wall -Wextra -Wno-unused-dummy-argument
+SAN := -fsanitize=address,undefined -fno-omit-frame-pointer
+FFLAGS ?= -O2 -g
+FFLAGS += -std=f2018 -fimplicit-none -J$(BUILD) -I$(BUILD) $(WARNINGS) $(EXTRA_FFLAGS)
+CFLAGS ?= -O2 -g
+CFLAGS += -std=c11 -D_POSIX_C_SOURCE=200809L -Wall -Wextra $(EXTRA_CFLAGS)
+LDFLAGS += $(EXTRA_LDFLAGS)
+LDLIBS += $(CURL_LIBS)
+
+LIB_SRC := src/cepis_errors.f90 src/cepis_strings.f90 src/cepis_json.f90 \
+ src/cepis_csv.f90 src/cepis_http.f90 src/cepis_models.f90 \
+ src/cepis.f90
+LIB_OBJ := $(LIB_SRC:%.f90=$(BUILD)/%.o)
+LIB_MOD := $(BUILD)/cepis.mod $(BUILD)/cepis_errors.mod \
+ $(BUILD)/cepis_strings.mod $(BUILD)/cepis_json.mod \
+ $(BUILD)/cepis_csv.mod $(BUILD)/cepis_http.mod \
+ $(BUILD)/cepis_models.mod
+
+ALL_F90 := $(LIB_SRC) test/test_server.f90 app/main.f90 test/test_cepis.f90
+
+STATIC := $(BUILD)/libcepis.a
+CLI := $(BUILD)/cepis
+TESTS := $(BUILD)/test_cepis
+
+.DEFAULT_GOAL := help
+.PHONY: help build test lint format check sanitize clean install uninstall
+
+help:
+ @echo 'Targets:'
+ @echo ' build static library, modules and the cepis CLI'
+ @echo ' test build and run the suite against a local HTTP server'
+ @echo ' lint strict warning-free rebuild + fprettify --diff (read-only)'
+ @echo ' format apply fprettify (writes)'
+ @echo ' check lint, then test, then build'
+ @echo ' sanitize rebuild and run the suite under ASan + UBSan'
+ @echo ' install install modules, the library and the CLI under PREFIX'
+ @echo ' clean remove $(BUILD)/'
+ @echo
+ @echo 'Requires gfortran (or another Fortran 2018 compiler), a C compiler'
+ @echo 'and libcurl with its development headers.'
+ @echo 'Override the compiler with e.g. make test FC=flang'
+
+build: $(STATIC) $(CLI)
+
+$(BUILD)/%.o: %.f90
+ @mkdir -p $(dir $@) $(BUILD)
+ $(FC) $(FFLAGS) -c $< -o $@
+
+$(BUILD)/%.o: %.c
+ @mkdir -p $(dir $@)
+ $(CC) $(CFLAGS) $(CURL_CFLAGS) -c $< -o $@
+
+$(BUILD)/src/cepis_json.o: $(BUILD)/src/cepis_strings.o
+$(BUILD)/src/cepis_csv.o: $(BUILD)/src/cepis_strings.o
+$(BUILD)/src/cepis_http.o: $(BUILD)/src/cepis_strings.o
+$(BUILD)/src/cepis_models.o: $(BUILD)/src/cepis_json.o $(BUILD)/src/cepis_strings.o
+$(BUILD)/src/cepis.o: $(BUILD)/src/cepis_errors.o $(BUILD)/src/cepis_strings.o \
+ $(BUILD)/src/cepis_json.o $(BUILD)/src/cepis_csv.o \
+ $(BUILD)/src/cepis_http.o $(BUILD)/src/cepis_models.o
+$(BUILD)/app/main.o: $(BUILD)/src/cepis.o
+$(BUILD)/test/test_server.o: $(BUILD)/src/cepis_strings.o
+$(BUILD)/test/test_cepis.o: $(BUILD)/src/cepis.o $(BUILD)/test/test_server.o
+
+$(STATIC): $(LIB_OBJ)
+ @mkdir -p $(dir $@)
+ $(AR) rcs $@ $(LIB_OBJ)
+
+$(CLI): $(BUILD)/app/main.o $(STATIC)
+ $(FC) $(FFLAGS) $(BUILD)/app/main.o $(STATIC) $(LDFLAGS) $(LDLIBS) -o $@
+
+$(TESTS): $(BUILD)/test/test_cepis.o $(BUILD)/test/test_server.o \
+ $(BUILD)/test/http_server.o $(STATIC)
+ $(FC) $(FFLAGS) $(BUILD)/test/test_cepis.o $(BUILD)/test/test_server.o \
+ $(BUILD)/test/http_server.o $(STATIC) $(LDFLAGS) $(LDLIBS) -lpthread -o $@
+
+test: $(TESTS)
+ $(TESTS)
+
+# Read-only by design, so it is safe in CI and in a pre-commit hook. The
+# rebuild turns every warning into an error without touching the ordinary
+# build tree; fprettify only reports, and is skipped when it is not installed.
+lint:
+ @rm -rf $(BUILD)/lint
+ @mkdir -p $(BUILD)/lint
+ $(FC) -std=f2018 -fimplicit-none $(WARNINGS) -Werror -fsyntax-only \
+ -J$(BUILD)/lint -I$(BUILD)/lint $(ALL_F90)
+ $(CC) $(CFLAGS) $(CURL_CFLAGS) -Werror -fsyntax-only test/http_server.c
+ @if command -v $(FPRETTIFY) >/dev/null 2>&1; then \
+ $(FPRETTIFY) --diff --indent 4 --line-length 100 $(ALL_F90); \
+ else \
+ echo 'fprettify not installed: skipping style check'; \
+ fi
+
+format:
+ $(FPRETTIFY) --indent 4 --line-length 100 $(ALL_F90)
+
+# 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
+
+# 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_FFLAGS='$(SAN) -fcheck=all' EXTRA_CFLAGS='$(SAN)' \
+ EXTRA_LDFLAGS='$(SAN)'
+ $(MAKE) clean
+
+install: build
+ install -d $(DESTDIR)$(INCLUDEDIR) $(DESTDIR)$(LIBDIR) $(DESTDIR)$(BINDIR)
+ install -m 644 $(LIB_MOD) $(DESTDIR)$(INCLUDEDIR)/
+ install -m 644 $(STATIC) $(DESTDIR)$(LIBDIR)/
+ install -m 755 $(CLI) $(DESTDIR)$(BINDIR)/
+
+uninstall:
+ rm -rf $(DESTDIR)$(INCLUDEDIR)
+ rm -f $(DESTDIR)$(LIBDIR)/libcepis.a
+ rm -f $(DESTDIR)$(BINDIR)/cepis
+
+clean:
+ rm -rf $(BUILD)