2016-02-17 3 views
2

Я создаю динамически связанную библиотеку и создаю простой набор тестов. Я хочу использовать gcov для создания отчета о покрытии статического кода.Как я могу протестировать динамическую библиотеку с помощью gcov?

Моя библиотека представляет собой файл C, содержащий функции реализации и файл заголовка, содержащий прототипы функций. Мой набор тестов - это просто приложение, которое вызывает функции различными способами и подтверждает достоверность вывода.

Я собираю как библиотеку, так и набор тестов с флагами -fprofile-arcs и -ftest-coverage, как описано on GNU's guide to GCOV. Я также включаю флаг -O0, чтобы отключить оптимизацию компилятора и флаг -g, чтобы включить символы отладки. Исполняемый файл из тестового набора динамически связан с библиотекой.

Все файлы скомпилированы без предупреждения, но не связывают набор тестов с библиотекой, ссылаясь на «скрытый символ __gcov_merge_add». Если я компилирую без флагов -fprofile-arcs и -ftest-coverage, соединение успешно завершается, и я могу запустить исполняемый файл тестового набора.

Поэтому у меня есть несколько вопросов, которые до сих пор не решены после прочтения руководства GNU для GCOV.

  1. Почему ссылка не работает? Как я могу это решить?
  2. Нужно ли включать профили и флаги покрытия при компиляции и библиотеки и набора тестов?

Вот мой 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 
+0

Вы действительно не должны использовать древний ANSI- C. По крайней мере, используйте C99, лучше стандарт C. – Olaf

+0

Мне нужна библиотека, совместимая с c89 из-за неясных платформ, к которым я буду доставлять. что касается работы gcov? –

+0

(очевидно, библиотека * real) сложнее, чем то, что я разместил здесь. Это только версия MCVE.) –

ответ

1

Вы должны введите командную строку a rgument -lgcov для компоновщика (обычно -ftest-coverage подразумевает -lgcov, но у вас есть отдельный шаг привязки, где -ftest-coverage не указан в качестве аргумента командной строки).Кроме того, вы можете просто использовать строку аргумент --coverage команду, которая ярлык также для -fprofile-arcs и -ftest-coverage, как описано здесь: http://www.univ-orleans.fr/sciences/info/ressources/webada/doc/gnat/gcc_3.html:

--coverage

используется Этот параметр компиляции и код ссылки для анализа . Опция является синонимом `-fprofile-arcs ' ` -ftest-coverage' (при компиляции) и `-lgcov '(при связывании). См. документацию для этих опций для получения более подробной информации.

На том же месте, кстати., Он также пояснил, что вы не должны компилировать все файлы с этими опциями, которые, надеюсь, ответ на ваш вопрос 2.

+0

Я попытался заменить два флага компиляции на '--coverage', и ошибка сохраняется. в соответствии со страницей, которую вы связали, '-ftest-coverage' уже подразумевал' -lgcov'. –

+0

, если я изменяю переменную CFLAGS в своем make-файле, чтобы использовать '--coverage', а не два флага, из которых я первоначально использовал * и * добавлял опцию' -lgcov' на шаг связывания, он успешно создает и связывает программу, но когда пытаясь запустить gcov, он говорит: «mylib.gcno: невозможно открыть файл графика». –

+0

, похоже, хранит файлы libmylib.gcno и libmylib.gcda в папке lib, хотя файлы unittest.gc ** находятся в корневом каталоге. –

Смежные вопросы