Skip to main content
Compilation Toolchain
Compilation Toolchain
IOT
1.5h

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 printf come 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 .o files)
  • -L = where to look, -l = what to link (strip lib prefix and .a suffix)
  • 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 $@