Makefile 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. # NOTE: only tested in GNU/Linux.
  2. SHELL := /bin/bash
  3. ## Binary dependencies.
  4. CC = gcc
  5. AR = ar
  6. # Global switches.
  7. # Compile with debug symbols. Libraries are suffixed with _dbg and can coexist
  8. # with non-debug libraries.
  9. DEBUG := $(filter 1,$(DEBUG))
  10. # Install in a user-owned directory provided as LOCAL_PREFIX or a default
  11. # (~/.local), instead of a system directory.
  12. LOCAL ?= 0
  13. ## Paths.
  14. LOCAL_PREFIX ?= $(HOME)/.local
  15. ifneq ($(LOCAL), 0)
  16. PREFIX ?= $(LOCAL_PREFIX)
  17. else
  18. PREFIX ?= /usr/local
  19. endif
  20. BINDIR := $(PREFIX)/bin
  21. LIBDIR := $(PREFIX)/lib
  22. INCLUDEDIR := $(PREFIX)/include
  23. BUILDDIR := ./build
  24. TMPDIR ?= /tmp
  25. VALGRIND_DUMP := $(TMPDIR)/volksdata_valgrind.log
  26. CALLGRIND_DUMP := $(TMPDIR)/volksdata_callgrind.out
  27. MASSIF_DUMP := $(TMPDIR)/volksdata_massif.out
  28. INCLUDE_BASE := . -Iinclude -Iext/hashmap -Iext/log/src
  29. INCLUDE := -I$(INCLUDE_BASE)
  30. _CFLAGS = -std=gnu11 -Wall -Wextra -fPIC $(INCLUDE)
  31. CFLAGS = $(if $(DEBUG),\
  32. $(_CFLAGS) -Itest -O0 -ggdb -DDEBUG,\
  33. $(_CFLAGS) -O3 -g0)
  34. #$(info CFLAGS: $(CFLAGS))
  35. # NOTE: -luuid is a Linux system library. Other OS's might need a different
  36. # link or a non-system library built.
  37. LDFLAGS := -L$(BUILDDIR) -L$(LIBDIR) -llmdb -lxxhash -luuid
  38. PARSER = bin/lemon
  39. LEMON_SRC = ext/sqlite/tool/lemon.c
  40. CODEC_DIR = src/codec
  41. # External sources compiled in core object.
  42. EXT_SRC := $(wildcard ext/log/src/*.c) \
  43. $(wildcard ext/hashmap/*.c)
  44. # External headers of libraries compiled in core.
  45. EXT_H := $(wildcard ext/log/src/*.h) \
  46. $(wildcard ext/hashmap/*.h)
  47. VOLK_SRC = $(wildcard src/*.c)
  48. SRC = $(EXT_SRC) $(VOLK_SRC)
  49. TEST_SRC = $(wildcard test/*.c) test.c
  50. EXT_OBJ := $(EXT_SRC:%.c=$(BUILDDIR)/%.o)
  51. # TODO This is extremely convoluted, simplify if possible.
  52. CODEC_SRC := $(wildcard $(CODEC_DIR)/codec_*.c)
  53. CODEC_REL_SRC := $(CODEC_SRC:$(CODEC_DIR)/%=%)
  54. ALL_CODEC_REL_SRC := $(CODEC_REL_SRC) $(CODEC_REL_SRC:codec_%=parser_%) \
  55. $(CODEC_REL_SRC:codec_%=grammar_%)
  56. CODEC_SRC = $(ALL_CODEC_REL_SRC:%=$(CODEC_DIR)/%)
  57. CODEC_OBJ = $(if $(DEBUG),\
  58. $(patsubst $(CODEC_DIR)/%.c, $(BUILDDIR)/%_dbg.o, $(CODEC_SRC)),\
  59. $(patsubst $(CODEC_DIR)/%.c, $(BUILDDIR)/%.o, $(CODEC_SRC)))
  60. STATIC_LIB = $(if $(DEBUG),\
  61. $(BUILDDIR)/libvolksdata_dbg.a,\
  62. $(BUILDDIR)/libvolksdata.a)
  63. LOCAL_OBJ = $(if $(DEBUG),\
  64. $(VOLK_SRC:src/%.c=$(BUILDDIR)/%_dbg.o),\
  65. $(VOLK_SRC:src/%.c=$(BUILDDIR)/%.o))
  66. OBJ = $(EXT_OBJ) $(LOCAL_OBJ)
  67. DYN_LIB = $(STATIC_LIB:.a=.so)
  68. LIBS = $(STATIC_LIB) $(DYN_LIB)
  69. #$(info EXT_SRC: $(EXT_SRC))
  70. #$(info EXT_OBJ: $(EXT_OBJ))
  71. #$(info OBJ: $(OBJ))
  72. #$(info LIBS: $(LIBS))
  73. # LDD for Linux, otool -L for OSX.
  74. ifeq (, $(shell which ldd))
  75. LDD := otool -L
  76. else
  77. LDD := ldd
  78. endif
  79. # For visual dep graph.
  80. DEPS := $(shell echo "${INCLUDE_BASE}" | sed -e 's/ -I/,/g'),include/codec
  81. DOCS = docs
  82. ## Environment.
  83. # Tests need the freshly compiled libs.
  84. export LD_LIBRARY_PATH = $(LIBDIR)
  85. ## Rules.
  86. .DEFAULT_GOAL := lib
  87. # Extract all rule comments into a help message.
  88. .PHONY: help
  89. help:
  90. @echo "Command overview:"; echo
  91. grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
  92. | sed -n 's/^\(.*\): \(.*\)##\(.*\)/\1|\3/p' \
  93. | column -t -s '|'
  94. .PHONY: lib
  95. lib: codec $(LIBS) ## Compile main library (static and dynamic linking).
  96. # Static library.
  97. $(STATIC_LIB): $(OBJ)
  98. $(info Static Lib: $(STATIC_LIB))
  99. $(info OBJ: $(OBJ))
  100. $(AR) rs $(STATIC_LIB) $^ $(CODEC_OBJ)
  101. # Dynamic library.
  102. $(DYN_LIB): $(OBJ)
  103. $(CC) -shared $(LDFLAGS) -o $(DYN_LIB) $^ $(CODEC_OBJ)
  104. # External libraries.
  105. $(BUILDDIR)/ext/%.o: ext/%.c
  106. mkdir -p $(dir $@)
  107. $(CC) $(CFLAGS) -c $^ -o $@
  108. # Standard objects.
  109. $(BUILDDIR)/%.o: src/%.c
  110. $(CC) $(CFLAGS) -c $^ -o $@
  111. # Debug objects.
  112. $(BUILDDIR)/%_dbg.o: src/%.c
  113. $(CC) $(CFLAGS) -c $^ -o $@
  114. # Codecs in a subfolder.
  115. .PHONY: codec
  116. codec: $(PARSER)
  117. mkdir -p $(BUILDDIR)
  118. $(MAKE) -C $(CODEC_DIR) codec DEBUG=$(DEBUG)
  119. # Build the parser executable.
  120. $(PARSER): $(LEMON_SRC)
  121. mkdir -p $(dir $@)
  122. $(CC) $^ -o $@
  123. install: lib ## Install library and dependencies to $PREFIX (or, if LOCAL = 1, to $LOCAL_PREFIX). May require sudo.
  124. @echo "Installing library files in $(PREFIX)."
  125. mkdir -p $(LIBDIR)
  126. mkdir -p $(INCLUDEDIR)/volksdata
  127. cp $(LIBS) $(LIBDIR)
  128. cp -r include/volksdata/* $(EXT_H) $(INCLUDEDIR)/volksdata
  129. cp include/*.h $(INCLUDEDIR)
  130. .PHONY: clean
  131. clean: ## Clean up artifacts.
  132. rm -rf $(BUILDDIR)
  133. .PHONY: deepclean
  134. deepclean: clean ## Clean up artifacts, including language parsers that normally are kept.
  135. rm -f include/codec/grammar_*.h
  136. rm -f src/codec/grammar_*.c src/codec/parser_*.c
  137. .PHONY: uninstall ## Uninstall library.
  138. uninstall:
  139. rm -f $(LIBDIR)/libvolksdata*
  140. rm -rf $(INCLUDEDIR)/volksdata*
  141. rm -f bin/test*
  142. bin/test: lib $(TEST_SRC)
  143. $(info DEBUG in bin/test: $(DEBUG))
  144. $(info OBJ in bin/test: $(OBJ))
  145. $(info CFLAGS in bin/test: $(CFLAGS))
  146. $(CC) $(CFLAGS) $(LDFLAGS) -lvolksdata_dbg test.c -o bin/test
  147. .PHONY: test
  148. test: DEBUG = 1
  149. test: bin/test
  150. $(info DEBUG in test: $(DEBUG))
  151. LD_LIBRARY_PATH=$(BUILDDIR) exec bin/test
  152. .PHONY: gdb_test
  153. gdb_test: DEBUG = 1
  154. gdb_test: bin/test ## Run a test suite within gdb.
  155. LD_LIBRARY_PATH=$(BUILDDIR) exec gdb bin/test
  156. .PHONY: memtest
  157. memtest: DEBUG = 1
  158. memtest: bin/test ## Run test suite within Valgrind and report memory errors.
  159. LD_LIBRARY_PATH=$(BUILDDIR) valgrind \
  160. --leak-check=full --show-leak-kinds=all --track-origins=yes \
  161. --log-file=$(VALGRIND_DUMP) \
  162. ./bin/test || true
  163. @echo "Memcheck complete. Valgrind log is at $(VALGRIND_DUMP)"
  164. lint:
  165. splint \
  166. $(INCLUDE) -Itest \
  167. -DUINT_MAX=0xFFFFFFFFUL \
  168. -nullpass \
  169. -posix-lib \
  170. test.c
  171. # Profiling application.
  172. bin/profile: lib profile.c
  173. $(CC) $(CFLAGS) -g -DTESTING $(LDFLAGS) -lvolksdata_dbg \
  174. profile.c -o bin/profile
  175. # Performance test application. Essentially the profiling code without debug.
  176. bin/perftest: lib profile.c
  177. $(CC) $(CFLAGS) -g $(LDFLAGS) -lvolksdata profile.c -o bin/perftest
  178. .PHONY: perftest
  179. perftest: bin/perftest ## Run a performance test by creating, inserting and looking up triples.
  180. bin/perftest
  181. .PHONY: profile
  182. profile: DEBUG = 1
  183. profile: bin/profile ## Run a profiling session on a limited set of high-volume commands.
  184. LD_LIBRARY_PATH=$(BUILDDIR) VOLK_MDB_MAPSIZE=800000 exec valgrind --tool=callgrind \
  185. --callgrind-out-file="$(CALLGRIND_DUMP)" bin/profile 1000
  186. @echo "Profile dump written at $(CALLGRIND_DUMP) . Open it with "\
  187. "qcachegrind, kcachegrind, etc."
  188. .PHONY: test_profile
  189. test_profile: DEBUG = 1
  190. test_profile: bin/profile ## Run profiling on the standard test suite.
  191. LD_LIBRARY_PATH=$(BUILDDIR) VOLK_MDB_MAPSIZE=800000 exec valgrind --tool=callgrind \
  192. --callgrind-out-file="$(CALLGRIND_DUMP)" bin/test
  193. @echo "Profile dump written at $(CALLGRIND_DUMP) . Open it with "\
  194. "qcachegrind, kcachegrind, etc."
  195. .PHONY: footprint
  196. footprint: bin/perftest ## Measure memory footprint by generating and storing 100K triples.
  197. LD_LIBRARY_PATH=$(BUILDDIR) VOLK_MDB_MAPSIZE=80000000 exec valgrind --tool=massif \
  198. --massif-out-file=$(MASSIF_DUMP) bin/perftest 100000
  199. @echo "Memory stats file written at $(MASSIF_DUMP). Open it with "\
  200. "massif-visualizer or similar."
  201. # Requires cinclude2dot (https://www.flourish.org/cinclude2dot) and Graphviz.
  202. depgraph: $(VOLK_SRC) include/* include/volksdata/* include/volksdata/codec/* ## Build a visual dependency graph of the code.
  203. cinclude2dot --merge=module --include=$(DEPS) \
  204. --exclude='test|ext' >| $(DOCS)/dev/deps.dot
  205. dot $(DOCS)/dev/deps.dot -Tpdf >| $(DOCS)/dev/deps.pdf