6

I want to be able to use Cmockery to mock C functions called from C++ code I'm testing. As a step towards that, I've renamed the Cmockery example run_tests.c to run_tests.cpp, and am attempting to compile and link it with cmockery.c:

g++ -m32 -DHAVE_CONFIG_H -DPIC -I ../cmockery-0.1.2 -I /usr/include/malloc -c run_tests.cpp -o obj/run_tests.o
gcc -m32 -DHAVE_CONFIG_H -DPIC -Wno-format -I ../cmockery-0.1.2 -I /usr/include/malloc -c ../cmockery-0.1.2/cmockery.c -o obj/cmockery.o
g++  -m32 -o run_tests obj/run_tests.o obj/cmockery.o

The first two command lines (to compile) are successful, but after the last I get:

Undefined symbols:
  "_run_tests(UnitTest const*, unsigned long)", referenced from:
      _main in run_tests.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

That undefined symbol is from line 29 of run_tests.cpp:

return run_tests(tests);

The run_tests() function is defined in cmockery.c.

After reading "Linking C++ code with 'gcc' (without g++)", I tried:

gcc -lstdc++ -m32 -o run_tests obj/run_tests.o obj/cmockery.o

But got the same result:

Undefined symbols:
  "_run_tests(UnitTest const*, unsigned long)", referenced from:
      _main in run_tests.o
ld: symbol(s) not found
collect2: ld returned 1 exit status

How do I compile and link C++ code so it finds the symbols in C code?

Community
  • 1
  • 1
Daryl Spitzer
  • 143,156
  • 76
  • 154
  • 173
  • None of the answers (at the time of writing this comment) make it clear that I don't need to modify cmockery.h. I can put the `extern "C"` declaration around the `#include ` in run_tests.cpp. I'll accept the first answer to make this clear. – Daryl Spitzer Jan 04 '11 at 21:13

4 Answers4

7

I think that you can get thinkgs to link from C++ by adding the following around the contents of the cmockery.h file:

At or near the beginning:

#if defined(__cplusplus)
extern "C" {
#endif

At or near the end:

#if defined(__cplusplus)
}
#endif

That way, use of the header in C sources will ignore the extern "C" part of the declaration, but when the header is include in C++ builds, the compiler will be properly told that the linkage for the declarations in that header use C semantics.

For a quick-n-dirty test or if you'd rather not modify the header, you can try:

extern "C" {
#include "cmockery.h"
}

but my preference would be to put the extern "C" block in the header (and only around the stuff that's required - that might need a bit of analysis).

Michael Burr
  • 333,147
  • 50
  • 533
  • 760
  • Why do you consider putting the `extern "C"` around the `#include` "quick-n-dirty"? – Daryl Spitzer Jan 04 '11 at 22:13
  • In the general case because it might apply the `extern "C"` modifier to stuff that doesn't expect it (in particular if the header includes other headers that are C++ aware). Headers could handle this by using the `extern "C++"` declaration spec, but I've only seen that used once to handle this case (probably because it's little known, and it's not needed nearly as much as the `extern "C"` version). – Michael Burr Jan 06 '11 at 01:34
5

In your header files included by your C++ code, you need extern "C" declarations for all the functions that are compiled in C.

Karl Bielefeldt
  • 47,314
  • 10
  • 60
  • 94
2

when you include the C header files from C++, have you wrapped the prototypes with extern "C" { .... }? If you don't the C++ function name wil be 'mangled' at link time.

2

As Karl said, extern "C" { .. } is needed.

The reason: C++ mangles the names (adds funny characters) so that linking is type safe. C doesn't, so in that language linking foo(int) to foo(double) is possible (but wrong and embarrassing).

For successful interoperability, you need to tell the C++ compiler that some function names are not to be mangled, in order for linking to succeed.

Macke
  • 24,812
  • 7
  • 82
  • 118