As discussed in Basic principles of C, code written in C needs to be built (compiled and linked) to produce executables. What follows is a short discussion of this process.
Building with GCC
The GNU Compiler Collection (GCC) is a suite of tools for the compilation process. The GCC is free software. It is pre-installed on most GNU/Linux distributions, and is also available on OS X and Windows. (On Windows you will need to install MinGW, a development environment that emulates, and gives the functionalities of, a basic Unix-like system.)
Due to its popularity and its free and open-source nature, the GCC has become, officially or unofficially, the standard compilation system on most Unix-like systems.
The GCC is designed so that the interface is the same on all systems. To compile the C source file foo.c, the basic command is
$ gcc foo.c
This will compile and link foo.c and produce the executable file a.out. You can specify a different name for the output file using the -o flag:
$ gcc -o foo foo.c
Multiple source files
If your program is written across several different source files, then the linking process can be taken care of automatically:
$ gcc -o output foo.c bar.c baz.c
There are many options that can be passed to gcc (and to its sisters, described below). Here are some of the more important ones:
- -I/path/to/dir: Adds the specified directory to the list of places where #include commands will search for files. On Unix-like systems, directories such as /usr/include and /usr/local/include are usually searched automatically, but if you need the header file of a library that is not installed there, then you will need to specify the path.
For example, on my laptop (running OS X), the GSL is installed in /usr/local/Cellar/gsl/1.16. To use the GSL headers, I would need to pass the flag -I/usr/local/Cellar/gsl/1.16/include/.
- -llibrary: Indicates that library should be linked. For example, if I am using the GSL, then I would need to link using -lgsl.
- -Wall: Tells the compiler to emit all warnings, not just fatal errors or serious warnings. This can be useful for revealing those places where your code works, but is not written as cleanly as it could be (for example, if you have declared variables which you do not actually use).
- -g: Tells the compiler to include debugging information in the produced object code or executable. For example, line references or even the actual text of the source file might be included. This is useful because it allows a debugger such as gdb or valgrind to tell you not just that memory leaks are happening, but also tell you where they take place.
- -O0: Tells the compiler not to optimise the compiled code. Usually, compilers do not simply translate source code directly into machine code; they may, for example, change the order in which some statements are executed. This improves the speed of the program and may reduce the size of the executable. Turning off optimisation may be desirable if you want a faster compilation, and is also useful in testing because the produced executable will better resemble the source in its structure.
Other tools in the GCC
The GCC also provides a suite of compilers for other languages, including g++ for C++ and gfortran for Fortran. All of these generate object code files (files with the .o extension) which are compatible: they may be linked together. Hence different parts of a program may be written in different languages, compiled into object code and then linked into one executable.
If you are working on a project with many source files and you have to compile many times during development, then typing out the above commands over and over again, and trying to remember what flags to pass to gcc, can be tedious. GNU Make is a very useful tool for automating the build process.
The GNU Make utility is not part of the C language, but it is an important part of its ‘culture’: Software written in C (or C++, or Fortran, or any other compiled language) is often built using GNU Make. Like GCC, GNU Make usually comes with GNU/Linux distributions and is available on OS X and Windows (with MinGW).
GNU Make will be described in more detail in a future post.
I mainly stick to using GNU Make, but it is good to mention a few other tools: also not parts of the C language, but common parts of the culture.
Git is a version control system that allows you to keep track of changes to source files in a project. You edit your files and then commit your changes each time you make a change. The history of these commits is recorded, and you can revert to previous versions.
Git is designed for multiple developers working on different parts of a project. Alice, having changed a few files, commits and then pushes her commits. Bob can then pull these changes: Git will try to update Bob’s copy of the code to apply the changes that Alice has made, without overwriting any changes that Bob might have made.
Alice and Bob may also create branches of the code if they want to work on different features of the project whilst keeping the master branch unchanged.
If you are working on a large project, then building can be tedious even with the aid of GNU Make: Keeping track of your source files and updating your makefiles to reflect their changes is difficult. The GNU Autotools suite is designed to help automate that process.
Integrated development environments (IDEs)
Alternatively, you may use an IDE such as Eclipse (cross-platform), Xcode (on OS X), or Microsoft Visual Studio (on Windows) to keep track of files and build processes. Most IDEs provide a compilation and linking system as well as a debugger. Their interfaces tend to be daunting, however.