- 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.
- 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. Analyze these files by opening kdevelop. We could compile it this way:
gcc -o code2 code2.c code3.c code4.c
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".
- 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.
gcc -c code2.c
gcc -c code3.c
gcc -c code4.c
gcc -o code2 code2.o code3.o code4.o
- 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.
- nm code2 - try this command 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.
Cem Ozdogan
2010-02-18