The Building Process for C Applications
Tags: spo600
Published: 2021-10-06 03:37:01

This week, I learned about the building process for C application in my Software Portability and Optimization class.

## How C gets compiled

C is a compiled language, and thus, has a process to compile the source code files into a binary form, which may be a library (also know a shared object or dynamic library), or an executable. C has 5 major stages of compilation:

1. preprocessing,
2. compilation (to an intermediate form such as [LLVM IR](https://en.wikipedia.org/wiki/LLVM#Intermediate_representation)),
3. optimization,
4. assembly,
5. linking.

Each process is, of course, non-trivial, but it is due to this abstraction that we can think of the compiler as a black box that simply spits out the desired program.

### Options for the compiler

Using the C compiler from GCC, we can specify different behaviours for each one of the stages without having to go deep inside the architecture. Things like optimization levels, showing the output after preprocessing or before assembling into a binary, what optimizations you can opt out or opt in, and how the program should be compiled into a static or dynamic executable are among the myriad of options available in the C compiler from GCC.

However, this process of invoking the C compiler every time for big projects can be time consuming and error prone, which is why some programmers developed programs to carry out building processes automatically. One of such programs is Make, which runs several commands depending on several rules that the programmer can write. Make is probably one of the most used automation build tools in the C ecosystem, and is required skill set if one wants to automate their building process for C development on Linux.

## The Program to Install

I decided to try to install a program through this process, instead of installing through my package manager. I decided to install [`zsh`](https://zsh.sourceforge.io/).

I went ahead and downloaded the tarballs and decompressed them. The first step was to run the `./configure` script included at the root of the project. This `./configure` gets the proper values of your system which are then fed into the Makefile of the project. This step is part of the GNU autotools build system. It is very standard to use autotools because of the wide support it provides.

After the I ran the `configure` script, I received an error that I had to install the ncurses development library to continue, so I had to head over my package manager and install that dependency. Following that, I ran the `configure` script one more time, and this time the configuration went through. This meant that I could run `make` and compile the code. The installation instructions recommended that I run `make check` after running `make`, to ensure that my compilation without issues. Since no issues were reported, I proceeded to install the shell with `make install`.

After that, I could run `zsh` without any issues.

## Conclusion

The process of installing with `make` was effortless, almost like magical. However, I am aware that package managers exist for a reason. That reason has to be related with the versioning of the program, as well as the libraries that users have to install to support their programs.

If not organized with proper care, a library may be installed several times, and some of those copies may be with the exact same version. Thus, a package manager takes into account all of those links and makes sure that unnecessary redundancy does not occur.