Next: Exercises
Up: Compiling A C Program
Previous: Running The Resulting Program
Contents
- So we learned how to compile a single-source program properly. Yet, sooner or later you'll see that having all the source in a single file is rather limiting, for several reasons:
- As the file grows, compilation time tends to grow, and for each little change, the whole program has to be re-compiled,
- It is very hard, if not impossible, that several people will work on the same project together in this manner,
- Managing your code becomes harder. Backing out erroneous changes becomes nearly impossible.
- The solution to this would be to split the source code into multiple files, each containing a set of closely-related functions (or, in C++, all the source code for a single class).
- There are two possible ways to compile a multi-source C program.
- The first is to use a single command line to compile all the files.Suppose that we have a program whose source is found in files http://siber.cankaya.edu.tr/OperatingSystems/cfiles/code2.c code2.c, http://siber.cankaya.edu.tr/OperatingSystems/cfiles/code3.c code3.cand http://siber.cankaya.edu.tr/OperatingSystems/cfiles/code4.c code4.c . We could compile it this way:
$gcc code2.c code3.c code4.c -o code2
This will cause the compiler to compile each of the given files separately, and then link them all together to one executable file named "code2". Two comments about this program:
- If we define a function (or a variable) in one file, and try to access them from a second file, we need to declare them as external symbols in that second file. This is done using the C extern keyword.
- The order of presenting the source files on the command line may be altered. The compiler (actually, the linker) will know how to take the relevant code from each file into the final program, even if the first source file tries to use a function defined in the second or third source file.
- The problem with this way of compilation is that even if we only make a change in one of the source files, all of them will be re-compiled when we run the compiler again. In order to overcome this limitation, we could divide the compilation process into two phases - compiling, and linking. Lets first see how this is done, and then explain:
$gcc -c code2.c
$gcc -c code3.c
$gcc -c code4.c
$gcc code2.o code3.o code4.o -o code2
- The first 3 commands have each taken one source file, and compiled it into something called "object file", with the same names, but with a ".o" suffix.
- It is the "-c" flag that tells the compiler only to create an object file, and not to generate a final executable file just yet.
- The object file contains the code for the source file in machine language, but with some unresolved symbols. For example, the "code2.o" file refers to a symbol named "func_a", which is a function defined in file "code3.c".
- Surely we cannot run the code like that. Thus, after creating the 3 object files, we use the 4th command to link the 3 object files into one program.
- The linker (which is invoked by the compiler now) takes all the symbols from the 3 object files, and links them together - it makes sure that when "func_a" is invoked from the code in object file "code2.o", the function code in object file "code3.o" gets executed.
- Try the following command;
$nm code2
and recognize the definitions for "func_a" and "func_b".
- Further more, the linker also links the standard C library into the program, in this case, to resolve the "printf" symbol properly.
- To see why this complexity actually helps us, we should note that normally the link phase is much faster than the compilation phase. This is especially true when doing optimizations, since that step is done before linking.
- Now, lets assume we change the source file "code3.c", and we want to re-compile the program. We'll only need now two commands:
$gcc -c code3.c
$gcc code2.o code3.o code4.o -o code2
In our small example, it's hard to notice the speed-up, but in a case of having few tens of files each containing a few hundred lines of source-code, the time saving is significant; not to mention even larger projects.
Next: Exercises
Up: Compiling A C Program
Previous: Running The Resulting Program
Contents
Cem Ozdogan
2009-05-11