【CMake基础入门教程】第六课:构建静态库 / 动态库 与安装规则(install)
太棒了,我们进入 第六课:构建静态库 / 动态库 与安装规则(install)。
这是模块化项目真正进入“可复用组件”的关键阶段:
你不仅能在项目里用库,还能编译出 .lib
或 .dll
文件用于发布、安装、共享。
🎯 本课目标
-
学会构建 静态库(.lib/.a) 和 动态库(.dll/.so)
-
区分
STATIC
/SHARED
的区别 -
使用
install()
安装头文件和库文件 -
了解导出宏(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()
实现)
✅ 小测验
-
STATIC
vsSHARED
区别是?✅ 静态库会被编译进程序,动态库需要运行时加载
-
Windows 下写 DLL 为什么要加宏?
✅ 因为导出/导入函数需要
__declspec(dllexport/import)
来告诉链接器 -
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
)