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
clangThe compiler. Turns.csource into an executable.lldbThe debugger. Pause a program, inspect variables, step one line at a time.lldLLVM's linker — the step that joins compiled pieces into one program.libc6-devThe C standard library headers, so#include <stdio.h>resolves.
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:
| Option | What it does | Why |
|---|---|---|
-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. |
./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.
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
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
| Command | Short | What it does |
|---|---|---|
breakpoint set --name main | b main | Stop when main is entered |
breakpoint set --file hello.c --line 5 | b hello.c:5 | Stop at a specific line |
run | r | Start the program |
next | n | Run the next line, stepping over function calls |
step | s | Run the next line, stepping into calls |
finish | Run until the current function returns | |
continue | c | Carry on until the next breakpoint |
print answer | p answer | Show the value of one expression |
frame variable | v | Show every local variable at once |
bt | Backtrace: how did we get to this line? | |
memory read --size 1 --format x --count 32 &answer | x/32xb &answer | Read raw bytes at an address |
quit | q | Leave the debugger |
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.