LAPACK, gcc, and g++

I have simple C code that compiles with gcc but not with g++ (as found here). It uses a LAPACK function (“dgtsv”, which solves a tridiagonal system); while gcc links to the library just fine, g++ is spouting an “undefined reference” error.

To compile, I’m simply changing “gcc” to “g++”. Since gcc compiles and produces an executable that…umm…executes, I know the appropriate libraries are installed and operational. What difference between the two compilers am I missing (and have just spent hours trying to google)?

While I realize I should probably ask this on a more programmer-oriented site, I figured there are enough programming literates here that I’d ask and see if anyone had a quick answer. Especially since, at the moment, I’m eating lunch and browsing the threads. :slight_smile:

There are two problems here:

a) g++ stupidly assumes that any file that you compile with it is a C++ file, even if it has a .c extension.
b) The header for your library is broken. It should start with:


#ifdef __cplusplus
extern "C" {
#endif

and end with


#ifdef __cplusplus
}
#endif

The easiest way to fix this, if you can’t modify the headers, is to wrap the #include with that extern “C” bit, like this:


#ifdef __cplusplus
extern "C" {
#endif
#include "whatever.h"
#ifdef __cplusplus
}
#endif

Thanks, Rysto, but I’m not sure that helps. At least, I don’t know how to use that info to get this to work.

The issue, or at least part of it, I think, is that LAPACK is a Fortran library, and the (semi-)related C libraries only implement a subset of the actual functions. In fact, there isn’t a lapack.h file in /usr/include/, although there is a liblapack.a in /usr/lib/. From what I gather, that’s why it’s necessary to include the “-lg2c” switch in the gcc command – to dynamically link Fortran libraries to C, as outlined in the link I provided above. And I did run the “nm” command on liblapack.a, just to make sure the symbol was defined (it is…might the problem have something to do with name-mangling?).

If you follow that link and look at the code, there is an extern in there, although it’s not accompanied by the “C” signifier. Suspecting it wouldn’t work, I did try to put the “C” in there, but g++ choked on it with an “expected unqualified-id before string constant” error.

Any other explanation you might suggest?

Aside: I’d not seen someone do a wrapper to access a library function like this before within a C program. Pretty nifty…at least, it would be if I could get it to do my bidding!

extern “C” {
#include “clapack.h”
}

will work. there is no “lapack.h” -lg2c links to “libg2c.a” not lapack. you need to specify -llapack to link to “liblapack.a” if gcc can’t find the library itself. If the library is in a weird directory use -Lpath to tell gcc to look for it there.

Thanks for the reply, Alex_Dubinsky, but…

…the issue (or, at least part of it) is that clapack is an incomplete implementation of the LAPACK library, so the header file doesn’t include a prototype for the function I need. And, just for clarity, the purpose of the “-lg2c” switch isn’t to link specifically to the LAPACK library, but to enable linking to a Fortran library.

So, for those who have any interest in this, I’ve resolved it enough to do what I want, and I believe I understand what the underlying issues was. First, what worked:

I came across this post, which indicates that the problem was indeed declaring the function as extern “C”. After adding such a declaration, the test program compiled without a problem, and executed just fine. I’ve added something similar to my own header file and it compiled; I haven’t tested execution yet, as there are some details I still need to address (e.g., row-major matrices in C vs. column-major in Fortran, actual test data, etc.), but I expect it to work as advertised.

Now, the underlying issue: I’m pretty sure it’s the name-mangling that C++ does (after all, isn’t that the whole reason for the “C” part of extern “C”?), compounded by the fact that there isn’t a proper header file for the LAPACK library. And it was even further exacerbated by the unknown-to-me style found in my first link (embedding an extern within a function). So, the practical outcome is that while this:


...
static long
dgtsv(long N, long NRHS, double *DL, double *D, double *DU, double *B, long LDB) {
  extern void dgtsv_(const long *Np, const long *NRHSp, double *DL, double *D, double *DU, double *B, const long *LDBp, long *INFOp);
  long info;
  dgtsv_(&N, &NRHS, DL, D, DU, B, &LDB, &info);
  return info;
}
...

works in C, it doesn’t work in C++. However, the following compiles and executes with both gcc and g++:


...
#ifdef __cplusplus
  extern "C" void dgtsv_(const long *Np, const long *NRHSp, double *DL, double *D, double *DU, double *B, const long *LDBp, long *INFOp);
#else
  extern void dgtsv_(const long *Np, const long *NRHSp, double *DL, double *D, double *DU, double *B, const long *LDBp, long *INFOp);
#endif
...
static long
dgtsv(long N, long NRHS, double *DL, double *D, double *DU, double *B, long LDB) {
  long info;
  dgtsv_(&N, &NRHS, DL, D, DU, B, &LDB, &info);
  return info;
}
...

Took me a few hours to figure out, but it’s definitely something I’m not likely to soon forget. :slight_smile:

Yeah. One of the places where C++ is not backwards-compatible with C is that C lets you declare nested functions. Actually, nested functions aren’t even a feature of the C standard, but of gcc. Funny that it’s g++ that’ll refuse them. They don’t offer much functionality, but they’re a nice way to make code neat.

Your example is only a declaration (with an extern qualifier). In C, you can also put a full function, with its body, inside another function. The nested functions can use variables of the containing function, and can’t be called outside the containing function. They’re “useless” but good for organization (factoring long code while keeping the headers simple). It’s a shame they got taken out.

It’s really interesting to me that I’ve never encountered this before. Not that I’m a hard-core C/C++ guy, having spent the last 6 years as a CS grad student doing mostly Java. But still…I find it surprising.

One of the motivating factors for tackling this current project was to brush up on my C/C++ coding, so it’s been beneficial in that respect. Thanks for the interest and replies.

Only gcc, though: If you have to compile with another compiler, you’ll have to change all of the code that relies on this trick.

For what it’s worth (not much, considering what you have works), the customary way to do what you did is to do this:



#ifdef __cplusplus
  extern "C" {
#endif

void dgtsv_(const long *Np, const long *NRHSp, double *DL, double *D, double *DU, double *B, const long *LDBp, long *INFOp);

#ifdef __cplusplus
  }
#endif


…that way you don’t have two seperate function decls that you need to fix up if the prototype changes.

:smack: Good point. Don’t know why that didn’t occur to me.