Master Static and Shared Libraries in Linux | Beginner-friendly, in-depth guide (2026)

0b63979cd9494aa401d1fce2d73bb002
On: September 14, 2025
Master Static and Shared Libraries in Linux

You’ve just finished writing a small program in C. It works fine, but then your friend asks, “Hey, can I also use that add() function you wrote?” You copy-paste it into their code. Then another friend asks. Before you know it, you have the same function floating around in three, four, maybe ten different projects. Every time you fix a bug, you have to update it everywhere.

That’s when you realize — “There has to be a better way.”

This is exactly why libraries exist. Instead of duplicating code across projects, you can put your reusable logic into one neat package and simply “plug it in” whenever you need it. In Linux, these packages come in two flavors: static libraries and shared libraries. Both solve the duplication problem, but they work in very different ways — one bakes the code directly into your program, the other stays outside as a separate file that your program borrows at runtime.

In this guide, we’ll walk step by step through creating both types of libraries, linking them with a program, and understanding when to use which — all explained in plain, beginner-friendly language with real commands you can try out right now.

What is a library?

A library is a collection of precompiled code (functions, classes, etc.) that programs can use.

  • Static library (.a): The code is copied into the final executable at link time. Result: bigger executable, no runtime dependency on that library file.
  • Shared (dynamic) library (.so): Code stays in a separate file and is linked at runtime (or sometimes at link time referencing a shared object). Result: smaller executables, multiple programs share the same loaded code, updates to the library can affect all programs that use it.

Why use libraries?

  • Reusability: Put common code in a library and reuse it across projects.
  • Memory & disk efficiency (shared libs): multiple processes use the same code in memory.
  • Updatability (shared libs): fix a bug in one library file and many programs benefit (if ABI-compatible).
  • Distribution: ship stable APIs to other developers via headers + library files.

Tradeoffs:

  • Static: simpler distribution (no runtime .so load problems) but larger binaries and harder to update.
  • Shared: smaller binaries and easier updates, but you must manage ABI compatibility and runtime search paths.

A Tiny Example Project of Static and Shared Libraries in Linux

We’ll implement a tiny add() function in libadd and use it in main.

Files:

  • add.h — header
  • add.c — library implementation
  • main.c — program using the library

add.h

#ifndef ADD_H
#define ADD_H

int add(int a, int b);

#endif // ADD_H

add.c

#include "add.h"

int add(int a, int b) {
    return a + b;
}

main.c

#include 
#include "add.h"

int main(void) {
    printf("2 + 3 = %d\n", add(2, 3));
    return 0;
}

Place these files in one directory for following commands.

Create a static library (.a)

Steps:

  1. Compile add.c to an object file:
gcc -c add.c -o add.o
  1. Create the static archive:
ar rcs libadd.a add.o
# or: ar rcu libadd.a add.o && ranlib libadd.a
  • ar rcs adds the object and builds an index. ranlib is sometimes used to create/refresh the index; modern ar rcs usually does it already.
  1. Link main with the static library (explicit .a is simple & unambiguous):
gcc main.c ./libadd.a -o main_static

(You can also use -L. -ladd, but if libadd.so exists the linker might pick the .so instead.)

  1. Run:
./main_static
# Output: 2 + 3 = 5

Notes

  • Static linking copies the needed code into main_static. The binary is self-contained (no libadd.so required at runtime).
  • Order matters: object files (or main.c) must come before libraries on the command line if you use -l style.

Create a shared library (.so)

Shared libraries require position-independent code (PIC) on many platforms (e.g., x86_64).

  1. Compile with -fPIC:
gcc -fPIC -c add.c -o add.o
  1. Create a versioned shared library and set a SONAME:
gcc -shared -Wl,-soname,libadd.so.1 -o libadd.so.1.0.0 add.o
  1. Create the conventional symlinks (so compilers/linkers find libadd.so and run-time uses SONAME):
ln -s libadd.so.1.0.0 libadd.so.1
ln -s libadd.so.1 libadd.so

Now you have:

  • libadd.so.1.0.0 — actual file
  • libadd.so.1libadd.so.1.0.0
  • libadd.solibadd.so.1

Why SONAME?

  • The ELF SONAME (set with -soname,) is embedded inside the .so. Programs record the SONAME they were linked against (e.g., libadd.so.1). This helps manage ABI compatibility and versioning.
  1. Link main against the shared lib:
gcc main.c -L. -ladd -o main_shared
  1. Run it:
    By default, the dynamic loader searches standard locations (/lib, /usr/lib, /usr/local/lib) — our . directory is not standard. Options:
  • Quick (not recommended for production):
LD_LIBRARY_PATH=. ./main_shared
  • Better: set rpath at link time so the binary knows where to look:
gcc main.c -L. -ladd -Wl,-rpath,'$ORIGIN' -o main_shared_rpath
# $ORIGIN tells the loader to look in the directory containing the binary
  • Install system-wide:
sudo cp libadd.so.1.0.0 /usr/local/lib/
sudo cp add.h /usr/local/include/
sudo ldconfig
# then you can run ./main_shared (no LD_LIBRARY_PATH)
  1. Inspect dependencies:
ldd ./main_shared
# shows which shared libs are required and where they're found

Useful inspection tools

  • ldd — show shared library dependencies and where loader finds them.
  • readelf -d libadd.so.1.0.0 | grep SONAME — inspect SONAME.
  • nm -C libadd.a — list symbols in a static archive. -C demangles C++ names.
  • nm -D --defined-only libadd.so.1.0.0 — list dynamic symbols defined by a shared library.
  • objdump -p libadd.so.1.0.0 — show dynamic section.
  • file libadd.so.1.0.0 — show file type and architecture.

Linking details & common gotchas

  • Order when using -l: Put the object files or source first, libraries after: gcc main.c -L. -ladd -o app If you use -l style, the linker resolves references left-to-right; unresolved references in earlier objects must be satisfied by later libraries.
  • Forcing static/dynamic:
    • To force using the static lib for a specific -l: -Wl,-Bstatic -ladd -Wl,-Bdynamic (advanced).
    • To simply use a .a, put the .a file directly: gcc main.c ./libadd.a -o main_static.
  • Undefined references at link time: Means the linker couldn’t find the function implementation. Check you linked the proper library and that the library defines the symbol (use nm to check).
  • “cannot open shared object file: No such file or directory” at runtime:
    • Run ldd to see “not found”.
    • Use LD_LIBRARY_PATH, or install library to /usr/local/lib and run ldconfig, or embed rpath.
  • ABI breaks: If a shared library changes in an incompatible way, programs linked to the previous ABI may break. That’s why SONAME versioning (e.g., .so.1) is important.

Versioning conventions (simple overview)

Common pattern:

  • Actual file: libfoo.so.1.2.3
  • SONAME: libfoo.so.1 (ABI major version)
  • Symlinks: libfoo.so.1.2.3 libfoo.so.1 -> libfoo.so.1.2.3 libfoo.so -> libfoo.so.1
  • If ABI changes incompatibly, bump the major SONAME (e.g., libfoo.so.2) so old programs still link to libfoo.so.1.

Quick command cheat-sheet

Compile object:

gcc -c add.c -o add.o

Static library:

ar rcs libadd.a add.o
gcc main.c ./libadd.a -o main_static

Shared library:

gcc -fPIC -c add.c -o add.o
gcc -shared -Wl,-soname,libadd.so.1 -o libadd.so.1.0.0 add.o
ln -s libadd.so.1.0.0 libadd.so.1
ln -s libadd.so.1 libadd.so
gcc main.c -L. -ladd -o main_shared
LD_LIBRARY_PATH=. ./main_shared

Install to system:

sudo cp libadd.so.1.0.0 /usr/local/lib/
sudo cp add.h /usr/local/include/
sudo ldconfig

Inspect:

ldd ./main_shared
nm -C libadd.a
readelf -d libadd.so.1.0.0 | grep SONAME

Best practices & tips

  • Build shared libraries with -fPIC.
  • Use SONAME to manage ABI compatibility. Change SONAME when you break the API/ABI.
  • Prefer versioned .so files and proper symlink structure.
  • Keep header files stable and document the API.
  • Use pkg-config for complex libraries so downstream build systems can find include/lib flags automatically.
  • For C++ libraries, pay attention to name mangling and symbol visibility (-fvisibility=hidden) to avoid leaking internal symbols.
  • Use rpath or $ORIGIN carefully — $ORIGIN is great for relocatable installs but mind security and packaging implications.

Summary & next steps

You now know:

  • The conceptual difference between static (.a) and shared (.so) libraries.
  • How to create both with gcc, ar, and ln.
  • How to link programs to them and how to handle runtime lookup (LD_LIBRARY_PATH, rpath, ldconfig).
  • Tools to inspect libraries (ldd, nm, readelf).

Next steps I suggest:

  • Try the example above and experiment with removing .a or .so to see linker/loader errors.
  • Learn pkg-config and create a .pc file for your library.
  • Explore building libraries with make or CMake for bigger projects.

Applications, Advantages & Disadvantages of Static & Shared Libraries in Linux

Applications of Static & Shared Libraries in Linux

  1. Static Libraries
    • Embedded systems where self-contained executables are preferred.
    • Small utilities that must run without external dependencies.
    • Distributing software in environments without package managers.
  2. Shared Libraries
    • Large software projects (e.g., browsers, databases) where multiple executables use the same code.
    • Operating system components like glibc or libpthread.
    • Applications that need frequent updates without recompiling everything.

Advantages of Static Libraries

  • No dependency issues at runtime (everything is inside the executable).
  • Easier to distribute as a single binary.
  • Faster loading since no dynamic linking is needed at startup.
  • Good for embedded/portable applications.

Disadvantages of Static Libraries

  • Executable size is larger.
  • Updating the library requires recompiling all dependent programs.
  • Memory usage increases if multiple processes use the same static code.

Advantages of Shared Libraries

  • Saves disk space and memory (multiple programs share one library).
  • Easier to update and patch — only update the .so file.
  • Smaller executables since code is not duplicated.
  • Widely used in Linux distributions for system and user applications.

Disadvantages of Shared Libraries

  • Runtime dependency — if the .so file is missing or incompatible, the program fails.
  • Slightly slower startup due to dynamic linking.
  • ABI compatibility must be maintained, or programs may break.
  • Managing library paths (LD_LIBRARY_PATH, rpath) can be tricky for beginners.

Interview Questions on Creating Static & Shared Libraries in Linux

Basic Questions (for beginners)

  1. What is a static library in Linux?
  2. What is a shared (dynamic) library in Linux?
  3. How do you create a static library using gcc?
  4. How do you create a shared library using gcc?
  5. What are the file extensions for static and shared libraries in Linux?
  6. What is the difference between static and shared libraries?
  7. Which command is used to list shared library dependencies of a program?
  8. Where are libraries stored in a Linux system?
  9. What is the difference between .a and .so files?
  10. Why do we use libraries instead of copy-pasting code?

Intermediate Questions (hands-on knowledge)

  1. How do you link a static library while compiling a program?
  2. How do you link a shared library while compiling a program?
  3. What is the role of ar in static library creation?
  4. What is position-independent code (PIC) and why is it required for shared libraries?
  5. What is the role of the -fPIC flag in gcc?
  6. What does the -shared option in gcc do?
  7. What are SONAME and RPATH in the context of shared libraries?
  8. How do you update the library path so that Linux can find your shared library?
  9. What does LD_LIBRARY_PATH do?
  10. How do you check which shared libraries a binary depends on?

Advanced Questions (conceptual & real-world)

  1. What are the advantages and disadvantages of static libraries?
  2. What are the advantages and disadvantages of shared libraries?
  3. Which library type is better for embedded systems? Why?
  4. How does Linux dynamic linker (ld.so) work with shared libraries?
  5. How does versioning work in shared libraries?
  6. What happens if a shared library version changes but the SONAME stays the same?
  7. How do package managers like apt or yum handle shared libraries?
  8. What is the difference between compile-time linking and run-time linking?
  9. Can we mix static and shared libraries in the same program?
  10. In a production environment, when would you prefer static linking over shared linking?

FAQ: Creating Static & Shared Libraries in Linux

Q1: What are static and shared libraries in Linux?

Answer: Static libraries are .a files linked at compile time, while shared libraries are .so files linked at runtime.

Q2: How do I create a static library in Linux?

Answer: Compile with gcc -c file.c to make object files, then use ar rcs libname.a file.o to create the static library.

Q3: How do I create a shared library in Linux?

Answer: Compile with gcc -fPIC -c file.c for position-independent code, then gcc -shared -o libname.so file.o to build the shared library.

Q4: What is the main difference between static and shared libraries?

Answer: Static libraries increase binary size but are self-contained, while shared libraries keep binaries smaller and reusable across programs.

Q5: Why use static libraries in Linux?

Answer: Static libraries make deployment simple because no external .so files are required at runtime — everything is inside the executable.

Q6: Why use shared libraries in Linux?

Answer: Shared libraries save memory and disk space, allow multiple programs to share the same code, and make updates easier without recompiling executables.

Q7: How can I check which shared libraries a program uses in Linux?

Answer: Use the ldd program_name command to list all dynamic libraries linked to the program.

Q8: What is the role of SONAME in shared libraries?

Answer: SONAME ensures versioning in shared libraries. Programs record the SONAME they are built against, helping manage compatibility between updates.

Q9: How can I force GCC to use a static library instead of a shared one?

Answer: Use -Wl,-Bstatic -lname -Wl,-Bdynamic when linking, or link directly with the .a file.

Q10: Which is better for beginners: static or shared libraries in Linux?

Answer: Beginners often start with static libraries for simplicity, then move to shared libraries once they need flexibility, smaller binaries, and easier updates.

You can also Visit other tutorials of Embedded Prep

Master Static and Shared Libraries in Linux
Beginner’s guide to Creating Static and Shared Libraries in Linux. Learn differences, build steps with GCC, and when to use each in real projects.

1 thought on “Master Static and Shared Libraries in Linux | Beginner-friendly, in-depth guide (2026)”

Leave a Comment