I bump into Compiling a C++ program with gcc today, and think it is a very interesting topic. So I do the following tests:
(1) Create a canonical C
source file:
$ cat main.c
#include <stdio.h>
void hello(void)
{
printf("Hello World!\n");
}
int main(void)
{
hello();
}
Use gcc
to compile it and search hello
in symbol table of executable file:
$ gcc main.c
$ readelf -s a.out | grep hello
53: 00000000004004f6 17 FUNC GLOBAL DEFAULT 13 hello
Then use g++
to compile it and also search hello
in a.out
:
$ g++ main.c
$ readelf -s a.out | grep hello
54: 0000000000400526 17 FUNC GLOBAL DEFAULT 13 _Z5hellov
Since hello
is name mangled to _Z5hellov
when using g++
, we can make sure that g++
will compile *.c
file as C++
.
(2) Modify main.c
to a standard C++
file:
$ cat main.cpp
#include <iostream>
void hello(void)
{
std::cout << "Hello, world!" << std::endl;
}
int main(void)
{
hello();
}
Use gcc
to compile it:
$ gcc main.cpp
/tmp/cccAb8IH.o: In function `hello()':
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&))'
/tmp/cccAb8IH.o: In function `__static_initialization_and_destruction_0(int, int)':
main.cpp:(.text+0x56): undefined reference to `std::ios_base::Init::Init()'
main.cpp:(.text+0x65): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status
We can see there are many link errors. The reason is when gcc
compiles *.cpp
file, it will employ C++
compiler, but it only use defaults C
and gcc
helpers libraries during linkage stage, and won’t use stdc++
library. Modify the command, then all is OK:
$ gcc main.cpp -lstdc++
$ readelf -s a.out | grep hello
41: 00000000004007f7 21 FUNC LOCAL DEFAULT 13 _GLOBAL__sub_I__Z5hellov
59: 0000000000400786 35 FUNC GLOBAL DEFAULT 13 _Z5hellov
Certainly , since it is a regular C++
file, use g++
will undoubtedly be OK:
$ g++ main.cpp
$ readelf -s a.out | grep hello
41: 0000000000400817 21 FUNC LOCAL DEFAULT 13 _GLOBAL__sub_I__Z5hellov
59: 00000000004007a6 35 FUNC GLOBAL DEFAULT 13 _Z5hellov
(3) Modify the above file name from main.cpp
to main.c
.
$ cat main.c
#include <iostream>
void hello(void)
{
std::cout << "Hello, world!" << std::endl;
}
int main(void)
{
hello();
}
Use g++
to compile it:
$ g++ main.c
$ readelf -s a.out | grep hello
41: 0000000000400817 21 FUNC LOCAL DEFAULT 13 _GLOBAL__sub_I__Z5hellov
59: 00000000004007a6 35 FUNC GLOBAL DEFAULT 13 _Z5hellov
All is OK, and the stdc++
library will be used during linkage stage.
Use gcc
instead:
$ gcc main.c
main.c:1:20: fatal error: iostream: No such file or directory
^
compilation terminated.
This error identifies gcc
always uses standard C
compiler to *.c
file, so it can’t find C++
related header files.
P.S. my gcc
version:
$ gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/6.3.1/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /build/gcc-multilib/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++ --enable-shared --enable-threads=posix --enable-libmpx --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release
Thread model: posix
gcc version 6.3.1 20170109 (GCC)