Programming Foundations

From Source Code to a Running Program

Follow compilation, linking, loading, and execution, and identify the stage at which an error occurs.

About 45 min · Updated 2026-10-25

Information checked as of: 2026-10-26

Learning objectives

  • Explain how source code passes through a compiler, interpreter, and runtime before execution.
  • Identify whether an error or performance problem belongs to the language implementation, runtime, operating system, or hardware.

You write some code, run it, and text appears on the screen. Between those steps, the system reads source stored as text, transforms it into an executable form, places the necessary content in memory, and lets the CPU carry out the work. Separating these stages helps you investigate problems such as “It builds but will not start” or “It only fails in this environment.”

Source code and executables have different roles

Source code is a representation used by people to describe a program. It is not necessarily a sequence of instructions the CPU can execute directly. In a language such as C, a compiler normally analyzes the source and translates it into machine code for a target CPU. This stage checks names and types as well as syntax. Optimization means that source expressions and machine instructions need not correspond one to one.

#include <stdio.h>
int main(void) {
    puts("Hello, LavaCS");
    return 0;
}

This example uses the library function puts. Writing its name does not automatically paste its implementation into the source. Distinguish the declaration supplied by a header, the compiled call, and the work that connects that call to the function’s implementation. The details depend on the OS, executable format, and whether linking is static or dynamic.

A typical C toolchain handles includes and macros during preprocessing, performs syntax and semantic analysis, produces an intermediate representation, and then optimizes and generates code. An assembler translates assembly into an object file, and a linker combines object files and libraries. A command such as clang also acts as a driver that invokes these tools in sequence.

clang -E hello.c -o hello.i   # preprocessed source
clang -S hello.c -o hello.s   # assembly representation
clang -c hello.c -o hello.o   # object file
clang hello.o -o hello       # link
./hello

Invalid syntax may cause compilation to fail, while a missing implementation of a declared function may cause a linker error. A shared library that cannot be found at startup is a problem at a later stage. Although all three situations look like “It does not work,” they require different investigations. Record which command failed, rather than just the final line of output.

Starting a program creates a process

The executable file on disk does not itself keep running. The OS prepares memory regions and resources and maps the required code and data. A process is an instance with execution state. If you start the same executable twice, each instance has state such as an instruction position and memory. Distinguish the file from a running instance of it.

A runtime may also provide a standard library, memory management, and exception handling. Screen output and file access involve OS facilities, but not every application function call becomes a system call. For example, a library may collect output in a buffer and pass it to the OS later as a batch.

Interpretation and compilation can work together

Classifying languages simply as “Python is interpreted, C is compiled” obscures how implementations work. CPython, a widely used Python implementation, compiles source into bytecode and executes those instructions on a virtual machine. Another implementation may use a JIT compiler to generate machine code while running. A language’s rules and an implementation of those rules are different things.

Bytecode is not necessarily an instruction set for a physical CPU. If it targets a virtual machine, a program implementing that machine must execute it. Successful compilation also does not prevent failures caused by input values, permissions, networks, or undefined behavior. Be precise about what a successful build actually establishes.

Check your understanding

  • Does starting the same executable twice give both instances the same execution state? Normally it creates two processes, each with its own state. Some parts can be deliberately shared through mechanisms such as shared memory or files.

  • A C function has a declaration, but its implementation has not been linked. At which stage is failure likely? At link time. The error may identify an unresolved symbol.

  • Can an interpreted implementation be assumed to perform no compilation? No. An implementation such as CPython includes compilation to bytecode.

Concepts in this unit: Compiler · Bytecode · Process ·

Read next: Kernels, Privilege Modes, and System Calls