Quick topics on compiling and linking in C/C++

From Wiki**3

This page provides basic examples of C/C++ compilation and linking. The objective is to provide a quick (although not complete) tour of how to organize code.

Even though neither C nor C++ impose code organization in files (this is done by, for instance, Java, where each public class must be defined in a file with the exact name of that class), we use a similar division as a way of producing better code. Thus, interfaces will reside in .h (header) files, and implementations will reside in .c or .cpp files. These latter sets of files are what we will call compilation units. File names will either be classes or will reflect that code functionality (this will be the norm, mostly, for C).

First Scenario: Without Libraries

The first scenario considers the following files, used to build the soup application:

  • soup.c - main body; uses the other components (uses .h files)
  • potato.c - potato implementation (interface in potato.h)
  • carrot.c - potato implementation (interface in carrot.h)
  • tomato.c - potato implementation (interface in tomato.h)

We assume the C language, but it could also be C++ (the idea is the same).

We assume that each vegetable is implemented as a function called by the main function. Further, we assume that all the vegetables are independent from each other (and that the soup depends on each of them).

Compiling each part

All parts are compiled separately, using the same command, but specific files.

 gcc -c soup.c -o soup.o
 gcc -c potato.c -o potato.o
 gcc -c carrot.c -o carrot.o
 gcc -c tomato.c -o tomato.o

Note that the -o part is optional in these commands.

Linking and running

Linking is carried out by the linker. In this case, we invoke it through GCC, so that we also get the C library and runtime and not just our .o files.

 gcc -o soup soup.o potato.o carrot.o tomato.o

Note that each vegetable provided a function needed by the soup and that the soup had unresolved references to such functions. It is the linker's task to "connect" (resolve/link) the references.

Second Scenario: Using Static Libraries

The basic assumptions are the same as in the first scenario. We assume that each vegetable is implemented as a function called by the main function. Further, we assume that all the vegetables are independent from each other (and that the soup depends on each of them).

As before, we assume the C language, but it could also be C++ (the idea is the same).

Compiling each part

All parts are compiled separately, using the same command, but specific files.

 gcc -c soup.c -o soup.o
 gcc -c potato.c -o potato.o
 gcc -c carrot.c -o carrot.o
 gcc -c tomato.c -o tomato.o

Note that the -o part is optional in these commands.

Creating the library

A static library is an archive of .o files. It can be created by the following command.

 ar cr libvegetables.a potato.o carrot.o tomato.o

More information on ar can be found in the manual pages. A Wikipedia page also exists: Ar_(Unix).

Linking and running

Linking is carried out by the linker. In this case, we invoke it through GCC, so that we also get the C library and runtime and not just our .o files.

If the library in installed in a standard location, the following command is sufficient to produce the executable. The -l flag assumes that the library is named libNAME.a (in this case, the flag is simply -lNAME).

 gcc -o soup soup.o -lvegetables

If the library in not installed, then its location may be specified in the linking command.

 gcc -o soup soup.o -Llocation/of/the/library -lvegetables

Or alternatively (less preferable):

 gcc -o soup soup.o location/of/the/library/libvegetables.a

Note that each vegetable provided a function needed by the soup and that the soup had unresolved references to such functions. It is the linker's task to "connect" (resolve/link) the references (as in the first scenario).

Third Scenario: Using Dynamic Libraries

Creating the library

Linking and running

Fourth Scenario: Using Dynamic Modules

Much like dynamic libraries, but each module is made into a shared object.

Creating shared objects

Linking and running

Fifth Scenario: Using Run-time Dynamic Modules

There is no explicit dependency between modules: symbols are used as strings.

Sample application