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_staticmath_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 ..

七、总结

类型 优点 缺点 适用场景
静态库 独立、启动快 体积大、更新难 小工具、嵌入式
动态库 节省内存、易更新 依赖管理复杂 大型项目、插件系统
相关推荐
jdlxx_dongfangxing29 分钟前
C++ 序列式容器深度解析:vector、string、deque 与 list
c++·stl
小欣加油1 小时前
leetcode 904 水果成篮
c++·算法·leetcode
Tipriest_2 小时前
C++ csignal库详细使用介绍
开发语言·c++·csignal·信号与异常
qq_25929724732 小时前
QT-窗口类部件
c++·qt
啊我不会诶2 小时前
CF每日4题(1500-1700)
c++·学习·算法
kyle~3 小时前
C++---多态(一个接口多种实现)
java·开发语言·c++
Mark12774 小时前
Trie 树(字典树)
c++·mark1277
Jiezcode4 小时前
Unreal Engine ClassName Rule
c++·游戏·图形渲染·虚幻引擎
risc-v@cn10 小时前
【在ubuntu下使用vscode打开c++的make项目及编译调试】
c++·vscode·ubuntu