5

I'm trying to use two large, complex linear algebra libraries which define many of the same functions. I can't rewrite (legally in one case, but technically in both) either of them. Let's call them "special" and "normal" because I only call a couple functions from special. To consistently call functions defined in normal.h and only in some cases from special.h, I've done something like this:

namespace special_space
{
#include "special.h"  // Defines foo()
}

#include "normal.h"   // Defines foo()

int main() {
  foo();                // Calls foo() defined in normal.h
  special_space::foo(); // Calls foo() defined in special.h
}

With g++-4.4, which was the default where I was developing this, the code compiles and links without warnings, and it executes as I would expect and as I want. This seems to be consistent across platforms, various Linux, Unix and BSD environments. But! if I compile with g++ >4.4, I get warnings about multiple foo() definitions:

In file special.h::line:col: warning: declaration of ‘void special_space::foo()’ with C language linkage [enabled by default]

The resulting executable then segfaults at the call to special_space::foo(). I /think/ that specifying extern "C++" in the definitions found in special.h might fix this, but I'm not allowed to change special.h. So what should I do? More specifically:

1) Is it safe to use g++-4.4? If so -- what changed in subsequent versions and why?

2) If specifying the C++ linkage model really would fix this, is there a way to tell ld to use it by default?

3) If neither of those -- is there another way to call functions from libraries that define functions of the same name?

gerowam
  • 383
  • 1
  • 11
  • 2
    Do both functions have C-linkage originally? If yes: [C functions disable name mangling](http://stackoverflow.com/questions/9685994/c-extern-c-functions-inside-a-namespace) – WorldSEnder Jul 08 '15 at 16:07
  • 1
    Try wrapping both includes in ` #ifdef __cplusplus extern "C" { #endif #include normal.h #ifdef __cplusplus } #endif' – rost0031 Jul 08 '15 at 16:09
  • 1
    If you can't change the libraries then they already have a particular linkage model, and you can't change that. – nneonneo Jul 08 '15 at 16:18
  • @rost0031 That worked! Thanks! I still get warnings about multiple definitions, but no segfault. Feel free to post (and maybe explain?) the answer. – gerowam Jul 08 '15 at 16:30
  • @gerowam: done and done. – rost0031 Jul 08 '15 at 16:57

1 Answers1

1

So as I posted in a comment, wrap the headers includes with

#ifdef __cplusplus
extern "C" {
#endif

#include normal.h

#ifdef __cplusplus
}
#endif

Do this with both headers.

Basically, since you're linking c libraries from c++, which does name mangling (this is what allowes overloading), your calls to the symbols in your c lib were being mangled by the linker. The #ifdef __cplusplus tells the linker not to mangle the names for those specific function symbols.

Ideally, the creators of the library should include this in their headers but you mentioned that you have no control over that. I had a similar problem with some generated code. I had to wrap all my header includes of the generated code in this to allow C++ to call it.

What I don't know, is how it ever worked without this. I've definitely had to do this going back to gcc < 4.4.

rost0031
  • 1,894
  • 12
  • 21
  • To name names: the problematic headers were from GSL (gsl/gsl_linag.h and gsl/gsl_blas.h) and Intel's MKL (mkl.h and mkl_lapacke.h). – gerowam Jul 09 '15 at 15:49