'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:
- Preprocessing
- Compilation
- Assembly
- Linking
This article gives some useful information about how to break up the compilation steps. And so I came up with the following:
Preprocessing
cpp helloworld.cpp > helloworld.i
Compilation
g++ -S helloworld.i
Assembly
as -o helloworld.o helloworld.s
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 commandg++ -Q -v -o hello hello.cpp
and take a look at the last line whereg++
invokescollect2
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 |