Master the Core Logic of Library Building from Compilation Principles to Industrial Practices
1. Essential Differences Between Static and Dynamic Libraries
Core Feature Comparison
| Feature | Static Library (<span>.a</span>/<span>.lib</span>) |
Dynamic Library (<span>.so</span>/<span>.dll</span>) |
|---|---|---|
| Linking Method | Compiled into the executable file at build time | Loaded dynamically at runtime |
| Memory Usage | Multiple loads of the same library will consume memory repeatedly | Loaded only once in memory, shared usage |
| Update Maintenance | Requires recompilation of the main program | Replacing the library file takes effect |
| Applicable Scenarios | Small toolchains, embedded development | Large frameworks, plugin systems |
1.2 Dependency Management
- Static Library:
- All dependencies are directly embedded in the final executable file.
- Advantages: Simple deployment (no external dependencies).
- Disadvantages: Large executable file size, requires full recompilation for updates.
- Dynamic Library:
- Dependencies are resolved at runtime.
- Advantages: Modular updates, saves memory.
- Disadvantages: Must ensure correct runtime paths (
<span>LD_LIBRARY_PATH</span>or<span>RPATH</span>).
2. Detailed Explanation of Core Function: <span>add_library()</span>
2.1 Basic Syntax and Parameters
add_library(<name> [STATIC | SHARED | OBJECT]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
- Type Parameter:
<span>STATIC</span>: Static library (default type).<span>SHARED</span>: Dynamic library (must enable<span>-fPIC</span>).<span>OBJECT</span>: Collection of intermediate object files (speeds up compilation).
- Key Options:
<span>EXCLUDE_FROM_ALL</span>: Does not participate in the default build (needs manual compilation).
2.2 Practical Example: Building a Mathematical Static Library and a Network Dynamic Library
# Static Library Example
add_library(math_utils STATIC
src/matrix.cpp
src/vector.cpp
)
# Dynamic Library Example (requires -fPIC)
add_library(network SHARED
src/socket.cpp
src/http.cpp
)
# Enable position-independent code (required for dynamic libraries)
set_target_properties(network PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
3. Symbol Hiding and Position Independent Code (fPIC)
3.1 Symbol Hiding
- Problem: By default, dynamic libraries export all symbols (functions/variables), leading to naming conflicts.
- Solution:
- Compiler Option:
<span>-fvisibility=hidden</span>(GCC/Clang). - Code Marking: Explicitly declare exported symbols.
// Export symbol
__attribute__((visibility("default"))) void public_api();
// Hide symbol (default)
void internal_impl();
- CMake Configuration:
set(CMAKE_CXX_VISIBILITY_PRESET hidden) # Globally hide symbols
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Hide inline functions
3.2 Position Independent Code (-fPIC)
- Function: Generates code that is independent of memory location, required for dynamic libraries.
- CMake Configuration:
# Globally enable (recommended)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# Or for specific targets
set_target_properties(network PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
4. Compilation Parameters and Optimization Techniques
4.1 Common Compilation Options
| Parameter | Function | Example |
|---|---|---|
<span>-Wall -Wextra</span> |
Enable all warnings | <span>target_compile_options(<target> PRIVATE -Wall -Wextra)</span> |
<span>-O3</span> |
Highest optimization level | <span>target_compile_options(<target> PRIVATE -O3)</span> |
<span>-g</span> |
Generate debug symbols | <span>target_compile_options(<target> PRIVATE -g)</span> |
<span>-march=native</span> |
Optimize for local CPU | <span>target_compile_options(<target> PRIVATE -march=native)</span> |
4.2 Separate Build Type Configuration
# Debug mode configuration
target_compile_options(math_utils PRIVATE
$<$<CONFIG:Debug>:-O0 -g3>
)
# Release mode configuration
target_compile_options(math_utils PRIVATE
$<$<CONFIG:Release>:-O3 -DNDEBUG>
)
5. Practical Example: Multi-Library Dependencies and Link Control
5.1 Project Structure
Project/
├── CMakeLists.txt
├── src/
│ ├── main.cpp
│ ├── math/
│ │ ├── matrix.cpp
│ │ └── vector.cpp
│ └── network/
│ ├── socket.cpp
│ └── http.cpp
└── include/
├── math_utils.h
└── network_utils.h
5.2 Configuring Dependencies
# Main program links library
add_executable(my_app src/main.cpp)
# Static Library: Math Library
add_library(math STATIC src/math/matrix.cpp src/math/vector.cpp)
target_include_directories(math PUBLIC include/)
# Dynamic Library: Network Library (depends on Math Library)
add_library(network SHARED src/network/socket.cpp src/network/http.cpp)
target_include_directories(network PUBLIC include/)
target_link_libraries(network PRIVATE math) # Private dependency
# Main program links Network Library (automatically gets Math header files)
target_link_libraries(my_app PRIVATE network)
5.3 Key Validation Points
- Symbol Visibility:
nm -D build/libnetwork.so | grep public_api # Should only show exported symbols
- Dependency Propagation:
// In main.cpp, can directly use math_utils.h (due to network's PUBLIC dependency)
#include "math_utils.h"
6. Common Issues and Solutions
6.1 Dynamic Library Load Failure
- Phenomenon: Runtime prompts
<span>error while loading shared libraries: libnetwork.so</span> - Solution:
# Set RPATH (relative path)
set(CMAKE_BUILD_RPATH "$ORIGIN") # Same directory as executable
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
6.2 Mixing Static and Dynamic Library Linking
- Rule: If a dynamic library depends on a static library, ensure the static library is compiled with
<span>-fPIC</span>. - Configuration:
# Enable -fPIC for static library (if it will be depended on by dynamic library)
set_target_properties(math PROPERTIES
POSITION_INDEPENDENT_CODE ON
)
6.3 Cross-Platform Symbol Export (Windows)
- Code Marking:
#ifdef _WIN32
# define API_EXPORT __declspec(dllexport)
#else
# define API_EXPORT __attribute__((visibility("default")))
#endif
API_EXPORT void public_api();
7. Summary and Next Article Preview
Key Points of This Article:
- Master the core differences and building methods of static and dynamic libraries.
- Deeply understand the compilation principles of
<span>-fPIC</span>and symbol hiding. - Implement multi-library dependency control and cross-platform configuration.
Next Article Preview:
- “Part 6: Header Files and Linkers – Modern
<span>target_*</span>Command Family”
<span>target_include_directories</span>vs<span>include_directories</span><span>target_link_libraries</span>dependency propagation rules- Completely eliminate traditional commands (such as
<span>link_directories</span>etc.)
CMake Mastery (1): CMake Simplified Introduction – Environment Configuration and First ProjectCMake Mastery (2): Variables and ScopesCMake Mastery (3): Functions and Parameter PassingCMake Mastery (4): Multi-Directory Project Management – The Philosophy of add_subdirectory