-1

I'm getting multiple definition errors and don't understand why.

I'm compiling C code with g++ on Cygwin. I'm using a unit test framework (google test, which is C++, and that's why I'm not using gcc). The unit test source file #includes the .c file (fileA.c) containing the function I want to unit test, essentially making it an extension of said file, and I compile the unit test source file. The function under test calls functions declared in fileB.h and defined in fileB.c. It's a bit like Override a function call in C. I'm not showing the include guards, but essentially the stripped down code looks like this:

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's sybols are linked into a static library that contains all the production code. The static library was compiled with g++ so there are no extern "C" issues. The makefile for utest_fileA.cpp statically links in this library. So far so good. Now, I want to provide my own fake version of do_something_with_object so I can spy on what's passed in to make sure myfunc calls do_something_with_object with the correct parameter. I don't want to modify the production code just to support this unit test. So, I create a fake version of do_something_with_object further up in the compilation unit for my unit test source:

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

The idea is that the unit test will use the fake definition, and since it has a definition it won't bother looking for it in the static library, and there will be no conflict. Usually this works. But in the case I'm up against right now, I get multiple definition errors for do_something_with_object(), finding the fake one first and then the real one. I don't see anything different from the cases where this works, but clearly I'm missing something. What could be causing this? What should I look for? It's failing when trying to link utest_fileA.o with libMyLib.a. It uses the -static flag. I tried some things I saw suggested elsewhere on stackoverflow, like -z muldefs, but Cygwin didn't like that, and I really would like to understand what's going on.

Community
  • 1
  • 1
jasper77
  • 1,553
  • 5
  • 19
  • 31
  • 3
    You're including the `fake_fileB.c` instead of `fake_fileB.h`? – Mooing Duck Nov 02 '11 at 22:28
  • Don't be so hasty. Since you didn't see what I was doing or asking, I'll streamline the example. – jasper77 Nov 03 '11 at 02:44
  • I wouldn't `typedef void *pClass;` because then you have to also do `typedef const void *cpClass;`, and then your user has to remember what naming convention you used for the `const` pointer typedef. Easier (IMHO) to use `void *` or `const void *` directly, or to say `typedef void Class;` and use `Class *` and `const Class *` (which at least _looks_ illustrative). – Chris Lutz Nov 03 '11 at 02:55
  • I think the unrelated details are getting in the way of my real question. I rewrote it here: http://stackoverflow.com/questions/8001991/override-a-c-function-defined-in-a-static-library – jasper77 Nov 03 '11 at 21:19

1 Answers1

0

The reason for the multiple definitions is that "extern pClass Object1" in fileB.h. As an unresolved external, when an object file includes it, the linker pulls in the object where it is defined, which is is fileB.o. The linker pulls in the entire fileB.o and not just a single symbol from it, so the function definitions get pulled in too. Thus, when the unit test code compiles and has the spy definition, it compiles fine. But when the linker tries to link in the static library, it finds another definition and the link fails.

Instead of trying to override a function call in the static library by having the linker find the spy version first, I ended up giving the spy a slightly different name and using the preprocessor to swap it in for the unit test. This allows the production code to remain untouched. It's similar to, but not exactly the same as, the answer selected in Override a function call in C, because the spy and its preprocessor directives are defined in a separate file which can be included in any unit test, so there is no need to register the substitutions in a particular header file.

Community
  • 1
  • 1
jasper77
  • 1,553
  • 5
  • 19
  • 31