Session 3 — Libraries: Instructor Print Guide
Instructor material — not student-facing
Single-page print reference: all demo files and terminal commands in order.
Setup
cd ~/lecture/session3/
Demo Files
lib/mylib.h
#ifndef MYLIB_H
#define MYLIB_H
/* A small vector math library for demonstration purposes. */
typedef struct
{
double x;
double y;
} Vec2;
Vec2 vec2_create(double x, double y);
Vec2 vec2_add(Vec2 a, Vec2 b);
Vec2 vec2_sub(Vec2 a, Vec2 b);
double vec2_dot(Vec2 a, Vec2 b);
double vec2_length(Vec2 v);
Vec2 vec2_normalize(Vec2 v);
void vec2_print(Vec2 v);
#endif
lib/mylib.c
#include <stdio.h>
#include <math.h>
#include "mylib.h"
Vec2 vec2_create(double x, double y)
{
Vec2 v = {x, y};
return v;
}
Vec2 vec2_add(Vec2 a, Vec2 b)
{
return vec2_create(a.x + b.x, a.y + b.y);
}
Vec2 vec2_sub(Vec2 a, Vec2 b)
{
return vec2_create(a.x - b.x, a.y - b.y);
}
double vec2_dot(Vec2 a, Vec2 b)
{
return a.x * b.x + a.y * b.y;
}
double vec2_length(Vec2 v)
{
return sqrt(v.x * v.x + v.y * v.y);
}
Vec2 vec2_normalize(Vec2 v)
{
double len = vec2_length(v);
if (len == 0.0)
return vec2_create(0.0, 0.0);
return vec2_create(v.x / len, v.y / len);
}
void vec2_print(Vec2 v)
{
printf("(%.2f, %.2f)\n", v.x, v.y);
}
app/main.c
#include <stdio.h>
#include "mylib.h"
int main(void)
{
Vec2 a = vec2_create(3.0, 4.0);
Vec2 b = vec2_create(1.0, 2.0);
printf("a = ");
vec2_print(a);
printf("b = ");
vec2_print(b);
Vec2 sum = vec2_add(a, b);
printf("a + b = ");
vec2_print(sum);
printf("a . b = %.2f\n", vec2_dot(a, b));
printf("|a| = %.2f\n", vec2_length(a));
Vec2 n = vec2_normalize(a);
printf("norm(a) = ");
vec2_print(n);
printf("|norm(a)| = %.2f\n", vec2_length(n));
return 0;
}
Makefile
# Makefile for session 3 — library demo
# Students will extend this during the lecture
CC = gcc
CFLAGS = -W -Wall -Wextra -Ilib
LDFLAGS = -lm
TARGET = app/program
default: $(TARGET)
$(TARGET): app/main.c
$(CC) $(CFLAGS) $< -o $@ $(LDFLAGS)
.PHONY: clean
clean:
rm -f $(TARGET) lib/*.o lib/*.a lib/*.so lib/*.dylib app/*.o
3.1 — What Are Libraries? (10 min)
# Every C program uses libraries — even "Hello World"
cat > /tmp/hello.c << 'EOF'
#include <stdio.h>
int main() { printf("Hello\n"); return 0; }
EOF
gcc /tmp/hello.c -o /tmp/hello
# Show linked libraries
ldd /tmp/hello # Linux
# otool -L /tmp/hello # macOS
“Where does
printfcome from? You didn’t write it. You didn’t compile it.”
Key concept: a library is precompiled code + headers.
3.2 — Static Libraries (25 min)
# Look at our library source
cat lib/mylib.h
cat lib/mylib.c
# Step 1: Compile to object file
gcc -W -Wall -c lib/mylib.c -o lib/mylib.o
# Step 2: Create static library
ar rcs lib/libmylib.a lib/mylib.o
# Inspect it
ar -t lib/libmylib.a # list contents
nm lib/libmylib.a # show symbols
# Step 3: Use it
gcc -W -Wall app/main.c -Ilib -Llib -lmylib -o app/program
./app/program
Teaching moments:
ar= archiver (bundles.ofiles)-L= where to look,-l= what to link (striplibprefix and.asuffix)- The library code is embedded in the executable
Warning
▶ Wooclap Q6
Fire before running rm.
# Prove static independence: delete the library, program still works
rm lib/libmylib.a
./app/program # still runs!
3.3 — Dynamic Libraries (25 min)
# Step 1: Compile with Position Independent Code
gcc -W -Wall -fPIC -c lib/mylib.c -o lib/mylib.o
# Step 2: Create shared library
gcc -shared -o lib/libmylib.so lib/mylib.o # Linux
# gcc -shared -o lib/libmylib.dylib lib/mylib.o # macOS
# Step 3: Link against it
gcc -W -Wall app/main.c -Ilib -Llib -lmylib -o app/program
# Try to run — error! Library not found at runtime
./app/program
# Fix: tell the loader where to find it
LD_LIBRARY_PATH=./lib ./app/program # Linux
# DYLD_LIBRARY_PATH=./lib ./app/program # macOS
Key teaching moment: difference between compile-time linking and runtime loading.
# Show the dependency
ldd app/program # libmylib.so => not found
# Now delete the library — unlike static, this breaks it
rm lib/libmylib.so
./app/program # fails!
3.4 — Static vs. Dynamic Comparison (10 min)
# Build both versions (requires both libmylib.a and libmylib.so present)
gcc app/main.c -Ilib -Llib -lmylib_static -o app/static_prog # static
gcc app/main.c -Ilib -Llib -lmylib -o app/dynamic_prog # dynamic
Warning
▶ Wooclap Q7
Fire before running ls -la.
# Compare sizes
ls -la app/static_prog app/dynamic_prog
# Compare dependencies
ldd app/static_prog
ldd app/dynamic_prog
Tradeoffs:
- Static: no dependencies, larger binary, needs rebuild if lib changes
- Dynamic: smaller binary, shared in RAM, but runtime dependency
3.5 — Library Versioning (10 min)
# Real-world symlink chain
ls -la /usr/lib/x86_64-linux-gnu/libz*
# libz.a
# libz.so -> libz.so.1.2.11
# libz.so.1 -> libz.so.1.2.11
# libz.so.1.2.11
M.m.p versioning: major (breaking API), minor (compatible additions), patch (bugfixes).
At compile time: linker follows libz.so
At runtime: loader follows libz.so.1 (soname)
3.6 — Integrating Libraries in Makefile (10 min)
# Add library build targets to session2 Makefile
lib/libmylib.a: lib/mylib.o
ar rcs $@ $^
lib/mylib.o: lib/mylib.c lib/mylib.h
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET): $(OBJ) lib/libmylib.a
$(CC) $(LDFLAGS) $(OBJ) -Llib -lmylib -o $@