CROSS_COMPILE ?= TARGET_FILE ?= test_c CC = $(CROSS_COMPILE)gcc CPP = $(CROSS_COMPILE)cpp CHECK = cppcheck LCOV = lcov GENHTML = genhtml SRC_DIR = src OBJ_DIR = obj BIN_DIR = bin COVERAGE_DIR = coverage UNIT_TEST_SRC_DIR = test/unit UNIT_TEST_OBJ_DIR = $(OBJ_DIR)/$(UNIT_TEST_SRC_DIR) PREFIX ?= /usr BIN_INSTALL_DIR = $(PREFIX)/bin INCLUDES := inc INCLUDES += $(PREFIX)/include/ INCLUDES += $(EXTRA_INC) LIBS = LD_FLAGS += $(addprefix -L,$(EXTRA_LIB_DIR)) ifneq "$(findstring $(MAKECMDGOALS), build_unit_test exec_unit_test coverage)" "" INCLUDES += test/inc C_FLAGS += --coverage LD_FLAGS += --coverage endif C_FLAGS += -fpic C_FLAGS += -O0 -g -Wall CPP_FLAGS += $(addprefix -I, $(INCLUDES)) CHECK_FLAGS = $(addprefix -I,$(filter-out $(PREFIX)/include/,$(INCLUDES))) CHECK_FLAGS += --enable=all --template=gcc --error-exitcode=1 --suppress=missingIncludeSystem --inline-suppr --force C_SRCS = $(wildcard $(SRC_DIR)/*.c) C_OBJS = $(patsubst $(SRC_DIR)%,$(OBJ_DIR)%,$(patsubst %.c,%.o,$(C_SRCS))) UNIT_TEST_SRCS = $(wildcard $(UNIT_TEST_SRC_DIR)/*.c) $(filter-out %main.c,$(CC_SRCS)) UNIT_TEST_OBJS = $(patsubst $(SRC_DIR)%,$(OBJ_DIR)%,$(patsubst $(UNIT_TEST_SRC_DIR)%,$(UNIT_TEST_OBJ_DIR)%,$(patsubst %.c,%.o,$(UNIT_TEST_SRCS)))) OBJS = $(C_OBJS) UNIT_TEST_TARGET = $(BIN_DIR)/$(UNIT_TEST_SRC_DIR)/$(TARGET_FILE) TARGET = $(BIN_DIR)/$(TARGET_FILE) THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST)) .PHONY: all install uninstall clean distclean all: $(TARGET) install: all install -d $(BIN_INSTALL_DIR) install -m 0666 $(TARGET) $(BIN_INSTALL_DIR) uninstall: rm -f $(BIN_INSTALL_DIR)/$(TARGET_FILE) clean: rm -f $(TARGET) rm -f $(OBJS) $(patsubst %.o,%.d,$(OBJS)) rm -f $(UNIT_TEST_OBJS) $(patsubst %.o,%.d,$(UNIT_TEST_OBJS)) $(UNIT_TEST_TARGET) rm -f $(UNIT_TEST_OBJ_DIR)/*.gcda rm -f $(UNIT_TEST_OBJ_DIR)/*.gcno rm -f $(OBJ_DIR)/*.gcda $(OBJ_DIR)/*.gcno rm -fr $(COVERAGE_DIR) distclean: rm -rf $(OBJ_DIR) $(BIN_DIR) $(COVERAGE_DIR) .PHONY: coverage coverage: _cov_genhtml $(eval COVERAGE:=$(shell grep 'lines' .coverage.tmp | egrep -o '[0-9]+.[0-9]+%')) @echo @echo Line coverage: $(COVERAGE) @echo @rm -f .coverage.tmp .PHONY: _cov_lcov _cov_lcov: exec_unit_test @rm -f $(UNIT_TEST_OBJ_DIR)/*.gcda @rm -f $(UNIT_TEST_OBJ_DIR)/*.gcno @mkdir -p $(COVERAGE_DIR) $(LCOV) -c -d $(OBJ_DIR) -o $(COVERAGE_DIR)/coverage.info .PHONY: _cov_genhtml _cov_genhtml: _cov_lcov $(GENHTML) -o $(COVERAGE_DIR)/html $(COVERAGE_DIR)/coverage.info > .coverage.tmp .PHONY: unit_test build_unit_test: $(UNIT_TEST_TARGET) .PHONY: unit_test exec_unit_test: $(UNIT_TEST_TARGET) $(UNIT_TEST_TARGET) .PHONY: check check: $(CC_SRCS) $(CHECK) $(CHECK_FLAGS) $(CC_SRCS) $(UNIT_TEST_TARGET): $(UNIT_TEST_OBJS) $(THIS_MAKEFILE) @mkdir -p $(BIN_DIR)/$(UNIT_TEST_SRC_DIR) $(CC) $(CC_FLAGS) $(LD_FLAGS) $(UNIT_TEST_OBJS) -o $@ $(TARGET): $(OBJS) $(THIS_MAKEFILE) @mkdir -p $(BIN_DIR) $(CC) $(CC_FLAGS) $(LD_FLAGS) $(OBJS) $(addprefix -l,$(LIBS)) -o $@ .PRECIOUS: $(OBJ_DIR)/%.d $(OBJ_DIR)/%.d: $(SRC_DIR)/%.c @mkdir -p $(OBJ_DIR) $(CPP) -MM -MF $@ -MP -MT $(patsubst %.d,%.o,$@) $(CPP_FLAGS) $(patsubst $(OBJ_DIR)/%.d,$(SRC_DIR)/%.c,$@) .PRECIOUS: $(UNIT_TEST_OBJ_DIR)/%.d $(UNIT_TEST_OBJ_DIR)/%.d: $(UNIT_TEST_SRC_DIR)/%.c @mkdir -p $(UNIT_TEST_OBJ_DIR) $(CPP) -MM -MF $@ -MP -MT $(patsubst %.d,%.o,$@) $(CPP_FLAGS) $(patsubst $(UNIT_TEST_OBJ_DIR)/%.d,$(UNIT_TEST_SRC_DIR)/%.c,$@) $(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(OBJ_DIR)/%.d @mkdir -p $(OBJ_DIR) $(CC) -c $(CPP_FLAGS) $(C_FLAGS) $< -o $@ $(UNIT_TEST_OBJ_DIR)/%.o: $(UNIT_TEST_SRC_DIR)/%.c $(UNIT_TEST_OBJ_DIR)/%.d @mkdir -p $(UNIT_TEST_OBJ_DIR) $(CC) -c $(CPP_FLAGS) $(C_FLAGS) $< -o $@ ifneq ($(MAKECMDGOALS),clean) -include $(patsubst %.o,%.d,$(OBJS)) endif