# NOTE: only tested in GNU/Linux. ## Binary dependencies. CC = gcc AR = ar ## Paths. PREFIX ?= /usr/local bindir ::= $(PREFIX)/bin libdir ::= $(PREFIX)/lib includedir = $(PREFIX)/include/lsup MDB_DIR = ext/openldap/libraries/liblmdb XXHASH_DIR = ext/xxHash VALGRIND_DUMP = /tmp/lsup_valgrind.log CALLGRIND_DUMP = /tmp/lsup_callgrind.out MASSIF_DUMP = /tmp/lsup_massif.out INCLUDE_BASE ::= . -Iinclude -I$(MDB_DIR) -I$(XXHASH_DIR) \ -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 # NOTE: -luuid is a Linux system library. Other OS's might need a different # link or a non-system library built. LDFLAGS ::= -L. -L$(libdir) -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) DEPLIBS = libxxhash liblmdb LIBS = liblsuprdf.a liblsuprdf.so DBG_LIBS = liblsuprdf_dbg.a liblsuprdf_dbg.so # 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 = .:$(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: $(DEPLIBS) codec $(LIBS) ## Compile main library (static and dynamic linking). debug: $(DEPLIBS) codec_dbg $(DBG_LIBS) ## Compile main library with debug symbols. # Static library. liblsuprdf.a: $(OBJ) $(AR) rs $@ $^ $(CODEC_OBJ) # Dynamic library. liblsuprdf.so: $(OBJ) $(CC) -shared $(LDFLAGS) -o $@ $^ $(CODEC_OBJ) # Static debug library. liblsuprdf_dbg.a: $(DBG_OBJ) $(AR) rs $@ $^ $(CODEC_DBG_OBJ) # Dynamic debug library. liblsuprdf_dbg.so: $(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 $@ # Ext libraries. .PHONY: libxxhash libxxhash: $(MAKE) -C $(XXHASH_DIR) .PHONY: liblmdb liblmdb: $(MAKE) -C $(MDB_DIR) install: lib ## Install library and dependencies to $PREFIX. May require sudo. @echo "Installing library files in $(PREFIX)." PREFIX=$(PREFIX) make -C $(MDB_DIR) install PREFIX=$(PREFIX) make -C $(XXHASH_DIR) install mkdir -p $(DESTDIR)$(libdir) mkdir -p $(DESTDIR)$(includedir) cp liblsuprdf.a liblsuprdf.so $(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 liblsuprdf_dbg.a liblsuprdf_dbg.so $(DESTDIR)$(libdir) .PHONY: clean ## Clean up artifacts, including language parsers. clean: rm -f src/*.[aod] ./*.[aod] src/codec/*.[aod] src/codec/*.out rm -rf build/ dist/ lsup_rdf.egg-info/ rm -f *.so rm -f include/codec/grammar_*.h rm -f src/codec/grammar_*.c src/codec/parser_*.c .PHONY: deepclean ## Clean up external libraries. deepclean: clean make -C $(MDB_DIR) clean make -C $(XXHASH_DIR) clean .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. # Performance test application. Essentially the profiling code without debug. 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/perftest 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." .PHONY: py py: codec ## Build and install python library. pip3 install build==0.8.0 pip3 uninstall -y lsup_rdf python3 -m build pip3 install --no-index --find-links=dist/ lsup_rdf .PHONY: py_dbg py_dbg: codec_dbg ## Build and install python library with debug symbols. pip3 install build==0.8.0 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. 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