Reading Assignment: All of Programming Ch5 Compiling and Running
Compiling a program is the act of translating the human-readable code that a programmer wrote into a machine-exectuable format. The compiler is the program that performs this process for you: it takes your source code as input, and writes out the actual executable file, which you can then run.
1 | gcc myProgram.c |
The Compilation Process
The Preprocessor: Header Files and Defines
the preprocessor take the C source file and combines it with any header files that it includes, as well as expanding any macros that you might have used.
Header files: They are include
directives. They primarily contain three things: function prototypes, macro definitions, and type declarations.
The advantages to use marco definitions
- You can change the constant by changing macro definition.
- Naming the constant makes the code more readable.
- Portability. You can reach the maximum and minimum values for specific type from
"limits.h"
The Actual Compiler
The output of the preprocessor is stored in a temporary file, and passed to the actual compiler. The compiler reads the pre-processed source code–which has all the specified files included and all macro definitions expanded– and translates it into assembly, which is the lowest level type of human readable code.
The compiler is a rather complex program.
There are several tips on dealing with compilation errors:
- The later confusing errors may produced by previous error. When you fix the first bug, you should recompile before fix the later ones.
- If parts of an error message are hard to understand, ignore them and focus on those you could make sense, otherwise Google.
- Editors may help with mismatched braces and parenthesis.
- Be confident in your fix for an error.
Assembling
The next step is to take the assembly that the compiler generated and assemble it into an object file. gcc
invokes the assembler to translate the assembly instructions from the human readable format into their numerical encodings that the processor can understand and execute. This translation is another example of the rule that everything is a number.
Linking
The final step of the process is to link the program. If all goes well, the linker will resolve all the symbol references, and combined the various object files and libraries together into an executable binary.
Building Large Programs: make
Real programs are tend to be quite a bit larger. As the program size increases, so does the compilation time. One does not need to recompile all of the source code, if the object .o
files from previous compilations are kept. Instead, only the files that were changed need to be recompiled, then the program needs to be linked again.
Long ago, programmers developed the make
utility to not only automate this process, but also to simplify compiling programs in general. The make
command reads a file called Makefile
(though you can ask it to read an input file by a different name) which specifies how to compile your program. Specifically, it names the targets
which can be made, their dependencies
, and the rules
to make the target.
When make
is run, it starts from a particular target–something that it can build out of other things. A common starting target might be your entire program. make
first checks if the target is up-to-date. Checking that a target is up-to-date requires checking that all of the files that the target depends on are themselves up-to-date, and that none of them are newer than the target. For example, the target for the whole program may depended on many object files. If any such file is not itself up-to-date(for example, the object file may depend on a .c
file, which just got changed), it is rebuilt first. make
than follows whatever rule was specified for the target to build it from its dependencies. If the target is already up to date, then it does nothing.
Running Your Program
Currently, your program is located at the exact the same as your current directory. You can just put ./
before the program’s name.
Two useful tools:
- gdb(the GNU Debugger): refer Ch37.2
- valgrind: emulates the computer but tracks more information about what your program is doing to report errors that may otherwise go undetected.
Recommended compiler options:
1 | gcc -o hello -Wall -Werror -Wsign-compare -Wwrite-strings -Wtype-limits -pedantic -std=gnu99 hello.c |
Compiler Options
-o
: The name of the executable.
--std=gnu99
: the compiler should use the C99 standard with GNU extentions.
-Wall
: It requests that the compiler issue warning for a wide range of questionable behavior.
-Werror
: It tells the compiler to treat all warnings as errors–making it refuse to compile the program until the programmer fixes all the warnings.
A programmer’s goal is not just to produce any executable program, but one that works correctly at hand.
Other Possibilities
The process of compiling and running a program that we have described here is not the only way to execute a program. An alternative to compilation is to interpret the program. Instead of translating the program into machine instructions, the source code is given to an interpreter–a program which reads the source of another program and performs the actions specified in it.