Step 3 · Ubuntu

C: clang and lldb

Two tools, and the loop between them. clang turns your C into a program the processor can run. lldb lets you stop that program mid-flight and look at what it is actually doing.

Run this

$ curl -fsSL https://aikaryashala.com/system_setup/scripts/install_c.sh | bash

The script finishes by compiling a small program, running it, and stopping it under the debugger — so you know the whole loop works before you write anything of your own.

What gets installed

That is the whole list. Compiler options that hunt for bugs are step 11, and tools that work on the result of compiling — hex viewers, disassemblers, valgrind, make — are step 7. Both are separate installs.

Compile something

Create hello.c:

#include <stdio.h>

int main()
{
    int answer = 42;
    printf("Namasthey from C. The answer is %d.\n", answer);
    return 0;
}

Compile and run it:

$ clang -g hello.c -o hello

Nothing is printed when it works. Now run the program you just built:

$ ./hello
Namasthey from C. The answer is 42.

Two options, and that is all you need for now:

OptionWhat it doesWhy
-g Keep debug information Without it, lldb can show you machine instructions but not your own lines of C.
-o hello Name the program Leave it out and clang produces a file called a.out instead.
Why ./hello and not hello

The dot means “this folder”. Typing hello on its own makes the shell search the places where system commands live — and your new program is not one of those. ./hello says “run the one right here”.

clang has many more options, including some that hunt for bugs on your behalf. Those are step 11, once this loop feels comfortable.

Want to see what that command really did?

Chapter 6 of the book follows one C file through all four stages of compiling — preprocessing, compiling, assembling and linking — stopping after each one so you can look at what came out.

Debug it with lldb

$ lldb ./hello
(lldb) target create "./hello"
(lldb) b main
(lldb) run
(lldb) frame variable
(lldb) next
(lldb) print answer
(lldb) continue
(lldb) quit
Want to understand what the debugger is doing?

Chapter 8 of the book takes a second program apart with lldb — stepping into a function you wrote, watching a loop change a value, and reading the call stack.

The commands worth memorising

CommandShortWhat it does
breakpoint set --name mainb mainStop when main is entered
breakpoint set --file hello.c --line 5b hello.c:5Stop at a specific line
runrStart the program
nextnRun the next line, stepping over function calls
stepsRun the next line, stepping into calls
finishRun until the current function returns
continuecCarry on until the next breakpoint
print answerp answerShow the value of one expression
frame variablevShow every local variable at once
btBacktrace: how did we get to this line?
memory read --size 1 --format x --count 32 &answerx/32xb &answerRead raw bytes at an address
quitqLeave the debugger
Coming from gdb?

LLDB accepts many gdb spellings, but its own syntax is <noun> <verb> <options> — for example breakpoint set, memory read, thread backtrace. The short aliases above cover almost everything you will do day to day.

Debugging without stopping to type

LLDB can run a fixed list of commands and exit, which is handy for a quick look or inside a script:

$ lldb --batch -o "b main" -o run -o "frame variable" -o quit ./hello

Check it worked

$ clang --version
$ lldb --version

Next

Step 4 sets up Python — with uv, which replaces the entire old stack of Python tooling.