Question
What Are .a and .so Files in C? Static vs Shared Libraries Explained
Question
I am porting a C application to AIX and am confused about the roles of .a and .so files. What are these file types, and how are they used when building and running a C application?
Short Answer
By the end of this page, you will understand what .a and .so files are, the difference between static and shared libraries, how the compiler and linker use them, and what happens at runtime when your program depends on one of these libraries.
Concept
In C and C-like systems programming, .a and .so files are both library files, but they are used differently.
- A
.afile is usually a static library archive. - A
.sofile is usually a shared object, also called a shared library.
.a files: static libraries
A static library is a bundle of compiled object files collected into one archive file.
For example, if you compile several source files:
math_utils.c
string_utils.c
file_utils.c
You might create a static library like this:
ar rcs libhelpers.a math_utils.o string_utils.o file_utils.o
When you link your program against libhelpers.a, the linker copies the needed machine code from the library into your final executable.
That means:
- the executable becomes larger
- the code is included at build time
- the program usually does not need that
.afile at runtime
.so files: shared libraries
A shared library is compiled code that stays outside the executable. The executable contains references to it, and the operating system loads it when the program starts, or sometimes on demand.
For example:
Mental Model
Think of libraries like tool storage for your program.
- A static library (
.a) is like copying the exact tools you need into your own toolbox before leaving the workshop. - A shared library (
.so) is like leaving the tools in a shared cabinet that many workers can use when needed.
Static library
You pack the tools into your own box:
- self-contained
- heavier to carry
- you do not depend on the cabinet later
Shared library
You borrow tools from the shared cabinet:
- lighter personal toolbox
- many people can use the same cabinet
- you must know where the cabinet is when work begins
This is the key difference:
- static linking copies code into the program
- dynamic linking keeps code external and loads it later
Syntax and Examples
Basic naming convention
On many Unix-like systems, libraries are named like this:
libname.afor a static librarylibname.sofor a shared library
When linking with -lname, the linker looks for libname.a or libname.so.
Example: building a static library
Source file
/* greet.c */
#include <stdio.h>
void greet(void) {
printf("Hello from the library!\n");
}
Main program
/* main.c */
void greet(void);
int main(void) {
greet();
return 0;
}
Build steps
Step by Step Execution
Consider this program:
/* main.c */
void greet(void);
int main(void) {
greet();
return 0;
}
And this library code:
/* greet.c */
#include <stdio.h>
void greet(void) {
printf("Hello from the library!\n");
}
Static linking walkthrough
gcc -c greet.c -o greet.o
ar rcs libgreet.a greet.o
gcc main.c -L. -lgreet -o app
Step by step
-
greet.cis compiled intogreet.o- This contains machine code for
greet().
- This contains machine code for
-
greet.ois placed into
Real World Use Cases
Static libraries (.a) are often used when
- building small self-contained command-line tools
- deploying software to systems where installing dependencies is difficult
- embedding a specific library version into a binary
- reducing runtime dependency problems
- building for restricted or embedded environments
Example:
- A maintenance utility is shipped as one executable with no external library setup.
Shared libraries (.so) are often used when
- many programs use the same library
- disk space or memory sharing matters
- libraries need to be updated independently of applications
- plugin-style systems load code dynamically
- operating system packages manage common dependencies
Example:
- Multiple applications use the same SSL or database client library.
In porting work
When moving a C program to another Unix platform such as AIX, you often need to check:
- whether the target platform prefers static or shared linking for a library
- where the runtime loader searches for libraries
- whether a
.afile contains static objects, shared objects, or both - whether the build scripts assume Linux-style
.sobehavior
Real Codebase Usage
In real projects, developers usually do not think only in terms of file extensions. They think in terms of linking strategy, deployment, and runtime loading.
Common patterns
Using system libraries
A project may link with standard libraries like:
gcc app.c -lm -lpthread -o app
The exact files chosen by the linker depend on what is installed and how the system is configured.
Using build tools
In Makefiles, CMake, or Autotools, developers usually specify library names and search paths rather than hardcoding file names.
Example Makefile style:
CFLAGS += -I./include
LDFLAGS += -L./lib
LDLIBS += -lgreet
This keeps the build more portable.
Guarding against runtime failures
When using shared libraries, teams often:
- install libraries in standard system paths
- configure runtime search paths
- package the correct library versions
- verify dependencies in CI or deployment scripts
Versioned shared libraries
Real systems often use versioned shared libraries such as:
libssl.so
libssl.so.3
This helps compatibility and upgrades.
Plugin loading
Some applications do not link a shared library at build time. Instead, they load it at runtime with platform APIs. This is common for:
Common Mistakes
1. Thinking .a and .so are source files
They are not source code files. They are already compiled binary libraries.
.a= archive of object files.so= shared library object
2. Confusing compile time with link time
Beginners often think #include is enough to use a library.
#include only gives declarations. You still need to link the compiled library.
Broken example:
#include "greet.h"
int main(void) {
greet();
return 0;
}
If you compile without linking the library:
gcc main.c -o app
You may get an error like:
undefined reference to `greet`
3. Linking succeeds, but the program fails at runtime
This often happens with shared libraries.
Comparisons
| Feature | .a static library | .so shared library |
|---|---|---|
| Full name | Archive library | Shared object |
| Linked when | Build time | Build time and loaded at runtime |
| Code copied into executable | Usually yes | Usually no |
| Executable size | Larger | Smaller |
| Runtime dependency | Usually no | Usually yes |
| Memory sharing across processes | No | Yes |
| Easier deployment | Often yes | Sometimes harder |
| Easier independent library updates | No |
Cheat Sheet
Quick reference
.o= object file.a= static library archive.so= shared library
Build a static library
gcc -c file.c -o file.o
ar rcs libname.a file.o
gcc main.c -L. -lname -o app
Build a shared library
gcc -fPIC -c file.c -o file.o
gcc -shared -o libname.so file.o
gcc main.c -L. -lname -o app
Linker naming rule
-lname
usually means:
- search for
libname.a - or search for
libname.so
Key idea
- static library: code is copied into executable
- shared library: code stays external and must be found at runtime
Common flags
-ccompile only-Ldiradd library search directory-lnamelink library namedlibname
FAQ
What is the difference between .a and .so files?
A .a file is usually a static library archive, while a .so file is usually a shared library. Static libraries are copied into the executable during linking; shared libraries are loaded separately at runtime.
Do I need a .a file at runtime?
Usually no. If your program was statically linked with code from a .a file, that code is already inside the executable.
Do I need a .so file at runtime?
Usually yes. The program depends on the shared library being available when it starts, unless it was linked differently or bundled specially.
Why does my program build but not run?
A common reason is that the program links against a shared library successfully, but the system cannot find that library at runtime.
What does -lfoo mean in a C build command?
It tells the linker to search for a library named libfoo, typically something like libfoo.a or libfoo.so.
Are .a files always static on AIX?
Not always in the way Linux developers expect. AIX can package shared-library-related content inside archive files too, so you should check AIX-specific library conventions.
Mini Project
Description
Create a tiny C project that demonstrates both a static library and a shared library using the same function. This project helps you see the difference between build-time linking and runtime loading in a concrete, hands-on way.
Goal
Build one C program that can be linked against a custom library, then observe how behavior differs when using a static library versus a shared library.
Requirements
- Create a library function that prints a message.
- Build that function into both a
.alibrary and a.solibrary. - Write a main program that calls the library function.
- Link and run the program using the library.
- Confirm what file is needed at runtime in each case.
Keep learning
Related questions
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.
C Pointer to Array vs Array of Pointers: How to Read Complex Declarations
Learn the difference between pointer-to-array and array-of-pointers in C, plus a simple rule for reading complex declarations correctly.