Функции Overiding C в статической библиотеке - PullRequest
0 голосов
/ 03 ноября 2011

Я получаю несколько ошибок определения и не понимаю, почему.

Я собираю код C с помощью g ++ на Cygwin. Я использую фреймворк для юнит-теста (google test, который является C ++, и поэтому я не использую gcc). Исходный файл модульного теста # включает в себя файл .c (fileA.c), содержащий функцию, которую я хочу выполнить модульным тестом, по сути, делая его расширением указанного файла, и я компилирую исходный файл модульного теста. Тестируемая функция вызывает функции, объявленные в fileB.h и определенные в fileB.c. Это немного похоже на Переопределить вызов функции в C . Я не показываю охрану включения, но по сути урезанный код выглядит так:

fileB.h

typedef void * pClass; // to hide the "class" in the .c file
extern pClass pObject1;

void do_something_with_object( void * );

fileB.c

#include "FileB.h"

typedef struct myclass {
    int stuff;
} myclass;

myclass Obj1 = { initial_value };

void *pObj1 = &Obj1;

void do_something_with_object( void *arg) {
    // do stuff, casting to myclass and verifying it's the right kind
}

fileA.h

#include "fileB.h"

void myfunc( void );

fileA.c

#include "fileA.h"

void myfunc( void ) {

    do_something_with_object( pObj1 );
}

utest_fileA.cpp

#include "../fileA.c"
// google test infrastructure stuff not shown
TEST(testname, testcase) {
    myfunc();
}

Символы fileB связаны в статическую библиотеку, которая содержит весь производственный код. Статическая библиотека была скомпилирована с g ++, поэтому проблем с extern "C" нет. Makefile для статического ссылки на utest_fileA.cpp в этой библиотеке. Все идет нормально. Теперь я хочу предоставить свою собственную поддельную версию do_something_with_object, чтобы я мог следить за тем, что было передано, чтобы myfunc вызывал do_something_with_object с правильным параметром. Я не хочу изменять производственный код только для поддержки этого модульного теста. Итак, я создаю поддельную версию do_something_with_object далее в модуле компиляции для моего источника модульного теста:

static void * myspy;
void do_something_with_object( void * arg) {
    myspy = arg;
}

Идея состоит в том, что в модульном тесте будет использоваться поддельное определение, и, поскольку оно имеет определение, оно не будет беспокоиться о его поиске в статической библиотеке, и конфликта не будет. Обычно это работает. Но в случае, с которым я сейчас сталкиваюсь, я получаю несколько ошибок определения для do_something_with_object (), сначала находя поддельную, а затем реальную. Я не вижу ничего отличного от случаев, когда это работает, но явно я что-то упускаю. Что может быть причиной этого? Что я должен искать? Это не удается при попытке связать utest_fileA.o с libMyLib.a. Он использует флаг -static. Я попробовал кое-что, что я предложил, в другом месте в stackoverflow, например -z muldefs, но Cygwin это не понравилось, и я действительно хотел бы понять, что происходит.

1 Ответ

0 голосов
/ 04 ноября 2011

Причиной нескольких определений является то, что "extern pClass Object1" в fileB.h. В качестве неразрешенного внешнего объекта, когда объектный файл включает его, компоновщик извлекает объект, в котором он определен, то есть fileB.o. Компоновщик извлекает весь файл B.o, а не только один символ из него, поэтому определения функций также включаются. Таким образом, когда код модульного теста компилируется и имеет определение шпиона, он компилируется нормально. Но когда компоновщик пытается скомпоновать статическую библиотеку, он находит другое определение, и ссылка не удается.

Вместо того, чтобы пытаться переопределить вызов функции в статической библиотеке, заставив компоновщика сначала найти версию шпиона, я в итоге дал шпиону немного другое имя и использовал препроцессор, чтобы заменить его для модульного теста. Это позволяет рабочему коду оставаться нетронутым. Он похож, но не совсем совпадает с ответом, выбранным в Переопределить вызов функции в C , потому что шпион и его директивы препроцессора определены в отдельном файле, который может быть включен в любой модульный тест, поэтому нет необходимости регистрировать замены в определенном заголовочном файле.

...