



Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
An in-depth look into the process of compiling a simple C program using the gcc compiler in Linux. It covers the role of the preprocessor, compiler, assembler, linker, and libraries in creating an executable. The document also explains how to compile, run, and name the executable.
Typology: Slides
1 / 6
This page cannot be seen from the preview
Don't miss anything!




For this lecture, we will learn how to write, compile, and run a very basic C program, and we will discuss the steps that are involved in creating the executable. The following C program prints out the text “Hello world!” to the screen:
/*
*/ #include<stdio.h>
int main(void) { printf("Hello world!\n"); }
To compile this program, we will be using the gcc compiler in Linux, which stands for “Gnu Compiler Collection”, and it is used as follows:
$ gcc hello.c
This creates an executable called a.out. To run the executable, you would type
$ ./a.out Hello world!
If we wanted to create an executable that is named something other than a.out, we would use the -o option in the form
$ gcc -o hello hello.c
and we could run the hello executable with
$ ./hello Hello world!
In what follows we will go over the details of what actually happens when you invoke the C compiler gcc.
When you invoked the gcc compiler, a series of steps were performed in order to generate an executable from the text you entered as your C program. These steps are as follows
Source Code (hello.c) ↓ Preprocessor ↓ Compiler ↓ Assembly Code ↓ Assembler ↓ Object Code (hello.o)
Libraries ↓ Linker ↓ Executable (a.out or hello)
The main function of the C preprocessor is to remove comments from the source code and interpret preprocessor directives which are given by the statements that begin with #. In our simple hello.c code, the preprocessor would strip the source of the comments contained within the /.../ and would include the file called stdio.h, which contains the standard input/output functions that are usually called within a C program. The #include statement can either be called with
#include<file.h>
or with
#include ‘‘file.h’’
The first method tells the preprocessor to look for the file in the standard include directories, which for Linux are in /usr/include. The second method, which uses the quotes, tells the preprocessor that the file to be included is in the local directory. We will go into more detail on different preprocessor directives as we look at different facets of the C programming language.
The object file hello.o contains a binary version of the machine language that was created from your source code hello.c. In order to create the executable hello or a.out, you need to use the linker to process your main function and any possible input arguments you might use, and link your program with other programs that contain functions that your program uses. In this very simple example, we used the printf function. The printf function is a standard function that is provided by the C compiler that your current object file knows nothing about. In order to use this function, we need to use the linker in order to link our program with the precompiled libraries provided to us by the C compiler. The linker links other precompiled object files or libraries together and creates the executable hello. When you type
$ gcc -o hello hello.c
the gcc compiler creates an object file and does the linking for you. However, when you use the -c option, you create an object file called hello.o. In order to link this object file and create the executable, you can do the linking yourself by again using the gcc compiler, but this time you provide the object files as the command line arguments rather than the source codes. Then you would type
$ gcc hello.o -o hello
When gcc sees object files, it invokes the linker automatically and links the necessary files to create the hello executable.
The beauty of the C programming language is that C itself is a relatively simple and small compiler. The power of C becomes obvious when you use the wealth of precompiled libraries that have already been written that you can use in your codes. We will illustrate the use of one of the standard C libraries in an example. Let’s say we would like to use the math library in order to take the square root of the number 7 in our C code. All of the standard libraries in Linux are located in the /usr/lib directory. With every standard library, there is a header file that contains information about how to execute each of the functions in that library. In order to determine which header file contains the function we are looking for, we use the man 3 command at the command prompt. Let’s say we want to know which header file contains the sqrt function and how to use this function. To do so, we type
$ man 3 sqrt
This give us information about the function and the appropriate header file to use
NAME sqrt - square root function
#include <math.h>
double sqrt(double x);
From this we know that in order to use the sqrt function, we need to use it as sqrt(7), since the number 7 will be type cast as a double precision number. This also tells us that details about the sqrt function can be found in /usr/include/math.h. Our simple C program that computes square root of 7 would then be given by (Leaving out the lengthy comments for space-conservation, but you should never leave out comments! In this case we use shorter comments with the //):
// Program math.c int main(void) { sqrt(7); }
If we try and compile our program, we will see that we get an error:
$ gcc math.c -o math /tmp/cciMjg1a.o: In function ‘main’: /tmp/cciMjg1a.o(.text+0x1b): undefined reference to ‘sqrt’ collect2: ld returned 1 exit status
This is an error given to us by the linker. In this case the linker is complaining to us of an “undefined reference to sqrt”. When you get this error, it means that you did not provide enough information to the linker because you need to tell the linker where the sqrt function exists. You can tell the linker where certain libraries exist that must be linked with your program with the -l flag. In our case, the standard math library is linked with our program using the -lm flag, as in
$ gcc math.c -lm -o math
Compilation occurs without errors because the linker was able to find the sqrt function in the standard math library. Note that in our first simple program hello.c, we did not need to do any linking because functions in the standard C library like printf are automatically linked with the linker. We could, however, have use the linker implicitly with
$ gcc -o hello.c -lc -o hello
and this would have linked our program with the standard C library. But the -lc flag is redundant here because gcc does this linking automatically.
Now let’s assume that in our program we would also like to use a variable that is defined in the standard math library. Variables are defined in C programs using the #define precompiler directive. We will get into this in more detail later, but for now let’s say we need to use the M_PI variable that is defined in the math library, which is in /usr/include/math.h. We can find the line with the grep command with