views:

306

answers:

7

I am integrating a medium-sized (10,000 or so lines) program written in C into a C++ program. I have created a new class, BWAGenome as an interface to the C code, so any access to the C functions is encapsulated. I am compiling everything with the g++ compiler. The .o files are all generated correctly, but when I attempt to link them together into a final executable, the compiler complains that it cannot find the symbols. Here is the error message I get:

Undefined symbols:
BWAGenome::BWTRestoreBWT(char const*)", referenced from:
  BWAGenome::BWAGenome(char const*)in BWAGenome.o
"BWAGenome::GetMatches(unsigned int, int, bwt_t*, bwt_t*, bwt_t*, bntseq_t*, bntseq_t*)", referenced from:
  BWAGenome::getMatches(unsigned int, int)in BWAGenome.o

These functions are all in the C++ class I made. They wrap functions in the C code, but I don't understand at all how the symbols could be undefined.

A few details about the code and what I have done so far:

  • Everything is compiled with g++, so if I understand correctly I don't need the extern "C" {}; surrounding the c header files I include.
  • All of the code compiles correctly individually. The error only occurs during linking.
  • I heard somewhere that the C code might need to be called from static functions, so I have tried wrapping each call to a C function inside a static class method and calling that instead.

Any ideas on how to solve this problem?


edit: added definitions and declarations of BWTRestoreBWT and GetMatches

//definition in BWAGenome.h
static bwt_t * BWTRestoreBWT(const char *fn);

//declaration in BWAGenome.cpp
static bwt_t * BWTRestoreBWT(const char *fn) {
    return bwt_restore_bwt(fn);
    //bwt_restore_bwt is a function in the C code that I am attempting to integrate
}

second edit: After much soul searching I realized the problem was pretty unrelated to most of what I thought it was. See my answer for details.

A: 

Have you checked that you really have the identically-shaped function declared?

It's looking for BWAGenome::BWTRestoreBWT(char const*), but maybe you have BWAGenome::BWTRestoreBWT(char *) (without a const) declared instead?

wallyk
Yep, checked and double-checked the function declarations. Anyways, wouldn't the compiler complain when first compiling the BWAGenome.o file, not when linking it together with everything else if this were the case?
Jergason
+2  A: 

I notice that it's looking for BWAGenome::BWTRestoreBWT and BWAGenome::GetMatches. Those are member functions its looking for, not root namespace global free functions.

Try changing calls to BWTRestoreBWT that are meant to be calls to your C function to be calls to ::BWTRestoreBWT in your code and see what happens. Do the same for calls to GetMatches.

And the person who told you that C functions need to be called from static C++ functions is dead wrong. That would force you to wrap the standard library in C++ static functions, and that's just silly.

Omnifarious
Do you mean adding the class before the function, so the call is BWAGenome::BWTRestoreBWT instead of BWARestoreBWT?
Jergason
No, I mean doing the exact opposite. Just put `::` in front of them to force the compiler to look for them in the global namespace where all the C style functions should be. Right now, for some reason, it's resolving to functions that are declared as member functions of the class.
Omnifarious
+2  A: 

try using nm program to get an output of symbols defined and referenced in your programs:

nm file.o | grep BWTRestoreBWT

You should see your symbols with either T or U. T means the name is defined, the later means the symbol is not defined but called. in order to link, for each U there must be corresponding T.

Make sure your functions do not have inline qualifiers unless they defined in header files.

aaa
+2  A: 

The more I think about this problem, the more it looks like you have the functions declared in your class declaration, but you have no corresponding definition for the functions.

For example, this example compiles just fine but produces the same linker errors you're seeing:

typedef unsigned int bwt_t;
typedef unsigned int bntseq_t;

class BWAGenome {
public:
    BWAGenome( char const* name);

    void BWTRestoreBWT( char const* name);

    void GetMatches( unsigned int, int, int, bwt_t*, bwt_t*, bwt_t*, bntseq_t*, bntseq_t*);
    void getMatches( unsigned int, int);

};

BWAGenome::BWAGenome( char const* name) 
{
    BWTRestoreBWT( name);
}

void BWAGenome::getMatches( unsigned int x, int y)
{
    GetMatches( x, y, 0,0,0,0,0,0);
}

int main()
{
    return 0;
}

Are the functions BWTRestoreBWT() and GetMatches() supposed to be part of class BWAGenome or are they the C functions that are being wrapped? If the latter, then that's an indication that you're including the header for those functions in the wrong place (and that they do, in fact, probably need to have an extern "C" linkage specification added).


Edit in response to new information in the question:


In your edited question you say:

//definition in BWAGenome.h
static bwt_t * BWTRestoreBWT(const char *fn);

//declaration in BWAGenome.cpp
static bwt_t * BWTRestoreBWT(const char *fn) {
    return bwt_restore_bwt(fn);
    //bwt_restore_bwt is a function in the C code that I am attempting to integrate
}

Because of the errors that are in your original question, I can only assume that the declaration of BWTRestoreBWT() in BWAGenome.h is inside of class BWAGenome, like so:

class BWAGenome {
    // etc...

    static bwt_t * BWTRestoreBWT(const char *fn);

    // etc...
};

This means that BWTRestoreBWT() is a member of class BWAGenome() so its definition should look like (note the BWAGenome:: scoping operator):

//declaration in BWAGenome.cpp
static bwt_t * BWAGenome::BWTRestoreBWT(const char *fn) {
    return bwt_restore_bwt(fn);
    //bwt_restore_bwt is a function in the C code that I am attempting to integrate
}

Or you can move the declaration of BWTRestoreBWT() outside of class BWAGenome (more formally known as 'namespace scope').

That should fix your current linker error. If you now get an error about something with a name similar to bwt_restore_bwt not being found, then you'll know you need to do extern "C" for the C functions as well.

Michael Burr
BWTRestoreBWT() and GetMatches() are part of BWAGenome, wrapping the C functions. I was under the impression that if I compiled the C code with g++ I didn't need to use the extern "C" around the header files. Is this wrong?
Jergason
it looks like you're running into a problem that's not directly related to whether or not the C functions are properly declared with `extern "C"`, since the linker isn't finding the C++ wrapper functions. Fix that problem first, then you can address the `extern "C"` issue (if necessary).
Michael Burr
+1  A: 

Have you told the linker where to find a library/object that contains the BWAGenome::BWTRestoreBWT function? Since you compile everything separately, you must link the output .o files explicitly.

The two reasons that may cause this link error are

  1. there is a definition of the saught names, but you didn't give it to the linker
  2. the object file you give the linker does not contain the method - i.e. you didn't implement it (or thought you did, but gave the implementation a 'wrong' name)
xtofl
+1  A: 

if you use static keyword with non-class member function, that function will have local linkage, meaning it is not going to be visible outside your compilation unit, i.e. .cpp file. you either have to get it of static keyword, or put function body into your include file.

In context of class member function, static has different meaning. In this case, static allows function to be called without instantiating class object.

aaa
A: 

The error was in the order I was linking the object files together. I needed to link in the C code first, and then the BWAGenome class I created to call it. The linker couldn't find the C code symbols because they weren't linked yet. Thanks for all your help though. I imagine I frustrated some people, but thanks anyways.

Jergason