Let’s compile a C program by hand. The aim is to compile the
a.c program.
$cat a.h
#define AA 100
$cat a.c
#include “a.h”
main()
{
printf(“%d
apples”, AA);
exit(19);
}
$
So, this is the program we really wanted to compile.
$gcc a.c –o a.exe
$./a.exe
100 apples$
$
To know what’s happening behind the scene, do this:
[kongkon@cadbury ~]$ gcc -v a.c
Reading specs from /usr/lib/gcc/i386-redhat-linux/3.4.3/specs
Configured with: ../configure
--prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --enable-shared --enable-threads=posix --disable-checking
--with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions
--enable-java-awt=gtk --host=i386-redhat-linux
Thread model: posix
gcc version 3.4.3 20050227 (Red Hat
3.4.3-22.1)
/usr/libexec/gcc/i386-redhat-linux/3.4.3/cc1
-quiet -v a.c -quiet -dumpbase a.c -auxbase a -version -o /tmp/ccfWiYm9.s
ignoring nonexistent directory
"/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../../i386-redhat-linux/include"
#include "..." search
starts here:
#include <...> search starts
here:
/usr/local/include
/usr/lib/gcc/i386-redhat-linux/3.4.3/include
/usr/include
End of search list.
GNU C version 3.4.3 20050227 (Red
Hat 3.4.3-22.1) (i386-redhat-linux)
compiled by GNU C version 3.4.3
20050227 (Red Hat 3.4.3-22.1).
GGC heuristics: --param
ggc-min-expand=98 --param ggc-min-heapsize=128313
as -V -Qy -o /tmp/ccyJwUTb.o /tmp/ccfWiYm9.s
GNU assembler version 2.15.92.0.2
(i386-redhat-linux) using BFD version 2.15.92.0.2 20040927
/usr/libexec/gcc/i386-redhat-linux/3.4.3/collect2
--eh-frame-hdr -m elf_i386 -dynamic-linker /lib/ld-linux.so.2
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../crt1.o
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../crti.o
/usr/lib/gcc/i386-redhat-linux/3.4.3/crtbegin.o
-L/usr/lib/gcc/i386-redhat-linux/3.4.3
-L/usr/lib/gcc /i386-redhat-linux/3.4.3
-L/usr/lib/gcc/i386-redhat-linux/3.4.3/../../.. /tmp/cc
yJwUTb.o -lgcc --as-needed -lgcc_s --no-as-needed -lc -lgcc --as-needed
-lgcc_s
--no-as-needed /usr/lib/gcc/i386-redhat-linux/3.4.3/crtend.o
/usr/lib/gcc/i386-redhat-linux/3.4.3/../../../crtn.o
[kongkon@cadbury ~]$
Understood? It’s really hard to understand. Let me explain a
little, and then things will look simpler. The –v switch to gcc explains what
gcc has done with the compilation process. Now, first of all what is gcc? gcc
is the compiler like everyone would say. Yes, it is the compiler. Actually it is a
wrapper, which calls different programs to compile the C program: if you look
at the –v output more closely you will see that, gcc calls "cpp", the C preprocessor
first, then "cc1", the C compiler, and then "as", the assembler. As an output we
get the object file, the same what we get by running “gcc –c a.c”. Here we take
help of the linker, "ld", to link a.o with our library for printf, since we have
not written code of printf() of our own. We need to link our a.o with libc.so for printf
code, as specified by -lc. This outputs a.exe, out executable. Run this, and
enjoy 100 apples.
Let’s do every thing by hand. Let’s call all of them one by
one. First the C preprocessor, cpp.
[kongkon@cadbury ~]$ cpp a.c
# 1 "a.c"
# 1 ""
# 1 ""
# 1 "a.c"
# 1 "a.h" 1
# 2 "a.c" 2
main()
{
printf("%d apples",100);
exit(19);
}
[kongkon@cadbury ~]$
cpp by default dumps the output in the console, redirect it
to a file, call it a.i.
[kongkon@cadbury ~]$ cpp a.c -o a.i
[kongkon@cadbury ~]$
[kongkon@cadbury ~]$ ls a.*
a.c
a.h a.i
[kongkon@cadbury ~]$
Next is the C compiler, cc1.
[kongkon@cadbury ~]$ cc1 a.i
-bash: cc1: command not found
[kongkon@cadbury ~]$
Oops! Bash did not find cc1, he does not know where is cc1. Take the help of gcc
itself to find where cc1 is. Do this:
[kongkon@cadbury ~]$ gcc
-print-prog-name=cc1
/usr/libexec/gcc/i386-redhat-linux/3.4.3/cc1
[kongkon@cadbury ~]$
Next, compile a.i, not a.c.
[kongkon@cadbury ~]$
/usr/libexec/gcc/i386-redhat-linux/3.4.3/cc1 a.i
main
Execution times (seconds)
parser : 0.01 (100%) usr 0.00 ( 0%) sys 0.00 ( 0%) wall
TOTAL : 0.01 0.00 0.01
[kongkon@cadbury ~]$
[kongkon@cadbury ~]$ ls a.*
a.c
a.h a.i a.s
This produces a.s.
Now, call the assembler, to create the object file, a.o.
[kongkon@cadbury ~]$ as a.s -o a.o
So, we have the object file here, a.o.
[kongkon@cadbury ~]$ ls a.*
a.c
a.h a.i a.o
a.s
[kongkon@cadbury ~]$
Now, call the linker program, ld.
[kongkon@cadbury ~]$ ld -o a.exe
a.o -e main -lc -dynamic-linker /lib/ld-linux.so.2
[kongkon@cadbury ~]$ ls a.*
a.c
a.exe a.h a.i
a.o a.s
[kongkon@cadbury ~]$
So, here we have the executable binary a.exe.
Run this and you will see the same output as we did in our
first step.
[kongkon@cadbury ~]$ ./a.exe
100 apples[kongkon@cadbury ~]$
Check whether the program exited successfully.
kongkon@cadbury ~]$ echo $?
19
[kongkon@cadbury ~]$
So, we have successfully compiler a C program. Happy
programming.
The thread ends here.