Build Program Manually using gcc or g++ Compiler

Build Program Manually using gcc or g++ Compiler

When we usually compile a C or C++ program, we just run a single command like gcc main.c -o test, and we have an executable. The compiler doesn't magically transform the source code into a runnable program. It goes through four key stages: preprocessing, compilation, assembling, and linking. This tutorial explains how to build program manually using gcc or g++ compiler.

Create the main.c file for testing:

#include <stdio.h>

int main() {
    printf("Hello world\n");

    return 0;
}

Note: This post uses gcc for compiling C code, but the same steps and syntax apply when using g++ for C++ code.

1. Preprocessing

In the preprocessing stage, the compiler processes all preprocessor directives such as #include, #define, and conditional compilation instructions like #ifdef. It essentially prepares the source code for compilation by expanding macros and including the full contents of header files directly into the source. The result is a large .i (or .ii for C++) file containing pure, expanded C or C++ code with no preprocessor commands. This stage helps developers understand what code the compiler actually sees after macro and header expansion.

gcc -E main.c -o main.i

2. Compilation

The compilation stage takes the preprocessed code and translates it into assembly language instructions specific to the target machine architecture. This stage checks for syntax errors and performs initial code optimization. The output is a .s file, which is still human-readable and contains the low-level representation of the program. It's useful for analyzing how high-level constructs like loops, conditionals, and function calls are handled at the assembly level.

gcc -S main.i -o main.s

3. Assembling

During the assembling stage, the assembly code is converted into machine code and packaged into an object file (.o). This file contains binary code, but it also includes metadata like symbol tables and relocation information needed during the linking phase. The assembler doesn't create a runnable program - just a compiled version of your file that's ready to be linked with other code and libraries. This is also the point where you can begin to inspect compiled binary instructions using tools like objdump.

gcc -c main.s -o main.o

4. Linking

The final stage, linking, takes one or more object files and combines them with standard libraries (like the C standard library that includes printf, malloc, etc.) to produce a complete executable. It resolves external references, such as function calls or global variables declared in other files or libraries. If anything is missing - like a symbol that isn't defined anywhere - you'll get a linker error. The final output is a fully functional binary (e.g., test or a.out) that you can run on your system.

gcc main.o -o test

You can run the program as follows:

./test

Alternative: save all stages in one go

If you want to check each stage of the build process without running separate commands for preprocessing, compilation, assembling, and linking, we can use -save-temps option. It saves all intermediate files so you can easily see what happens at each step.

gcc -save-temps main.c -o test

Leave a Comment

Cancel reply

Your email address will not be published.