0

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?

user32882
  • 5,094
  • 5
  • 43
  • 82
  • You usually don't need to specify standard libraries? The linker should get these automatically. Do you have some problems with that? – πάντα ῥεῖ May 10 '22 at 14:38
  • Like I said, this is for educational purposes.I'm aware that I can compile everything in one go without having to worry about specifying the standard libraries – user32882 May 10 '22 at 14:39
  • Any consistent compiler installation would have standard libraries such as `iostream` available. – Fred Larson May 10 '22 at 14:44
  • The output *is* very verbose, but as the article says, you only need to look at the last line, which invokes `collect2`. The `-L` options are library locations, and the `-l` options are actual libraries. The inputs named "*.o" are linked object files rather than libraries. – molbdnilo May 10 '22 at 14:44
  • So which should I include in my `ld` invocation? The `-L` options or the `-l` options? Or both? – user32882 May 10 '22 at 14:48
  • @user32882 both, they have completely different meanings. – πάντα ῥεῖ May 10 '22 at 14:58
  • 1
    Prefer to use `g++` to link rather than `ld`. But if you must use `ld`, [there are ways](https://stackoverflow.com/q/14163208/10077). – Fred Larson May 10 '22 at 15:18
  • @FredLarson Is there a way to get `g++` to **only** link? – user32882 May 11 '22 at 04:44
  • @user32882: Sure, just feed it only object and library files. – Fred Larson May 11 '22 at 13:19

2 Answers2

0

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.

Employed Russian
  • 199,314
  • 34
  • 295
  • 362
0

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.

user32882
  • 5,094
  • 5
  • 43
  • 82