当前位置: 首页 > news >正文

【CMake基础入门教程】第六课:构建静态库 / 动态库 与安装规则(install)

太棒了,我们进入 第六课:构建静态库 / 动态库 与安装规则(install)

这是模块化项目真正进入“可复用组件”的关键阶段:
你不仅能在项目里用库,还能编译出 .lib.dll 文件用于发布、安装、共享。


🎯 本课目标

  1. 学会构建 静态库(.lib/.a)动态库(.dll/.so)

  2. 区分 STATIC / SHARED 的区别

  3. 使用 install() 安装头文件和库文件

  4. 了解导出宏(Windows 动态库中必要)


一、什么是静态库与动态库?

类型文件扩展名链接方式使用场景
静态库.lib(Windows) / .a(Linux)编译时直接打包进程序单一程序使用
动态库.dll(Windows) / .so(Linux)编译时链接,运行时加载模块插件、共享使用

二、构建静态库的写法(默认就是 STATIC)

add_library(math_lib STATIC add.cpp)

表示编译出 math_lib.lib(或 .a),链接后合并进主程序

🔍 补充说明:

  • add_library(math_lib STATIC add.cpp)add_library(math_lib add.cpp) 是等价的,因为 CMake 默认库类型就是 STATIC

  • 为了提高可读性,建议只写一次;

  • 如果未来你想改成动态库,只需改为 SHARED 即可。


三、构建动态库的写法

add_library(math_lib SHARED add.cpp)

表示编译出:

  • Windows: math_lib.dll + math_lib.lib

  • Linux: libmath_lib.so

主程序运行时要能找到动态库文件才不会报错。


⚠️ Windows 下写 DLL 要加“导出宏”

✅ 修改 add.h
#pragma once// __declspec(dllexport) / __declspec(dllimport)
#ifdef _WIN32
#  ifdef MATH_LIB_EXPORTS
#    define MATH_API __declspec(dllexport)
#  else
#    define MATH_API __declspec(dllimport)
#  endif
#else
#  define MATH_API
#endifMATH_API int add(int a, int b);
✅ 修改 math/CMakeLists.txt
add_library(math_lib SHARED add.cpp)target_include_directories(math_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})# 告诉编译器定义 MATH_LIB_EXPORTS(用于导出符号)
target_compile_definitions(math_lib PRIVATE MATH_LIB_EXPORTS)

四、安装库和头文件(install)

你可以让项目支持:

cmake --install .

添加到 math/CMakeLists.txt

install(TARGETS math_libRUNTIME DESTINATION bin     # .exe, .dllLIBRARY DESTINATION lib     # .soARCHIVE DESTINATION lib     # .lib, .a
)install(FILES add.h DESTINATION include)

运行安装命令:

cmake --install . --config Release

安装结果目录结构(默认 build/):

build/
└── install/├── bin/│   └── math_lib.dll├── lib/│   └── math_lib.lib└── include/└── add.h

你也可以设置安装目录:

cmake .. -DCMAKE_INSTALL_PREFIX=D:/MyLibs

五、主程序如何使用你安装的库?

在其他项目中你可以这样使用:

include_directories(D:/MyLibs/include)
link_directories(D:/MyLibs/lib)
target_link_libraries(app math_lib)

(更推荐方法我们后面会用 find_package() 实现)


✅ 小测验

  1. STATIC vs SHARED 区别是?

    ✅ 静态库会被编译进程序,动态库需要运行时加载

  2. Windows 下写 DLL 为什么要加宏?

    ✅ 因为导出/导入函数需要 __declspec(dllexport/import) 来告诉链接器

  3. install() 的作用是?

    ✅ 把库、头文件、执行文件拷贝到标准结构,供后续其他项目复用

以下是一个完整演示项目,包含:

  • 静态库和动态库的构建;

  • 安装规则(头文件、库);

  • 主程序调用库;

  • 所有文件都加上详细注释。


✅ 项目结构如下(推荐创建名为 math_demo_project):

math_demo_project/
├── CMakeLists.txt             # 主工程
├── main.cpp                   # 主程序
└── math/                      # 子模块(库)├── CMakeLists.txt├── add.h└── add.cpp

📄 main.cpp(主程序)

#include <iostream>
#include "add.h"int main() {int x = 10, y = 20;std::cout << x << " + " << y << " = " << add(x, y) << std::endl;return 0;
}

📄 math/add.h(头文件,带导出宏)

#pragma once// 支持 Windows 动态库导入导出
#ifdef _WIN32
#  ifdef MATH_LIB_EXPORTS
#    define MATH_API __declspec(dllexport)
#  else
#    define MATH_API __declspec(dllimport)
#  endif
#else
#  define MATH_API
#endif// 导出函数
MATH_API int add(int a, int b);

📄 math/add.cpp(库实现)

#include "add.h"int add(int a, int b) {return a + b;
}

📘 math/CMakeLists.txt(构建静态库和动态库)

# 构建一个动态库
add_library(math_shared SHARED add.cpp)
target_include_directories(math_shared PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(math_shared PRIVATE MATH_LIB_EXPORTS)# 构建一个静态库
add_library(math_static STATIC add.cpp)
target_include_directories(math_static PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})# 安装规则(头文件 + 库文件)
install(TARGETS math_shared math_staticRUNTIME DESTINATION bin         # .dll/.exe (Windows)LIBRARY DESTINATION lib         # .so       (Linux/macOS)ARCHIVE DESTINATION lib         # .lib/.a   (Windows, Linux)
)install(FILES add.h DESTINATION include)

📘 顶层 CMakeLists.txt(主项目)

cmake_minimum_required(VERSION 3.10)
project(MathDemo LANGUAGES CXX)# 添加子模块(库)
add_subdirectory(math)# 创建主程序
add_executable(main_app main.cpp)
target_compile_features(main_app PRIVATE cxx_std_17)# 使用静态库或动态库:
# 任选一个链接(不建议两个都连)target_link_libraries(main_app PRIVATE math_shared)
# target_link_libraries(main_app PRIVATE math_static)

🔨 编译 + 安装流程(命令行)

# Step 1: 创建构建目录
mkdir build
cd build# Step 2: 配置项目(推荐使用 VS 或者 MinGW)
cmake .. -G "Visual Studio 17 2022" -DCMAKE_INSTALL_PREFIX=install# Step 3: 构建 Release 模式
cmake --build . --config Release# Step 4: 安装库文件和头文件
cmake --install . --config Release

✅ 安装结果目录(build/install):

install/
├── bin/
│   └── math_shared.dll
├── lib/
│   ├── math_shared.lib
│   └── math_static.lib
└── include/└── add.h

💡 使用建议

  • 默认链接动态库 math_shared(你也可以切换到 math_static

  • 若用的是 math_shared.dll程序运行时要和 .dll 在同目录

  • 使用 install() 后,可以在其他项目中方便复用这个库


⏮️ 上一课回顾:【CMake基础入门】第五课:拆分模块与使用 add_subdirectory() 构建子目录项目

⏭️ 下一课预告:使用第三方库(如 Qt / Boost / OpenCV)与 find_package()

下一课将非常关键,我们将讲解:

  • 如何使用系统或 vcpkg / conan 安装的库

  • 使用 find_package() 找到并连接这些库

  • target 方式的现代写法(target_link_libraries

相关文章:

  • MySQL至KES迁移最佳实践
  • 用 Spark 优化亿级用户画像计算:Delta Lake 增量更新策略详解
  • vue3 json 转 实体
  • 2.1、STM32 CAN外设简介
  • Vue3 中 Axios 深度整合指南:从基础到高级实践引言总结
  • MR30分布式IO:产线改造省时 70%
  • 22. 括号生成
  • AI编程工具深度对比:腾讯云代码助手CodeBuddy、Cursor与通义灵码
  • ubuntu20.04如何给appImage创建快捷方式
  • EXILIUM×亚矩云手机:重构Web3虚拟生存法则,开启多端跨链元宇宙自由征途
  • 【JeecgBoot AIGC】打造智能AI应用
  • 51c~嵌入式~PLC~三菱~合集1
  • 记dwz(JUI)前端框架使用之--服务端响应提示框
  • 如何在x86_64 Linux上部署Android Cuttlefish模拟器运行环境
  • Spring Cloud Feign 整合 Sentinel 实现服务降级与熔断保护
  • python + opencv实现简单的文字水印
  • 【CSS 行高陷阱:如何避免文本被截断问题】
  • 【RESTful接口设计规范全解析】URL路径设计 + 动词名词区分 + 状态码 + 返回值结构 + 最佳实践 + 新手常见误区汇总
  • Day43 复习日 图像数据集——CNN
  • 数据结构进阶 - 第一章 绪论