Я создаю динамически связанную библиотеку и создаю простой набор тестов. Я хочу использовать gcov для создания отчета о покрытии статического кода.Как я могу протестировать динамическую библиотеку с помощью gcov?
Моя библиотека представляет собой файл C, содержащий функции реализации и файл заголовка, содержащий прототипы функций. Мой набор тестов - это просто приложение, которое вызывает функции различными способами и подтверждает достоверность вывода.
Я собираю как библиотеку, так и набор тестов с флагами -fprofile-arcs
и -ftest-coverage
, как описано on GNU's guide to GCOV. Я также включаю флаг -O0
, чтобы отключить оптимизацию компилятора и флаг -g
, чтобы включить символы отладки. Исполняемый файл из тестового набора динамически связан с библиотекой.
Все файлы скомпилированы без предупреждения, но не связывают набор тестов с библиотекой, ссылаясь на «скрытый символ __gcov_merge_add
». Если я компилирую без флагов -fprofile-arcs
и -ftest-coverage
, соединение успешно завершается, и я могу запустить исполняемый файл тестового набора.
Поэтому у меня есть несколько вопросов, которые до сих пор не решены после прочтения руководства GNU для GCOV.
- Почему ссылка не работает? Как я могу это решить?
- Нужно ли включать профили и флаги покрытия при компиляции и библиотеки и набора тестов?
Вот мой inc/mylib.h
файл:
#ifndef __MYLIB_H__
#define __MYLIB_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
int
foo (int a);
int
bar (int a);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __MYLIB_H__ */
Вот мой src/mylib.c
файл:
#include <stdio.h>
#include "mylib.h"
int foo(int a) {
if (a > 5) {
return 5;
}
return a;
}
int bar(int a) {
if (a < 0) {
return 0;
}
return a;
}
Вот мой test/unittests.c
файл:
#include <stdio.h>
#include "mylib.h"
void run_foo_tests() {
int inputs[] = {3, 6};
int expected_results[] = {3, 5};
int i, actual_result;
for (i = 0; i < sizeof(inputs)/sizeof(int); i++) {
actual_result = foo(inputs[i]);
if (actual_result == expected_results[i]) {
printf("Test %d passed!\n", i + 1);
} else {
printf("Test %d failed!\n", i + 1);
printf(" Expected result: %d\n", expected_results[i]);
printf(" Actual result: %d\n", actual_result);
}
}
}
void run_bar_tests() {
int inputs[] = {3, -1};
int expected_results[] = {3, 0};
int i, actual_result;
for (i = 0; i < sizeof(inputs)/sizeof(int); i++) {
actual_result = bar(inputs[i]);
if (actual_result == expected_results[i]) {
printf("Test %d passed!\n", i + 1);
} else {
printf("Test %d failed!\n", i + 1);
printf(" Expected result: %d\n", expected_results[i]);
printf(" Actual result: %d\n", actual_result);
}
}
}
int main(int argc, char *argv[]) {
run_foo_tests();
run_bar_tests();
return 0;
}
Вот мой Makefile
:
CC=gcc
CFLAGS=-Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage
all: clean build run_tests
build:
$(CC) $(CFLAGS) -fPIC -c src/*.c -o lib/mylib.o
$(CC) -shared lib/mylib.o -o lib/libmylib.so
$(CC) $(CFLAGS) test/*.c -o bin/unittests -Llib -lmylib
run_tests:
LD_LIBRARY_PATH=lib bin/unittests
gcov src/*.c
clean:
rm -f *.gcda *.gcno *.gcov
rm -rf bin lib ; mkdir bin lib
Когда я бегу make
, я представил этот вывод:
rm -f *.gcda *.gcno *.gcov
rm -rf bin lib ; mkdir bin lib
gcc -Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage -fPIC -c src/*.c -o lib/mylib.o
gcc -shared lib/mylib.o -o lib/libmylib.so
gcc -Wall -std=c89 -g -O0 -Iinc -fprofile-arcs -ftest-coverage test/*.c -o bin/unittests -Llib -lmylib
/usr/bin/ld: bin/unittests: hidden symbol `__gcov_merge_add' in /usr/lib/gcc/x86_64-redhat-linux/4.8.5/libgcov.a(_gcov_merge_add.o) is referenced by DSO
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
make: *** [build] Error 1
Вы действительно не должны использовать древний ANSI- C. По крайней мере, используйте C99, лучше стандарт C. – Olaf
Мне нужна библиотека, совместимая с c89 из-за неясных платформ, к которым я буду доставлять. что касается работы gcov? –
(очевидно, библиотека * real) сложнее, чем то, что я разместил здесь. Это только версия MCVE.) –