summaryrefslogtreecommitdiffstats
path: root/Makefile
blob: e64964269a76c0d5b9126531898f3c6235d930db (plain)
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
128
129
130
131
132
133
134
135
136
137
138
139
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)