gcc -shared Option
The -shared option in gcc creates shared libraries (.so files) that can be dynamically linked at runtime. This allows multiple programs to share the same library code, reducing memory usage and enabling library updates without recompiling programs.
Syntax
gcc -shared -fPIC -o libname.so source.c
-shared Option Details
- Purpose: Create shared libraries (.so files)
- Requires: Usually combined with -fPIC for position-independent code
- Output: Shared object file with .so extension
- Loading: Libraries loaded at runtime by dynamic linker
- Naming: Follow libname.so.version convention
Description
The -shared option creates dynamic libraries that are loaded at runtime rather than being embedded into executables. This provides flexibility and efficiency in software distribution and memory usage.
Key characteristics:
- Code shared between multiple programs
- Smaller executable sizes
- Runtime library loading and linking
- Ability to update libraries independently
- Reduced memory footprint when multiple programs use same library
Shared vs Static Libraries
| Aspect | Shared Libraries (.so) | Static Libraries (.a) |
|---|---|---|
| File Size | Smaller executables | Larger executables |
| Memory Usage | Shared between programs | Duplicated per program |
| Loading Time | Runtime loading | No runtime loading |
| Updates | Update library independently | Must recompile programs |
| Dependencies | Requires library at runtime | Self-contained executable |
✅ Advantages of Shared Libraries
- Memory Efficiency: Single copy shared by multiple programs
- Smaller Executables: Reduced disk space usage
- Easy Updates: Update library without recompiling programs
- Plugin Architecture: Dynamic loading of optional components
- System Libraries: Standard system functionality
⚠️ Considerations
- Runtime Dependencies: Library must be available at runtime
- Version Conflicts: "DLL Hell" - incompatible library versions
- Startup Time: Slight delay for dynamic linking
- Distribution: Must ensure library availability on target systems
- Debugging: More complex debugging across library boundaries
Detailed Examples
Basic shared library creation
# Create library source
gcc -fPIC -c mathlib.c -o mathlib.o
gcc -shared -o libmath.so mathlib.o
# Use library in program
gcc main.c -L. -lmath -o program
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./program
gcc -fPIC -c mathlib.c -o mathlib.o
gcc -shared -o libmath.so mathlib.o
# Use library in program
gcc main.c -L. -lmath -o program
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./program
Creates a shared library and links it with a program
One-step library creation
gcc -shared -fPIC -o libutils.so utils.c helper.c
Compiles and creates shared library in one command
Library with version information
# Create versioned library
gcc -shared -fPIC -Wl,-soname,libmath.so.1 -o libmath.so.1.0 mathlib.c
# Create symbolic links
ln -sf libmath.so.1.0 libmath.so.1
ln -sf libmath.so.1 libmath.so
gcc -shared -fPIC -Wl,-soname,libmath.so.1 -o libmath.so.1.0 mathlib.c
# Create symbolic links
ln -sf libmath.so.1.0 libmath.so.1
ln -sf libmath.so.1 libmath.so
Creates versioned shared library with proper naming convention
Complex library with dependencies
# Create library that depends on other libraries
gcc -shared -fPIC -o libcomplex.so complex.c -lm -lpthread
# Link program with complex library
gcc main.c -L. -lcomplex -o program
gcc -shared -fPIC -o libcomplex.so complex.c -lm -lpthread
# Link program with complex library
gcc main.c -L. -lcomplex -o program
Creates shared library with external dependencies
Installing system-wide
# Create and install library
gcc -shared -fPIC -o libmylib.so mylib.c
sudo cp libmylib.so /usr/local/lib/
sudo ldconfig
# Now can link without -L flag
gcc main.c -lmylib -o program
gcc -shared -fPIC -o libmylib.so mylib.c
sudo cp libmylib.so /usr/local/lib/
sudo ldconfig
# Now can link without -L flag
gcc main.c -lmylib -o program
Installs shared library system-wide for easy access
Complete Example
Library source (mathlib.c)
#include "mathlib.h"
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
int add(int a, int b) {
return a + b;
}
int multiply(int a, int b) {
return a * b;
}
Header file (mathlib.h)
#ifndef MATHLIB_H
#define MATHLIB_H
int add(int a, int b);
int multiply(int a, int b);
#endif
#define MATHLIB_H
int add(int a, int b);
int multiply(int a, int b);
#endif
Build and use
# Create shared library
gcc -shared -fPIC -o libmath.so mathlib.c
# Create main program
gcc main.c -L. -lmath -o calculator
# Run program
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./calculator
gcc -shared -fPIC -o libmath.so mathlib.c
# Create main program
gcc main.c -L. -lmath -o calculator
# Run program
export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./calculator
Best Practices
- Use -fPIC: Always compile with position-independent code
- Version Libraries: Use semantic versioning for library names
- Export Control: Use visibility attributes to control symbol exports
- ABI Stability: Maintain binary compatibility across versions
- Documentation: Provide clear API documentation and examples
- Testing: Test library with different programs and scenarios