Home / Tutorials / Dynamic Libraries

Dynamic Libraries

Dynamic libraries (also called shared libraries) allow multiple programs to share a single copy of compiled code at runtime. Unlike static libraries, the linking happens at load time rather than compile time.

Why Dynamic Libraries?

With static libraries, each executable contains its own copy of the library code. If ten programs use the same library, ten copies exist on disk and in memory. Dynamic libraries solve this:

The trade-off is that the library must be present on the system at runtime.

Position-Independent Code

To be used as a shared library, code must be compiled as position-independent code (PIC). This tells the compiler to generate code that works regardless of where in memory it is loaded.

Use the -fPIC flag:

gcc -fPIC -c mylib.c -o mylib.o

Creating a Shared Library

Once you have position-independent object files, create the shared library with -shared:

gcc -shared -o libmylib.so mylib.o

By convention, shared libraries are named lib<name>.so.

Linking Against a Shared Library

When compiling a program that uses the library:

gcc main.c -L. -lmylib -o myprogram

Runtime Library Path

At runtime, the dynamic linker must be able to find the .so file. Options:

  1. Copy the library to a standard location like /usr/lib
  2. Add the directory to /etc/ld.so.conf and run ldconfig
  3. Set the LD_LIBRARY_PATH environment variable:
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./myprogram

Dynamic Loading with dlopen

You can also load shared libraries at runtime programmatically using the dl API:

#include <dlfcn.h>

void *handle = dlopen("libmylib.so", RTLD_LAZY);
if (!handle) {
    fprintf(stderr, "%s\n", dlerror());
    return 1;
}

RTLD_LAZY defers symbol resolution until they are actually called. RTLD_NOW resolves all symbols immediately.

Looking Up Symbols with dlsym

Once a library is open, retrieve a pointer to any exported symbol:

typedef int (*add_func_t)(int, int);

add_func_t add = (add_func_t) dlsym(handle, "add");
char *error = dlerror();
if (error != NULL) {
    fprintf(stderr, "%s\n", error);
    return 1;
}

int result = add(3, 4);
printf("3 + 4 = %d\n", result);

Always call dlerror() after dlsym to check for errors — dlsym may legitimately return NULL for a symbol whose value is null.

Closing the Library with dlclose

When done with a library handle:

dlclose(handle);

This decrements the library's reference count. When the count reaches zero, the library is unloaded from memory.

Compile with -ldl

Programs that use dlopen, dlsym, and dlclose must link against the dl library:

gcc main.c -ldl -o myprogram

Summary

Step Command
Compile to PIC objects gcc -fPIC -c mylib.c
Create shared library gcc -shared -o libmylib.so mylib.o
Link program gcc main.c -L. -lmylib -o prog
Runtime loading dlopen() / dlsym() / dlclose()
Link dl API gcc main.c -ldl -o prog