C++之静态库 vs 动态库

我将详细为你讲解 C++ 项目中使用 CMake 构建 静态库(Static Library) 和 动态库(Shared Library) 的区别、用法、配置方式以及它们的优缺点。


一、静态库 vs 动态库:基本概念

特性 静态库(Static Library) 动态库(Shared Library)
文件扩展名 .a(Linux/Unix),.lib(Windows) .so(Linux),.dll(Windows),.dylib(macOS)
链接时机 编译时链接(Link Time) 运行时链接(Runtime)
包含方式 被复制到最终可执行文件中 不复制,运行时动态加载
文件大小 可执行文件较大 可执行文件较小
内存占用 每个程序都有独立副本 多个程序可共享一份
更新方式 修改库需重新编译整个程序 替换库文件即可更新
启动速度 快(无需加载外部库) 稍慢(需加载库)

二、CMake 中创建静态库和动态库

1. 基本语法

cmake 复制代码
add_library(<name> [STATIC | SHARED | MODULE] <source_files>)
  • STATIC:创建静态库
  • SHARED:创建动态库
  • 不指定类型时,由 BUILD_SHARED_LIBS 变量决定(推荐显式指定)

2. 示例项目结构

css 复制代码
project_root/
├── CMakeLists.txt
├── include/
│   └── math_utils.h
├── src/
│   └── math_utils.cpp
└── app/
    ├── main.cpp
    └── CMakeLists.txt

3. 根目录 CMakeLists.txt

cmake 复制代码
# CMake 最低版本
cmake_minimum_required(VERSION 3.10)

# 项目名称
project(MathLibrary LANGUAGES CXX)

# 设置 C++ 标准
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# 添加头文件路径(全局)
include_directories(include)

# 创建静态库
add_library(math_static STATIC
    src/math_utils.cpp
)

# 创建动态库
add_library(math_shared SHARED
    src/math_utils.cpp
)

# 设置目标属性(可选)
set_target_properties(math_static PROPERTIES OUTPUT_NAME "math")
set_target_properties(math_shared PROPERTIES OUTPUT_NAME "math")

# 导出头文件目录
target_include_directories(math_static PUBLIC include)
target_include_directories(math_shared PUBLIC include)

# 添加子目录(应用)
add_subdirectory(app)

4. include/math_utils.h

cpp 复制代码
#ifndef MATH_UTILS_H
#define MATH_UTILS_H

int add(int a, int b);
int multiply(int a, int b);

#endif

5. src/math_utils.cpp

cpp 复制代码
#include "math_utils.h"

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

int multiply(int a, int b) {
    return a * b;
}

6. app/main.cpp

cpp 复制代码
#include <iostream>
#include "math_utils.h"

int main() {
    std::cout << "5 + 3 = " << add(5, 3) << std::endl;
    std::cout << "5 * 3 = " << multiply(5, 3) << std::endl;
    return 0;
}

7. app/CMakeLists.txt

cmake 复制代码
# 创建可执行文件
add_executable(app_main main.cpp)

# 链接静态库
target_link_libraries(app_main math_static)

# 或者链接动态库(二选一)
# target_link_libraries(app_main math_shared)

三、编译与使用

1. 编译项目

bash 复制代码
mkdir build
cd build
cmake ..
make

生成的文件:

  • libmath.a(静态库)
  • libmath.so(动态库,Linux)
  • app_main(可执行文件)

2. 使用动态库时的注意事项

Linux 下运行时找不到 .so 文件?

解决方法:

  • 将 .so 文件放在系统库路径(如 /usr/lib),或
  • 设置环境变量:
bash 复制代码
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:.
./app_main

四、何时选择静态库 or 动态库?

场景 推荐类型 原因
发布独立可执行文件 静态库 无需依赖外部库
多个程序共享同一功能 动态库 节省内存,便于更新
希望快速部署 静态库 一键运行
插件系统 动态库(MODULE) 运行时加载
第三方库(如 OpenCV) 动态库 减小体积,避免重复编译

五、高级技巧

1. 使用 BUILD_SHARED_LIBS 控制默认类型

cmake 复制代码
set(BUILD_SHARED_LIBS ON)  # 默认生成 shared 库
add_library(mylib src.cpp) # 自动生成 .so 或 .dll

2. 导出库供其他项目使用

使用 install() 和 export 命令,生成配置文件供他人 find_package()。

cmake 复制代码
install(TARGETS math_static math_shared
        LIBRARY DESTINATION lib
        ARCHIVE DESTINATION lib
        INCLUDES DESTINATION include)

install(FILES ${CMAKE_SOURCE_DIR}/include/math_utils.h
        DESTINATION include)

3. 跨平台兼容命名

cmake 复制代码
set_target_properties(math_static PROPERTIES
    OUTPUT_NAME "math"
    PREFIX "lib"
    SUFFIX ".a"
)

六、常见问题

❓ 静态库和动态库能同时存在吗?

✅ 可以!只要名字不同(如 math_static 和 math_shared),就可以共存。

❓ 动态库在 Windows 上是 .dll,怎么用?

  • .dll 是运行时库
  • .lib 是导入库(用于链接)
  • CMake 会自动生成

❓ 如何只构建其中一个库?

使用 CMake 选项:

cmake 复制代码
option(BUILD_SHARED "Build shared library" ON)
option(BUILD_STATIC "Build static library" ON)

if(BUILD_SHARED)
    add_library(math_shared SHARED src/math_utils.cpp)
    target_include_directories(math_shared PUBLIC include)
endif()

if(BUILD_STATIC)
    add_library(math_static STATIC src/math_utils.cpp)
    target_include_directories(math_static PUBLIC include)
endif()

调用时指定:

bash 复制代码
cmake -DBUILD_SHARED=OFF ..

七、总结

类型 优点 缺点 适用场景
静态库 独立、启动快 体积大、更新难 小工具、嵌入式
动态库 节省内存、易更新 依赖管理复杂 大型项目、插件系统
相关推荐
悠仁さん6 小时前
【C++】AVL 树
c++
wuminyu6 小时前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++
小徐不徐说7 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
ragnwang7 小时前
Notes: Python pybind11 import C++ module
开发语言·c++·python
充值内卷8 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
樱花树下的数学喵11 小时前
手写简易 STL string|C++ 字符串底层实现
开发语言·c++
AI吃大瓜11 小时前
指针压力表读数3:C/C++实现指针压力表读数(可实时检测)
c++·指针读数·指针压力表·压力表自动读数·压力表读数
-银雾鸢尾-11 小时前
两数之和-C++实现
c++·算法
j7~12 小时前
【动态规划算法专题】动态规划五部曲实战:泰波那契数、三步问题、最小花费爬楼梯
c++·算法·动态规划·数据结构与算法
jimy112 小时前
C++ 报错的 qualifiers 的意思
开发语言·c++