# NOTE: only tested in GNU/Linux. SHELL := /bin/bash ## Binary dependencies. CC = gcc AR = ar ## Paths. PREFIX ?= /usr/local bindir := $(PREFIX)/bin libdir := $(PREFIX)/lib includedir = $(PREFIX)/include/lsup outdir = ./bin VALGRIND_DUMP = /tmp/lsup_valgrind.log CALLGRIND_DUMP = /tmp/lsup_callgrind.out MASSIF_DUMP = /tmp/lsup_massif.out INCLUDE_BASE := . -Iinclude -Iext/tpl/src -Iext/hashmap -Iext/log/src INCLUDE := -I$(INCLUDE_BASE) _CFLAGS := -std=gnu11 -Wall -fPIC -MMD $(INCLUDE) CFLAGS = $(_CFLAGS) -O3 DBG_CFLAGS = $(_CFLAGS) -Itest -O0 -g3 -DDEBUG #$(info CFLAGS: $(CFLAGS)) #$(info DBG_CFLAGS: $(DBG_CFLAGS)) # NOTE: -luuid is a Linux system library. Other OS's might need a different # link or a non-system library built. LDFLAGS := -L$(libdir) -L$(outdir) -L. -llmdb -lxxhash -luuid PARSER = bin/lemon LEMON_SRC = ext/sqlite/tool/lemon.c CODEC_DIR = src/codec # External sources compiled in core object. EXT_SRC := $(wildcard ext/log/src/*.c) \ $(wildcard ext/hashmap/*.c) \ $(wildcard ext/tpl/src/*.c) # External headers of libraries compiled in core. EXT_H := $(wildcard ext/log/src/*.h) \ $(wildcard ext/tpl/src/*.h) \ $(wildcard ext/hashmap/*.h) LSUP_SRC = $(wildcard src/*.c) SRC = $(EXT_SRC) $(LSUP_SRC) TEST_SRC = $(wildcard test/*.c) test.c EXT_OBJ := $(EXT_SRC:.c=.o) # TODO This is extremely convoluted, simplify if possible. CODEC_SRC := $(wildcard $(CODEC_DIR)/codec_*.c) CODEC_REL_SRC := $(CODEC_SRC:$(CODEC_DIR)/%=%) ALL_CODEC_REL_SRC := $(CODEC_REL_SRC) $(CODEC_REL_SRC:codec_%=parser_%) \ $(CODEC_REL_SRC:codec_%=grammar_%) CODEC_SRC = $(ALL_CODEC_REL_SRC:%=$(CODEC_DIR)/%) CODEC_OBJ = $(CODEC_SRC:.c=.o) CODEC_DBG_OBJ = $(CODEC_SRC:.c=_dbg.o) OBJ = $(EXT_OBJ) $(LSUP_SRC:.c=.o) DBG_OBJ = $(EXT_OBJ) $(LSUP_SRC:.c=_dbg.o) STATIC_LIB = $(outdir)/liblsuprdf.a DYN_LIB = $(outdir)/liblsuprdf.so STATIC_DBG_LIB = $(outdir)/liblsuprdf_dbg.a DYN_DBG_LIB = $(outdir)/liblsuprdf_dbg.so LIBS = $(STATIC_LIB) $(DYN_LIB) DBG_LIBS = $(STATIC_DBG_LIB) $(DYN_DBG_LIB) # LDD for Linux, otool -L for OSX. ifeq (, $(shell which ldd)) LDD := otool -L else LDD := ldd endif # For visual dep graph. DEPS := $(shell echo "${INCLUDE_BASE}" | sed -e 's/ -I/,/g'),include/codec DOCS = docs ## Environment. # Tests need the freshly compiled libs. export LD_LIBRARY_PATH = $(outdir):$(libdir) ## Rules. .DEFAULT_GOAL := lib # Extract all rule comments into a help message. .PHONY: help help: @echo "Command overview:"; echo; \ grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \ | sed -n 's/^\(.*\): \(.*\)##\(.*\)/\1|\3/p' \ | column -t -s '|' lib: codec $(LIBS) ## Compile main library (static and dynamic linking). debug: codec_dbg $(DBG_LIBS) ## Compile main library with debug symbols. # Static library. $(STATIC_LIB): $(OBJ) $(AR) rs $@ $^ $(CODEC_OBJ) # Dynamic library. $(DYN_LIB): $(OBJ) $(CC) -shared $(LDFLAGS) -o $@ $^ $(CODEC_OBJ) # Static debug library. $(STATIC_DBG_LIB): $(DBG_OBJ) $(AR) rs $@ $^ $(CODEC_DBG_OBJ) # Dynamic debug library. $(DYN_DBG_LIB): $(DBG_OBJ) $(CC) -shared $(LDFLAGS) -o $@ $^ $(CODEC_DBG_OBJ) # Debug objects. %_dbg.o: %.c $(CC) $(DBG_CFLAGS) -c $^ -o $@ # Codecs in a subfolder. .PHONY: codec codec: $(PARSER) $(MAKE) -C $(CODEC_DIR) codec .PHONY: codec_dbg codec_dbg: $(PARSER) $(MAKE) -C $(CODEC_DIR) debug # Build the parser executable. $(PARSER): $(LEMON_SRC) $(CC) $^ -o $@ install: lib ## Install library and dependencies to $PREFIX. May require sudo. @echo "Installing library files in $(PREFIX)." mkdir -p $(DESTDIR)$(libdir) mkdir -p $(DESTDIR)$(includedir) cp $(LIBS) $(DESTDIR)$(libdir) && \ cp -r include/*.h include/codec $(EXT_H) $(DESTDIR)$(includedir) debug_install: install debug ## Install standard and debug libraries. @echo "Installing debug library files in $(PREFIX)." cp $(DBG_LIBS) $(DESTDIR)$(libdir) .PHONY: clean ## Clean up artifacts, including language parsers. clean: rm -f ./*.[aod] bin/* src/*.[aod] src/codec/*.[aod] src/codec/*.out rm -rf build/ dist/ lsup_rdf.egg-info/ rm -f $(LIBS) $(DBG_LIBS) rm -f include/codec/grammar_*.h rm -f src/codec/grammar_*.c src/codec/parser_*.c rm -rf venv/ .PHONY: uninstall ## Uninstall library (not the dependencies). uninstall: rm -f $(DESTDIR)$(libdir)/liblsuprdf* rm -rf $(DESTDIR)$(includedir) rm -f bin/test* # For testing, use debug symbols. bin/test: debug $(TEST_SRC) $(CC) $(DBG_CFLAGS) $(LDFLAGS) -llsuprdf_dbg \ test.c -o bin/test .PHONY: test test: bin/test ## Run a test suite. @echo "Using libraries: "; $(LDD) bin/test exec bin/test .PHONY: gdb_test gdb_test: bin/test ## Run a test suite within gdb. @echo "Using libraries: "; $(LDD) bin/test exec gdb bin/test lint: splint \ $(INCLUDE) -Itest \ -DUINT_MAX=0xFFFFFFFFUL \ -nullpass \ -posix-lib \ test.c .PHONY: memcheck memcheck: valgrind \ --leak-check=full --show-leak-kinds=all --track-origins=yes \ --log-file=$(VALGRIND_DUMP) \ ./bin/test @echo "Memcheck complete. Valgrind log is at $(VALGRIND_DUMP)" memtest: bin/test memcheck ## Run a test suite using Valgrind. Output to separate file. # Profiling application. bin/profile: debug profile.c $(CC) $(CFLAGS) -g -DTESTING $(LDFLAGS) -llsuprdf_dbg \ profile.c -o bin/profile # Performance test application. Essentially the profiling code without debug. bin/perftest: lib profile.c $(CC) $(CFLAGS) -g $(LDFLAGS) -llsuprdf profile.c -o bin/perftest .PHONY: perftest perftest: bin/perftest ## Run a performance test by creating, inserting and looking up triples. bin/perftest .PHONY: profile profile: bin/profile ## Run a profiling session. Output can be inspected with KCachegrind. LSUP_MDB_MAPSIZE=800000 valgrind --tool=callgrind \ --callgrind-out-file="$(CALLGRIND_DUMP)" bin/profile 1000 @echo "Profile dump written at $(CALLGRIND_DUMP). Open it with "\ "qcachegrind, kcachegrind, etc." .PHONY: footprint footprint: bin/perftest ## Measure memory footprint by generating and storing 100K triples. LSUP_MDB_MAPSIZE=80000000 valgrind --tool=massif \ --massif-out-file=$(MASSIF_DUMP) bin/perftest 100000 @echo "Memory stats file written at $(MASSIF_DUMP). Open it with "\ "massif-visualizer or similar." venv: test -d venv || python3 -m venv ./venv .PHONY: py py: venv codec ## Build and install python library. source ./venv/bin/activate && (\ pip3 install build~=1.2; \ pip3 uninstall -y lsup_rdf; \ python3 -m build; \ pip3 install --no-index --find-links=dist/ lsup_rdf \ ) .PHONY: py_dbg py_dbg: venv codec_dbg ## Build and install python library with debug symbols. source ./venv/bin/activate && (\ pip3 install build~=1.2; \ pip3 uninstall -y lsup_rdf; \ DEBUG=1 python3 -m build; \ pip3 install --no-index --find-links=dist/ lsup_rdf \ ) .PHONY: pytest pytest: py_dbg ## Run a test suite for the Python package. source ./venv/bin/activate && (\ python3 test/cpython_test.py ) # Requires cinclude2dot (https://www.flourish.org/cinclude2dot) and Graphviz. depgraph: $(LSUP_SRC) $(CODEC_SRC) include/* include/codec/* ## Build a visual dependency graph of the code. cinclude2dot --merge=module --include=$(DEPS) \ --exclude='test|ext' >| $(DOCS)/dev/deps.dot dot $(DOCS)/dev/deps.dot -Tpdf >| $(DOCS)/dev/deps.pdf