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:
- A single
.sofile is shared among all programs that use it - Updates to the library take effect for all programs without recompilation
- Executable file sizes are smaller
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
-L.tells the linker to look in the current directory-lmyliblinks againstlibmylib.so
Runtime Library Path
At runtime, the dynamic linker must be able to find the .so file. Options:
- Copy the library to a standard location like
/usr/lib - Add the directory to
/etc/ld.so.confand runldconfig - Set the
LD_LIBRARY_PATHenvironment 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 |