... undefined reference to ... collect2: ld returned 1 exit status

18,046

Solution 1

Why do you have these lines in error.cpp?

#ifdef error_h
  ...
#endif

Since the preprocessor symbol error_h is not defined the entire contents of error.cpp are being omitted by the preprocessor. Remove those lines and your program will link successfully.

You seem to have a misunderstanding of how (and maybe why) #include guards are to be used. Refer to this answer for an explanation.

Also, there's no need to include iostream and cstdio in error.h, since that file is not using anything declared in either of those headers. Those files should be included in error.cpp.

Solution 2

error_h is not defined in error.cpp, so all your file content gets #ifdef'd away.

In essence, you're compiling error.cpp as an empty file.

Solution 3

Remove this

#ifdef error_h

and the corresponding #endif from error.cpp. Otherwise, here:

$ g++ -c error.cpp foobar.cpp

error.cpp is essentially empty. This is because at that stage error_h is not defined. So you are not compiling the implementation (it would work if you had included error.h before the #ifdef, but there is no reason to have that in the .cpp file anyway).

Share:
18,046
user1358
Author by

user1358

Updated on June 05, 2022

Comments

  • user1358
    user1358 almost 2 years

    I have the following 3 files:

    error.h

    #ifndef error_h
    #define error_h
    #include <string>
    #include <iostream>
    #include <cstdio>
    void Error(std::string msg);
    #endif
    

    error.cpp

    #ifdef error_h
    #include "error.h"
    void Error(std::string msg)
    {
        std::cerr
         << "\n=========================================================\n"
         << msg
         << "\n=========================================================\n";
        exit(EXIT_FAILURE);
    }
    #endif
    

    foobar.cpp

    #include "error.h"
    int main()
    {
        for(int i=0; i<99; i++)
            if(i==55)
                Error("this works");
        return 0;
    }
    

    Now I do:

    $ g++ -c error.cpp foobar.cpp
    $ g++ error.o foobar.o -o exampleprogram
    

    And I get:

    foobar.o: In function `main':
    foobar.cpp:(.text+0x4b): undefined reference to `Error(std::basic_string<char,
    std::char_traits<char>, std::allocator<char> >)'
    collect2: ld returned 1 exit status
    

    What am I doing wrong? What do I need to understand to resolve this, and similar issues in the future without asking questions? Thanks!

  • user1358
    user1358 over 11 years
    Thank you! I have been doing a lot of ".cpp including" of template implementations lately and I just typed these without thinking and overlooked them the whole time. You mentioned iostream and cstdio includes... does this mean that I have to scatter around some of the includes? Some in the .h and some in the .cpp? Is #include <string> needed by the function prototype? Isn't there a way of bundleing all the includes for a .h and .cpp in general? Thanks again.
  • Praetorian
    Praetorian over 11 years
    @user1358 Best practice is to only include the headers that are actually needed in that file, so yes, includes tend to be scattered around. There's nothing incorrect about including both the headers in error.h, but when you include error.h in main.cpp, the preprocessor will include the files in the translation unit created from main.cpp and the compiler will have to process those headers as well. Not really a concern in small projects, but for large projects this can significantly impact build times.
  • user1358
    user1358 over 11 years
    Your explanations helped a lot. Thank you very much.