Video summary

Learn to program with c - Part 18 - Libraries

Main summary

Key takeaways

Educational

Main ideas / concepts covered

  • What a library is (C context)

    • A library is a packaged collection of functions, structures, and other code intended to be reused.
    • You create libraries to:
      • Maintain shared code separately (e.g., math utilities).
      • Avoid recompiling the same code for every program build.
      • Potentially improve portability (static) or reduce duplication/bloat (dynamic).
  • Two primary library types

    1. Static library (archive)

      • File type: typically *.a (ends with a for “archive”).
      • Built using the ar tool.
      • Behavior when linked:
        • The referenced functions are copied into the final executable.
        • The executable becomes larger.
      • Portability advantage:
        • The program can run without requiring that external shared library at runtime (as long as architecture matches).
      • Re: performance:
        • Any speedup is said to be negligible; the main benefit emphasized is portability and bundling.
    2. Dynamic/shared library

      • File type: typically *.so (shared object).
      • Not copied into the executable.
      • Behavior when linked/running:
        • The executable contains references and at runtime loads the library code into memory.
      • Advantages:
        • Many programs can share one copy of the library on disk and in memory.
        • Library updates may avoid recompiling every dependent program if function prototypes don’t change.
      • Tradeoff:
        • Can create dependency/version problems (“dependency hell”).
      • Key requirement:
        • To build a shared library, objects typically must be relocatable (commonly compiled with -fPIC).

Methodology / instruction-like steps (as shown in the video)

A) Creating and using a static library (libwacky.a)

  • Create header file

    • wacky math.h
    • Declare a function (example):
      • wacky_add(int a, int b) (named with a unique wacky prefix to avoid symbol name clashes at link time)
  • Create implementation file

    • wacky math.c
    • Implement:
      • wacky_add(int a, int b) returning a + b + (rand() % 10)
    • Include needed headers:
      • stdlib.h for rand() (and mention rand() is pseudo-random, dependent on a seed)
  • Create a program that uses the library

    • wacky do.c (program name used in the video)
    • Include:
      • stdlib.h (for seeding the RNG)
      • wacky math.h
    • Use:
      • srand(0) to make output deterministic across runs/builds
      • Call wacky_add(3, 4) multiple times and print results
  • Makefile targets / build rules

    • Build the object and archive:
      • Compile wacky math.o from wacky math.c
      • Create the archive using ar:
        • ar rcsv libwacky.a wacky math.o
          • r: insert/replace objects
          • c: create archive
          • s: (implicitly discussed) maintain symbol table
          • v: verbose
    • Link the executable:
      • Example dependency: executable depends on libwacky.a
      • Link step uses:
        • -L <dir> to tell the compiler/linker where to search libraries
        • -l wacky to link libwacky.a (prefix lib and suffix .a are assumed)
  • Verify archive contents

    • Use ar to list what’s inside the archive
    • Use nm to inspect symbols inside:
      • Shows wacky_add (and notes undefined/defined symbol markers)
    • Use nm on the executable to confirm:
      • For static linking, wacky_add appears as defined inside the executable.

B) Creating and using a dynamic/shared library (libwacky.so)

  • Reuse the same library source (wacky math.c, header)
  • Change the build to produce a shared object

    • Create a target for libwacky.so (named lib wacky doo in the subtitles)
    • Important fix when building shared libraries:
      • The build may fail with a relocation error unless code is position-independent
      • Recompile the object with:
        • -fPIC
      • Build shared library from PIC object(s)
  • Key steps emphasized

    • Compile wacky math.o with -fPIC:
      • so it can be relocated at runtime
    • Link the executable against the shared library:
      • Ensure the order of arguments matters:
        • Library flags (e.g., -l...) must typically come after the source/object files that need them
    • Run-time library discovery:
      • Executable must know where to find the .so
      • Methods shown:
        • Use LD_LIBRARY_PATH=. (set to current directory)
        • Or use ldconfig to add directories to the system shared library cache
      • Warning noted:
        • Misuse of ldconfig can break other programs if the cache becomes inconsistent/unreliable.
  • Verification differences

    • Use nm:
      • For dynamic linking, wacky_add is undefined in the executable (resolved via the .so at runtime)
      • wacky_add is defined inside the shared library.

C) Linking to an existing external library (SDL example)

  • Example app behavior

    • SDL (“Simple DirectMedia Layer”) program:
      • Initialize SDL
      • Create surfaces
      • Load a bitmap image (mushroom picture)
      • Blit (draw) it to a screen surface
      • Update/flip buffers
      • Wait, then free resources and quit
  • Build instructions shown

    • Add makefile target sdl example depending on sdl example.c
    • Compiler flags:
      • -I <include-dir> (to find headers, e.g., where SDL/SDL.h lives)
    • Linker flags:
      • -L <lib-dir> and -lSDL (so it links against libSDL.so or libSDL.a)
    • SDL header/library locations may require installing “dev” packages.
  • Tool-assisted method

    • Use sdl-config (example of common *-config tools) to get:
      • --cflags (compile-time include flags / defines)
      • --libs or --static-libs (linker flags)
    • Video notes:
      • sdl-config --libs output may include additional libraries (e.g., -lpthread) that you should include for correctness.

Main lessons / “gotchas” highlighted

  • Static vs dynamic consequences

    • Static: code copied into executable → larger executable, fewer runtime dependencies.
    • Dynamic: code loaded at runtime from .so → smaller executable, but requires runtime library resolution.
  • Linker argument order matters

    • Undefined reference errors can happen if the library appears before the objects/sources it should satisfy.
  • Shared library build requires PIC

    • Use -fPIC when building objects that will go into shared libraries.
  • Runtime search paths for .so

    • Either set LD_LIBRARY_PATH or use ldconfig/system cache mechanisms.
  • External libraries require both headers and linkable binaries

    • Use -I for header locations and -L/-l for libraries.

Speakers / sources featured

  • Primary speaker: Unnamed presenter/instructor (voice-over; “hi there…” and teaching narration)
  • Tools/utility sources referenced: gcc/clang toolchain, ar, nm, ldconfig, environment variable LD_LIBRARY_PATH, sdl-config (SDL configuration tool)
  • External library source referenced: SDL (“Simple DirectMedia Layer”)

Original video