'How can I make sure `iostream` is available to the linker?

I have the following C++ code in a file called helloworld.cpp:

#include<iostream>

int main()
{
    std::cout << "Hello, World!\n";
}

I would like to compile this manually so I can really understand how the compilation steps work with gcc, namely:

  1. Preprocessing
  2. Compilation
  3. Assembly
  4. Linking

This article gives some useful information about how to break up the compilation steps. And so I came up with the following:

  1. Preprocessing cpp helloworld.cpp > helloworld.i

  2. Compilation g++ -S helloworld.i

  3. Assembly as -o helloworld.o helloworld.s

  4. Linking ld -o helloworld helloworld.o

Everything seems to work except for the last step, as outlined by the article:

ld -o hello hello.o ...libraries...

The libraries argument above is a long list of libraries that you need to find out. I omitted the exact arguments because the list is really long and complicated, and depends on which libraries g++ is using on your system. If you are interested to find out, you can run the command g++ -Q -v -o hello hello.cpp and take a look at the last line where g++ invokes collect2

And so I tried running g++ -Q -v -o helloworld helloworld.cpp, but the result is extremely verbose.

I'm still unsure how to complete ld such that iostream can be available to the linker when I invoke it. How can I make sure iostream is available to the linker?



Solution 1:[1]

Based on the comments and posted answer I realized that the blog from which I was copying those commands makes things more complicated than they really need to be for my purposes. It's definitely possible to isolate every step of the compilation process using solely the g++ command. Here's a Makefile I came up with:

all: preprocess compile assemble link

# helloworld.i contains preprocessed source code
preprocess:
    @echo "\nPREPROCESSING\n"; g++ -E -o helloworld.i helloworld.cpp

# compile preprocessed source code to assembly language. 
# hello.s will contain assembly code
compile:
    @echo "\nCOMPILATION\n"; g++ -S helloworld.i

# convert assembly to machine code
assemble:
    @echo "\nASSEMBLY\n"; g++ -c helloworld.s

# links object code with the library code to produce an executable
# libraries need to be specified here
link:
    @echo "\nLINKING\n"; g++ helloworld.o -o test

clean:
    @find -type f ! -name "*.cpp" ! -name "*.h" ! -name "Makefile" -delete

Now I can compile my C++ programs in such a way that I can track whether the preprocessor, compiler, assembler or linker is generating the error.

Solution 2:[2]

I'm still unsure how to complete ld such that iostream can be available to the linker when I invoke it.

You should never use ld to link any user-level programs, only when you are linking something esoteric, like an OS kernel or a boot loader.

Instead, (for user-level program) always use appropriate compiler driver (g++ here).

While you can find out how the compiler driver eventually invokes ld internally (e.g. using strace -fe execve -s 1024 g++ ...), note that that command may change from version to version, and depends on a multitude of flags (-pie vs. -no-pie, -shared, -static etc.) and you chances of continuing to use correct ld command after a few months are nil.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 user32882
Solution 2 Employed Russian