Using only g++ works, but not "g++ -c" and ld

21,219

Solution 1

I think if you use ld directly it does not include the C++ libraries by default. You can use g++ to do the linking as well, it will call ld with the correct settings.

g++ -c main.cpp
g++ -o main main.o

Solution 2

GCC internally links against a few additional libraries and object files. To see what those are, execute -###, which will print the tool commands it would execute, including the linker. The linker command used by my GCC is (I made the actual .o file I invoked g++ on bold, so you can spot it easily).

/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/collect2 --build-id --eh-frame-hdr -m elf_i386 "--hash-style=both" -dynamic-linker /lib/ld-linux.so.2 /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crt1.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crti.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/crtbegin.o -L/usr/lib/gcc/i686-pc-linux-gnu/4.6.0 -L/usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../.. main1.o "-lstdc++" -lm -lgcc_s -lgcc -lc -lgcc_s -lgcc /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/crtend.o /usr/lib/gcc/i686-pc-linux-gnu/4.6.0/../../../crtn.o

You can substitute the collect2 path by ld (if I remember correctly, collect2 is only needed as a proxy for the real ld by GCC backends that don't support modern binary formats, to collect constructor and destructor functions according to their mangled name. The ELF format has native sections support for that).

Executing that command, with ld substituted literally, successfully links the executable.

Solution 3

When you use g++, it also links the libstd++ library which linker uses to resolve the names. But using g++ -c and then ld do not link the library automatically. You've to link the library manually now.

Try (untested):

ld -o main main.o -llibstd++

Or you can look into the correct syntax by reading this manual:

Solution 4

Well, you didn't link in the standard library. g++ does this for you automatically; that's why we use it: it wraps calls to ccplus1 and ld with all the extras taken care of.

BTW, strictly speaking, the equivalent of g++ main.cpp -o main is:

cc1plus main.cpp -o main.o
ld -o main main.o

(cc1plus may well not be on your path; I found mine in /usr/libexec/gcc/i386-redhat-linux/4.1.1/)

g++ -c main.cpp does traditionally perform that first step. g++ main.cpp -o main wraps both.

g++ is a wrapper to the individual compilation and linkage tools, tuned for C++. As such, it provides arguments to cc1plus and ld as it sees fit, including the argument to link in the C++ Standard Library:

ld -o main main.o -llibstd++

It'll also link in the runtime and possibly some other stuff.

In general, there is no need to try to do these things yourself: let g++ take care of it.

Share:
21,219
Valentin Lorentz
Author by

Valentin Lorentz

Updated on August 03, 2022

Comments

  • Valentin Lorentz
    Valentin Lorentz almost 2 years

    I have the following source code in main.cpp:

    #include <iostream>
    #include <iomanip>
    
    int main() {
        std::cout << "Hi" << std::endl;
        return 0;
    }
    

    Using this command works, and creates the executable file:

    g++ -o main main.cpp
    

    But this commands don't work:

    g++ -c main.cpp
    ld -o main main.o
    

    The second one errors with:

    ld: warning: cannot find entry symbol _start; defaulting to 00000000004000e8
    main.o: In function `main':
    main.cpp:(.text+0xa): undefined reference to `std::cout'
    main.cpp:(.text+0xf): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)'
    main.cpp:(.text+0x14): undefined reference to `std::basic_ostream<char, std::char_traits<char> >& std::endl<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&)'
    main.cpp:(.text+0x1c): undefined reference to `std::ostream::operator<<(std::ostream& (*)(std::ostream&))'
    main.o: In function `__static_initialization_and_destruction_0(int, int)':
    main.cpp:(.text+0x4a): undefined reference to `std::ios_base::Init::Init()'
    main.cpp:(.text+0x4f): undefined reference to `std::ios_base::Init::~Init()'
    main.cpp:(.text+0x54): undefined reference to `__dso_handle'
    main.cpp:(.text+0x61): undefined reference to `__cxa_atexit'
    
  • hailinzeng
    hailinzeng almost 7 years
    the flag to link with libstdc++ library is -lstdc++