Gcov — свободно распространяемая утилита для исследования покрытия кода. Gcov генерирует точное количество исполнений для каждого оператора в программе и позволяет добавить аннотации к исходному коду. Gcov поставляется как стандартная утилита в составе пакета GCC.

При создании Makefile для проекта(String+) в школе 21 я все никак не понимал, как мне сделать это самое покрытие и сделать по нему отчет с помощью lcov.

Давайте разберем как я в итоге решил этот вопрос

SRC_C_FILES := $(shell find $(SRC_DIR) -name "s21_*.c")
  


TEST_C_FILES := $(shell find $(TEST_DIR) -name "test_*.c")
OBJS_TEST_FILES := $(addprefix $(TEST_OBJ_DIR)/, $(notdir $(TEST_C_FILES:.c=.o)))

SRC_C_FILES - поиск в папке src всех си файлов которые начинаются с s21_
OBJS_C_FILES - преобразование си файлов в объектные, и их запись в папку objs
По такой же аналогии я сделал с тестовыми файлами

Затем основная часть gcov_report цель моего мейк файла

gcov_report: s21_string.a
	gcc $(GCC_FLAGS) --coverage main.c $(TEST_C_FILES) $(SRC_C_FILES) s21_string.a -L. s21_string.a $(TEST_FLAGS) -o $(BUILD_PATH)$(EXE) 
	$(BUILD_PATH)$(EXE)
	lcov -t "Report" -c -d $(BUILD_PATH) --output-file $(BUILD_PATH)coverage.info
	genhtml $(BUILD_PATH)coverage.info --output-directory $(BUILD_PATH)report/
	open $(BUILD_PATH)report/index.html
  1. Gcov report с целью нашей статичной библиотеки s21_string.a

  2. Затем мы компилируем все наши си файлы и статичную библиотеку. В main.c находиться запуск юнит тестов для проверки нашей библиотеки, он является главным тестовым файлом. С помощью флага coverage мы как бы говорим компилятору сделать отчет по тому что мы будем в дальше ему передавать. Флаг -L указывает на то что наша статичная библиотека находиться в этой же папки где и make. -o $(build_path)$(exe) указывает выходной файл и папку в которой он будет создаваться.

  3. Затем запускаем скомпилированное исполняемое тестовое приложение, что необходимо для генерации файлов данных покрытия (.gcda и .gcno).

  4. lcov - инструмент для сбора данных о покрытии. -t "Report" заголовок для отчета покрытия. -с сбор данных о покрытии. -d $(build_path) - там где искать те самые файлы .gcda и .gcno.  --output-file $(BUILD_PATH)coverage.info - имя выходного файла с собранными данными покрытия.

  5. gentml - инструмент для создания html файла с данными о покрытии

  6. Открытие готового файла

Таким образом выглядит отчет о покрытии
Таким образом выглядит отчет о покрытии

Вот так выглядит мой мейк целиком

GCC_FLAGS = -Wall -Werror -Wextra -std=c11
SANITAIZER = -g -fsanitize=address
TEST_FLAGS = -lcheck -lm -lpthread
GCOV_FLAGS = -fprofile-arcs -ftest-coverage
EXE=test.out

# Папки поиска
SRC_DIR = .
TEST_DIR = ./test
OBJ_DIR = ./objs
TEST_OBJ_DIR = ./test/objs
BUILD_PATH=./


SRC_C_FILES := $(shell find $(SRC_DIR) -name "s21_*.c")
OBJS_C_FILES := $(addprefix $(OBJ_DIR)/, $(notdir $(SRC_C_FILES:.c=.o)))


TEST_C_FILES := $(shell find $(TEST_DIR) -name "test_*.c")
OBJS_TEST_FILES := $(addprefix $(TEST_OBJ_DIR)/, $(notdir $(TEST_C_FILES:.c=.o)))


all: s21_string.a test gcov_report

rebuild: clean all

test: $(OBJS_TEST_FILES) s21_string.a main.o
	gcc $(TEST_FLAGS) $(OBJS_TEST_FILES) $(OBJS_C_FILES) main.o
	./a.out

s21_string.a: $(OBJS_C_FILES)
	ar rcs s21_string.a $(OBJS_C_FILES)
	ranlib s21_string.a

main.o: main.c
	gcc -c $(GCC_FLAGS) -o $@ $<


$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c | $(OBJ_DIR)
	gcc $(GCC_FLAGS) -c $< -o $@

$(TEST_OBJ_DIR)/%.o: $(TEST_DIR)/%.c | $(TEST_OBJ_DIR)
	gcc $(GCC_FLAGS) -c $< -o $@

$(OBJ_DIR):
	mkdir -p $(OBJ_DIR)

$(TEST_OBJ_DIR):
	mkdir -p $(TEST_OBJ_DIR)

gcov_report: s21_string.a
	gcc $(GCC_FLAGS) --coverage main.c $(TEST_C_FILES) $(SRC_C_FILES) s21_string.a -L. s21_string.a $(TEST_FLAGS) -o $(BUILD_PATH)$(EXE) 
	$(BUILD_PATH)$(EXE)
	lcov -t "Report" -c -d $(BUILD_PATH) --output-file $(BUILD_PATH)coverage.info
	genhtml $(BUILD_PATH)coverage.info --output-directory $(BUILD_PATH)report/
	open $(BUILD_PATH)report/index.html

clean: 
	rm -rf *.a *.out *.info
	rm -rf $(OBJ_DIR)/*.o
	rm -rf $(TEST_OBJ_DIR)/*.o
	rm -rf $(OBJ_DIR)
	rm -rf $(TEST_OBJ_DIR)
	rm -rf *.o
	rm -rf *.gcno *.gcov *.gcda
	rm -rf report/


Эта статья будет полезна тем, кто столкнулся с проблемой создания отчета о покрытии с помощью gcov и lcov.

Комментарии (2)


  1. xi-tauw
    08.06.2024 13:23
    +4

    Для начала, конечно, сойдет. Но вообще вам бы разобраться почему .gcno создается при компиляции, а .gcna при запуске, как они связаны между собой и бинарем. И какие увлекательные следствия из всего этого следуют (например, в ситуации когда собираете на одной машинке, а тесты запускаете на другой).

    Там уже недолго и до drcov из DynamoRIO с IDA+lighthouse дойти.


    1. Back6pace Автор
      08.06.2024 13:23

      Спасибо за комментарий, изучу этот вопрос, а так статейка написана ради интереса, хотел посмотреть как сюда в принципе писать статьи