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

七、总结

类型 优点 缺点 适用场景
静态库 独立、启动快 体积大、更新难 小工具、嵌入式
动态库 节省内存、易更新 依赖管理复杂 大型项目、插件系统
相关推荐
江安下小雨6 分钟前
muduo网络库(十六):新增连接池模块
网络·c++
「QT(C++)开发工程师」16 分钟前
C++11 std::unique_ptr — 独占所有权的智能指针
c语言·开发语言·c++·qt
不正经学生37 分钟前
C语言动态内存管理(上):堆上的自由与责任
c语言·开发语言·c++·算法·面试
zl.rs1 小时前
配置更适合生产环境的coredump
c++
一木 之林2 小时前
三.C++ 内存管理(进阶)(二)
开发语言·arm开发·c++
DLite2 小时前
开源一个静态类型语言——NLang
c++·编译器·nlang
uoKent2 小时前
c++中new和malloc的区别
java·jvm·c++
会周易的程序员3 小时前
aiDgeController 软PLC虚拟机stvm集成测试报告
c++·物联网·架构·集成测试·st·软plc·iec61131
布莱克6053 小时前
队列详解:定义、分类、应用场景及与栈的区别(C/C++ 代码讲解)
c语言·开发语言·c++·队列
郝学胜-神的一滴3 小时前
C++11 工程级应用 06:自己造一个类似Python的Range迭代器
开发语言·c++·windows·python·程序人生·microsoft