mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-12-08 12:45:22 -05:00
Collect initial coverage data with lcov --initial and add this to coverage data to the combined coverage from each test binary. This ensures that all functions in the target file(s) are included in coverage statistics, even if those functions are not tagged in a _utest.c file. Note: Functions which are excluded by the preprocessor will not have initial coverage data generated for them.
211 lines
7.4 KiB
Makefile
211 lines
7.4 KiB
Makefile
# Indent with spaces
|
|
.RECIPEPREFIX := $(.RECIPEPREFIX) $(.RECIPEPREFIX)
|
|
|
|
# define the name for this test's output files
|
|
ifdef SUITE
|
|
EXEC_PREFIX := $(PROJECT)_$(SUITE)
|
|
else
|
|
EXEC_PREFIX := $(PROJECT)
|
|
endif
|
|
|
|
# Define directory paths
|
|
|
|
ifdef SUITE
|
|
PROJECT_DIR := $(abspath ../)
|
|
else
|
|
PROJECT_DIR := $(abspath .)
|
|
endif
|
|
|
|
SUITE_DIR := $(abspath .)
|
|
|
|
ifdef SUITE
|
|
SCRATCH_DIR := $(GENERATED_DIR)/$(PROJECT)/$(SUITE)
|
|
else
|
|
SCRATCH_DIR := $(GENERATED_DIR)/$(PROJECT)
|
|
endif
|
|
|
|
MOCKS_DIR := $(SCRATCH_DIR)/mocks
|
|
PROJ_DIR := $(SCRATCH_DIR)/proj
|
|
|
|
# Define mock details
|
|
MOCK_FILES := $(notdir $(MOCK_FILES_FP))
|
|
MOCK_HDR := $(addprefix mock_,$(MOCK_FILES))
|
|
MOCK_SRC := $(addprefix mock_,$(MOCK_FILES:.h=.c))
|
|
MOCK_OBJ := $(addprefix mock_,$(MOCK_FILES:.h=.o))
|
|
MOCK_HDR_LIST := $(addprefix $(MOCKS_DIR)/,$(MOCK_HDR))
|
|
MOCK_SRC_LIST := $(addprefix $(MOCKS_DIR)/,$(MOCK_SRC))
|
|
MOCK_OBJ_LIST := $(addprefix $(SCRATCH_DIR)/,$(MOCK_OBJ))
|
|
CFLAGS += -I$(MOCKS_DIR)
|
|
|
|
# Kernel files under test
|
|
PROJ_SRC_LIST := $(addprefix $(KERNEL_DIR)/,$(PROJECT_SRC))
|
|
PROJ_PP_LIST := $(addprefix $(PROJ_DIR)/,$(PROJECT_SRC:.c=.i))
|
|
PROJ_OBJ_LIST := $(addprefix $(PROJ_DIR)/,$(PROJECT_SRC:.c=.o))
|
|
PROJ_GCDA_LIST := $(PROJ_OBJ_LIST:.o=.gcda)
|
|
|
|
# Unit test files
|
|
SUITE_OBJ_LIST := $(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:.c=.o))
|
|
RUNNER_SRC_LIST := $(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:_utest.c=_utest_runner.c))
|
|
RUNNER_OBJ_LIST := $(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:_utest.c=_utest_runner.o))
|
|
|
|
# Support files
|
|
SF_OBJ_LIST := $(addprefix $(SCRATCH_DIR)/sf_,$(SUITE_SUPPORT_SRC:.c=.o))
|
|
DEPS_OBJ_LIST := $(addprefix $(SCRATCH_DIR)/dep_,$(PROJECT_DEPS_SRC:.c=.o))
|
|
EXECS := $(addprefix $(EXEC_PREFIX)_,$(SUITE_UT_SRC:.c=))
|
|
EXEC_LIST := $(addprefix $(BIN_DIR)/,$(EXECS))
|
|
LCOV_LIST := $(addsuffix .info,$(addprefix $(SCRATCH_DIR)/,$(SUITE_UT_SRC:.c=)))
|
|
COVINFO_INITIAL := $(SCRATCH_DIR)/$(EXEC_PREFIX)_initial.info
|
|
COVINFO_COMBINE := $(SCRATCH_DIR)/$(EXEC_PREFIX)_combined.info
|
|
COVINFO := $(abspath $(SCRATCH_DIR)/..)/$(EXEC_PREFIX).info
|
|
LIBS_LIST := $(foreach lib, $(LIBS), $(LIB_DIR)/$(lib).so)
|
|
|
|
# Coverage related options
|
|
GCC_COV_OPTS := -fprofile-arcs -ftest-coverage -fprofile-generate
|
|
GCOV_OPTS := --unconditional-branches --branch-probabilities
|
|
COV_REPORT_DIR := $(SCRATCH_DIR)/coverage
|
|
|
|
.PHONY: all clean run gcov bin lcov lcovhtml libs
|
|
|
|
# Prevent deletion of intermediate files
|
|
NO_DELETE : $(MOCK_HDR_LIST) $(MOCK_SRC_LIST) $(MOCK_OBJ_LIST) \
|
|
$(DEPS_OBJ_LIST) $(SF_OBJ_LIST) $(EXEC_LIST) \
|
|
$(PROJ_PP_LIST) $(PROJ_OBJ_LIST) $(PROJ_GCDA_LIST) \
|
|
$(SUITE_OBJ_LIST) $(RUNNER_SRC_LIST) $(RUNNER_OBJ_LIST) \
|
|
$(COVINFO) $(LCOV_LIST)
|
|
|
|
# Cases that run test binaries cannot be run in parallel.
|
|
.NOTPARALLEL : $(COVINFO) $(LCOV_LIST) $(PROJ_GCDA_LIST)
|
|
|
|
.DEFAULT_GOAL := run
|
|
|
|
# Generate gcov files by default
|
|
run : gcov
|
|
|
|
gcov : $(PROJ_GCDA_LIST)
|
|
|
|
clean:
|
|
rm -rf $(SCRATCH_DIR)
|
|
rm -rf $(EXEC_LIST)
|
|
rm -rf $(COVINFO)
|
|
|
|
$(LIBS_LIST) :
|
|
make -C $(UT_ROOT_DIR) libs
|
|
|
|
define run-test
|
|
$(1)
|
|
|
|
endef
|
|
|
|
# Run and append to gcov data files
|
|
$(PROJ_GCDA_LIST) : $(EXEC_LIST)
|
|
rm -f $(PROJ_DIR)/*.gcda
|
|
mkdir -p $(BIN_DIR)
|
|
# run each test case
|
|
$(foreach bin,$^,$(call run-test,$(bin)))
|
|
|
|
# Run and generate lcov
|
|
lcov: $(COVINFO)
|
|
|
|
lcovhtml : $(COVINFO)
|
|
mkdir -p $(COV_REPORT_DIR)
|
|
genhtml $(COVINFO) $(LCOV_OPTS) --output-directory $(COV_REPORT_DIR)
|
|
|
|
bin: $(EXEC_LIST)
|
|
|
|
# Generate _mock.c / .h files
|
|
$(MOCK_HDR_LIST) $(MOCK_SRC_LIST) : $(PROJECT_DIR)/$(PROJECT).yml $(MOCK_FILES_FP)
|
|
mkdir -p $(SCRATCH_DIR) $(MOCKS_DIR)
|
|
cd $(SCRATCH_DIR) && \
|
|
ruby $(CMOCK_EXEC_DIR)/cmock.rb -o$(PROJECT_DIR)/$(PROJECT).yml \
|
|
$(MOCK_FILES_FP)
|
|
|
|
# Generate callgraph for coverage filtering
|
|
$(PROJ_DIR)/callgraph.json : $(PROJ_SRC_LIST)
|
|
mkdir -p $(PROJ_DIR)
|
|
python3 $(UT_ROOT_DIR)/tools/callgraph.py --out $@ $^
|
|
|
|
# preprocess proj files to expand macros for coverage
|
|
$(PROJ_DIR)/%.i : $(KERNEL_DIR)/%.c
|
|
mkdir -p $(PROJ_DIR)
|
|
$(CC) -E $< $(CPPFLAGS) $(CFLAGS) -o $@
|
|
|
|
# compile the project objects with coverage instrumented
|
|
$(PROJ_DIR)/%.o : $(PROJ_DIR)/%.i
|
|
$(CC) -c $< $(CPPFLAGS) $(INCLUDE_DIR) $(GCC_COV_OPTS) -o $@
|
|
|
|
# Build mock objects
|
|
$(SCRATCH_DIR)/mock_%.o : $(MOCKS_DIR)/mock_%.c
|
|
$(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@
|
|
|
|
# compile unit tests
|
|
$(SCRATCH_DIR)/%_utest.o : $(SUITE_DIR)/%_utest.c $(MOCK_HDR_LIST) $(LIBS_LIST)
|
|
mkdir -p $(SCRATCH_DIR)
|
|
$(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@
|
|
|
|
# compile support files
|
|
$(SCRATCH_DIR)/sf_%.o : $(PROJECT_DIR)/%.c $(MOCK_HDR_LIST)
|
|
mkdir -p $(SCRATCH_DIR)
|
|
$(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@
|
|
|
|
# compile c files that are needed by PROJ but not mocked
|
|
$(SCRATCH_DIR)/dep_%.o : $(KERNEL_DIR)/%.c
|
|
mkdir -p $(SCRATCH_DIR)
|
|
$(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@
|
|
|
|
# generate a test runner for each test file
|
|
$(SCRATCH_DIR)/%_utest_runner.c : $(SUITE_DIR)/%_utest.c
|
|
mkdir -p $(SCRATCH_DIR)
|
|
ruby $(UNITY_BIN_DIR)/generate_test_runner.rb\
|
|
$(PROJECT_DIR)/$(PROJECT).yml $< $@
|
|
|
|
# compile test runner
|
|
$(SCRATCH_DIR)/%_utest_runner.o : $(SCRATCH_DIR)/%_utest_runner.c
|
|
mkdir -p $(SCRATCH_DIR)
|
|
$(CC) -c $< $(CPPFLAGS) $(CFLAGS) -o $@
|
|
|
|
# Link the _utest binary
|
|
$(EXEC_LIST) : $(BIN_DIR)/$(EXEC_PREFIX)_%_utest : $(SCRATCH_DIR)/%_utest.o \
|
|
$(SCRATCH_DIR)/%_utest_runner.o \
|
|
$(SF_OBJ_LIST) $(MOCK_OBJ_LIST) \
|
|
$(PROJ_OBJ_LIST) $(LIBS_LIST) \
|
|
$(DEPS_OBJ_LIST)
|
|
mkdir -p $(BIN_DIR)
|
|
$(CC) $< $(subst .o,_runner.o,$<) $(SF_OBJ_LIST) $(DEPS_OBJ_LIST) \
|
|
$(MOCK_OBJ_LIST) $(PROJ_OBJ_LIST) $(LDFLAGS) -o $@
|
|
|
|
# Generate baseline inital coverage data from .gcno file
|
|
$(SCRATCH_DIR)/$(EXEC_PREFIX)_initial.info : $(PROJ_OBJ_LIST)
|
|
lcov $(LCOV_OPTS) --capture --initial --directory $(PROJ_DIR) -o $@
|
|
|
|
# Run the test runner and genrate a filtered gcov.json.gz file
|
|
$(SCRATCH_DIR)/%_utest.info : $(BIN_DIR)/$(EXEC_PREFIX)_%_utest \
|
|
$(PROJ_DIR)/callgraph.json
|
|
# Remove any existing coverage data
|
|
rm -f $(PROJ_DIR)/*.gcda
|
|
|
|
# run the testrunner
|
|
$<
|
|
|
|
# Gather coverage into a json.gz file
|
|
gcov $(GCOV_OPTS) $(foreach src,$(PROJECT_SRC),$(PROJ_DIR)/$(src:.c=.gcda)) \
|
|
--json-format --stdout | gzip > $(subst .info,.json.gz,$@)
|
|
|
|
# Filter coverage based on tags in unit test file
|
|
$(TOOLS_DIR)/filtercov.py --in $(subst .info,.json.gz,$@) \
|
|
--map $(PROJ_DIR)/callgraph.json \
|
|
--test $(SUITE_DIR)/$*_utest.c \
|
|
--format lcov \
|
|
--out $@
|
|
-lcov $(LCOV_OPTS) --summary $@
|
|
|
|
# Remove temporary files
|
|
rm -f $(subst .info,.json.gz,$@)
|
|
rm -f $(PROJ_GCDA_LIST)
|
|
|
|
# Combine lcov from each test bin into one lcov info file for the suite
|
|
$(COVINFO_COMBINE) : $(LCOV_LIST)
|
|
lcov $(LCOV_OPTS) -o $@ $(foreach cov,$(LCOV_LIST),--add-tracefile $(cov) )
|
|
|
|
# Add baseline / initial coverage generated by gcc to point out untagged functions
|
|
$(COVINFO) : $(COVINFO_COMBINE) $(COVINFO_INITIAL)
|
|
lcov $(LCOV_OPTS) -o $@ --add-tracefile $(COVINFO_INITIAL) --add-tracefile $(COVINFO_COMBINE)
|