windows + visual studio 2019 使用cmake 编译构建静、动态库并调用详解

环境
windows + visual studio 2019
visual studio 2019创建cmake工程

1. 静态库.lib

1.1 静态库编译生成

以下是我创建的cmake工程文件结构,只关注高亮文件夹部分
在这里插入图片描述

  • libout 存放编译生成的.lib文件
  • libsrc 存放编译用的源代码和头文件
  • CMakeLists.txt 此次编译CMake项目的配置文件

接着我们看一下我们的代码, 代码注释很详细


libscr/add.h 头文件中声明了两个不同精度的求和函数

// #ifndef...  #define...   #endif... 防止头文件被重复调用的时候头文件中多次定义报错, 意思只定义一次
#ifndef ADD_H
#define ADD_Hint add(int, int);
double add(double, double);#endif

libscr/add.cpp 源文件是两个不同精度的求和函数的定义

// add.cpp
#include "add.h"// 重载 int 类型的加法
int add(int a, int b) {return a + b;
}// 重载 double 类型的加法
double add(double a, double b) {return a + b;
}

CMakeLists.txt

  • add_library()中 addlib 是生成的.lib名称;STATIC 指定的是生成库类型为静态库
  • set_target_properties 设置静态库存放路径为libout文件夹下
# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置
# 并包含子项目。
#
cmake_minimum_required (VERSION 3.8)
project ("libgen")
# 设置c++标准
set(CMAKE_CXX_STANDARD 11)# 生成静态库并指定静态库存放路径
add_library(addlib STATIC libsrc/add.cpp)
set_target_properties(addlib PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libout)

全部重新生成,即可将编译的.lib文件生成到指定的文件夹下
在这里插入图片描述
在这里插入图片描述


1.2 静态库使用

同样只关注高亮文件夹部分
在这里插入图片描述

  • libinclude 存放头文件,直接从libscr 将头文件copy过来即可
  • libout 1.1中编译生成的.lib文件
  • libuse 调用lib的代码实现
  • CMakeLists.txt 此次编译执行的CMake项目的配置文件

libuse/main.cpp 调用静态库中的add求和函数实现

#include "add.h"
#include <iostream>int main() {int a = 3, b = 5;std::cout << "add(3.1, 4.1) = " << add(3.1, 4.1) << std::endl;std::cout << "add(3.1f, 4.1f) = " << add(3.1f, 4.1f) << std::endl;std::cout << "add(3, 4) = " << add(a, b) << std::endl;return 0;
}

CMakeLists.txt 注释说的非常清楚了,不在详说

# CMakeList.txt: 顶层 CMake 项目文件,在此处执行全局配置
# 并包含子项目。
#
cmake_minimum_required (VERSION 3.8)
project ("libgen")
# 设置c++标准
set(CMAKE_CXX_STANDARD 11)# 生成静态库并指定静态库存放路径
# add_library(addlib STATIC libsrc/add.cpp)
# set_target_properties(addlib PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/libout)## 创建可执行文件并指定头文件
add_executable(testlib libuse/main.cpp)
## 指定addlib.lib的绝对路径
target_link_libraries(testlib  PRIVATE ${PROJECT_SOURCE_DIR}/libout/addlib.lib)
## 指定头文件目录
target_include_directories(testlib PRIVATE ${PROJECT_SOURCE_DIR}/libinclude)

执行结果和预期完全一样
在这里插入图片描述

2. 动态库.dll

2.1 动态库编译生成

在这里插入图片描述

  • dllout 存放编译生成的动态库文件
  • dllsrc 存放编译用的源代码和头文件
  • CMakeLists.txt 此次编译CMake项目的配置文件

dllscr/add.h 这里与静态库非常不一样
在Windows平台上,动态库(DLL)的导出和导入需要通过 __declspec(dllexport)__declspec(dllimport) 来显式声明。通常,我们会使用一个宏来切换这两种声明。如下:

  • MATHLIBRARY_EXPORTS 被定义时,MATHLIBRARY_API 会被替换为 __declspec(dllexport),表示当前正在编译动态库,需要导出符号。在编译dll的时候CMakeLists.txt中会定义。
  • MATHLIBRARY_EXPORTS 未被定义时,MATHLIBRARY_API 会被替换为 __declspec(dllimport),表示当前正在使用动态库,需要导入符号。在执行调用dll的时候CMakeLists.txt中不会定义。
// add.h
#pragma once#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endifextern "C" MATHLIBRARY_API int add(int a, int b);
  • extern "C":告诉编译器按照C语言的方式处理函数名,即不进行名称修饰。
  • MATHLIBRARY_EXPORTS 被定义时,MATHLIBRARY_API 会被替换为 __declspec(dllexport),表示该函数需要从动态库中导出。
  • MATHLIBRARY_EXPORTS 未被定义时,MATHLIBRARY_API 会被替换为 __declspec(dllimport),表示该函数是从动态库中导入的。

dllscr/add.cpp 源文件函数定义没什么好说的

// add.cpp
#include "add.h"extern "C" MATHLIBRARY_API int add(int a, int b) {return a + b;
}

CMakeLists.txt

  • add_library()中 adddll 是生成的.lib名称;SHARED 指定的是生成库类型为动态库
  • set_target_properties 设置静态库存放路径为dllout文件夹下
  • target_compile_definitions() 编译动态库是一定要定义宏,告知此时需要导出库
cmake_minimum_required(VERSION 3.10)
project("dllgen")# 设置C++标准
set(CMAKE_CXX_STANDARD 11)# 添加动态库
add_library(adddll SHARED dllsrc/add.cpp)# 指定动态库的导出宏 编译动态库的时候定义宏MATHLIBRARY_EXPORT
target_compile_definitions(adddll PRIVATE MATHLIBRARY_EXPORTS)# 设置输出路径
set_target_properties(adddll PROPERTIESARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/dlloutRUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/dllout
)

编译生成的只需要.dll 和.lib 。记住.lib并非静态库,而是导入库,用于解析符号引用
在这里插入图片描述


2.2 动态库使用

同样只关注高亮文件夹部分
在这里插入图片描述

  • dllinclude 存放头文件,直接从dllscr 将头文件copy过来即可
  • dllout 2.1中编译生成的.dll, .lib文件
  • dlluse 调用dll的代码实现
  • CMakeLists.txt 此次编译执行的CMake项目的配置文件

dlluse/main.cpp 调用静态库中的add求和函数实现

// main.cpp
#include <iostream>
#include "add.h"int main() {int result = add(3, 4);std::cout << "3 + 4 = " << result << std::endl;return 0;
}

CMakeLists.txt 注释说的非常清楚了,不在详说,但是需要注意的是:

  • 链接的是.lib 导入库
  • .dll 的文件夹路径一定要添加到环境变量中,或者放在.exe目录下,我这里是提前添加到环境变量中去了
    在这里插入图片描述
cmake_minimum_required(VERSION 3.10)
project("dllgen")# 设置C++标准
set(CMAKE_CXX_STANDARD 11)# 添加动态库
#add_library(adddll SHARED dllsrc/add.cpp "dllinclude/add.h")# 指定动态库的导出宏 编译动态库的时候定义宏MATHLIBRARY_EXPORT
#target_compile_definitions(adddll PRIVATE MATHLIBRARY_EXPORTS)# 设置输出路径
#set_target_properties(adddll PROPERTIES
#    ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/dllout
#    RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/dllout
#)# 添加可执行文件
add_executable(testdll dlluse/main.cpp)# 链接动态库的导入库到可执行文件,并非直接链接动态库
target_link_libraries(testdll PRIVATE ${PROJECT_SOURCE_DIR}/dllout/adddll.lib)
## 指定头文件目录
target_include_directories(testdll PRIVATE ${PROJECT_SOURCE_DIR}/dllinclude)

执行结果和预期完全一样,而且输出视图中我们能够看到adddll.dll的加载
在这里插入图片描述
在这里插入图片描述

3 静态库、动态库区别联系(以下来自deepseek)

静态库和动态库是两种常见的代码复用方式,它们在代码链接、内存管理、维护灵活性等方面有显著差异。以下是它们的核心区别与联系:


一、核心区别

特性静态库动态库
文件格式.lib(Windows)、.a(Linux).dll(Windows)、.so(Linux) + 导入库 .lib(Windows)
链接时机编译时直接嵌入到可执行文件中运行时由操作系统动态加载到内存中
代码存储可执行文件包含库代码的完整副本可执行文件仅包含对动态库的引用
内存占用多进程无法共享库代码,内存冗余多进程可共享同一动态库,节省内存
更新维护更新库需重新编译整个程序更新库只需替换动态库文件,无需重新编译程序
运行依赖无需外部库文件,独立性强依赖动态库文件存在且路径正确
加载速度启动快(代码已嵌入)启动稍慢(需加载动态库)
体积大小可执行文件体积大可执行文件体积小

二、核心联系

  1. 代码复用

    • 两者均用于封装通用功能(如数学计算、文件操作),避免重复开发。
    • 例如:将加密算法封装为库,供多个项目调用。
  2. 模块化设计

    • 通过库分离核心模块和业务逻辑,提升代码可维护性。
    • 例如:将图形渲染功能封装为动态库,独立于主程序更新。
  3. 混合使用

    • 项目中可同时使用静态库和动态库。
    • 例如:主程序链接静态库保证核心功能稳定,插件使用动态库实现热更新。

三、典型应用场景

场景静态库动态库
嵌入式开发✅ 资源有限,需减少运行时依赖❌ 动态加载可能增加复杂性
跨平台插件❌ 更新需重新编译✅ 支持运行时加载,如浏览器插件、游戏模组
系统级共享功能❌ 内存占用高✅ 如Windows的kernel32.dll,Linux的libc.so
闭源分发✅ 代码完全嵌入,保护知识产权❌ 需分发动态库文件
快速迭代更新❌ 每次更新需重新编译✅ 替换动态库即可生效

四、技术细节对比

1. 符号冲突处理
  • 静态库:多个静态库中同名符号会导致链接错误。
  • 动态库:符号在运行时解析,不同动态库的同名符号可共存。
2. 跨平台兼容性
  • Windows
    • 静态库:.lib
    • 动态库:.dll(实现文件) + .lib(导入库)
  • Linux
    • 静态库:.a
    • 动态库:.so(直接链接,无需导入库)
3. CMake配置
# 静态库
add_library(MyStaticLib STATIC src.cpp)
target_include_directories(MyStaticLib PUBLIC include)# 动态库(需导出符号)
add_library(MySharedLib SHARED src.cpp)
target_compile_definitions(MySharedLib PRIVATE MYLIB_EXPORTS)
target_include_directories(MySharedLib PUBLIC include)# 使用库
add_executable(MyApp main.cpp)
target_link_libraries(MyApp PRIVATE MyStaticLib MySharedLib)

五、如何选择?

  • 选静态库
    ✅ 项目规模小,无需频繁更新
    ✅ 对启动速度敏感(如命令行工具)
    ✅ 目标环境依赖管理困难(如嵌入式设备)

  • 选动态库
    ✅ 代码需多进程共享(如系统库)
    ✅ 支持热更新或插件化架构
    ✅ 减少可执行文件体积(如大型应用)


六、总结

静态库和动态库本质是代码复用的两种策略

  • 静态库追求简单性和独立性,牺牲体积和灵活性。
  • 动态库追求资源共享和灵活性,牺牲启动速度和环境依赖。

实际开发中,二者常结合使用。例如:核心基础模块用静态库保证稳定性,业务模块用动态库支持灵活扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/69731.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【前端】几种常见的跨域解决方案代理的概念

几种常见的跨域解决方案&代理的概念 一、常见的跨域解决方案1. 服务端配置CORS&#xff08;Cross-Origin Resource Sharing&#xff09;&#xff1a;2. Nginx代理3. Vue CLI配置代理&#xff1a;4 .uni-app在manifest.json中配置代理来解决&#xff1a;5. 使用WebSocket通讯…

Git 分布式版本控制工具使用教程

1.关于Git 1.1 什么是Git Git是一款免费、开源的分布式版本控制工具&#xff0c;由Linux创始人Linus Torvalds于2005年开发。它被设计用来处理从很小到非常大的项目&#xff0c;速度和效率都非常高。Git允许多个开发者几乎同时处理同一个项目而不会互相干扰&#xff0c;并且在…

基于java手机销售网站设计和实现(LW+源码+讲解)

专注于大学生项目实战开发,讲解,毕业答疑辅导&#xff0c;欢迎高校老师/同行前辈交流合作✌。 技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、小程序、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;…

GitHub Pages + Jekyll 博客搭建指南(静态网站搭建)

目录 &#x1f680; 静态网站及其生成工具指南&#x1f30d; 什么是静态网站&#xff1f;&#x1f4cc; 静态网站的优势⚖️ 静态网站 VS 动态网站 &#x1f680; 常见的静态网站生成器对比&#x1f6e0;️ 使用 GitHub Pages Jekyll 搭建个人博客&#x1f4cc; 1. 创建 GitHu…

1.【线性代数】——方程组的几何解释

一 方程组的几何解释 概述举例举例一1. matrix2.row picture3.column picture 概述 三种表示方法 matrixrow picturecolumn picture 举例 举例一 { 2 x − y 0 − x 2 y 3 \begin{cases} 2x - y 0 \\ -x 2y 3 \end{cases} {2x−y0−x2y3​ 1. matrix [ 2 − 1 − 1 …

ZZNUOJ(C/C++)基础练习1091——1100(详解版)⭐

目录 1091 : 童年生活二三事&#xff08;多实例测试&#xff09; C C 1092 : 素数表(函数专题&#xff09; C C 1093 : 验证哥德巴赫猜想&#xff08;函数专题&#xff09; C C 1094 : 统计元音&#xff08;函数专题&#xff09; C C 1095 : 时间间隔&#xff08;多…

innovus如何分步长func和dft时钟

在Innovus工具中&#xff0c;分步处理功能时钟&#xff08;func clock&#xff09;和DFT时钟&#xff08;如扫描测试时钟&#xff09;需要结合设计模式&#xff08;Function Mode和DFT Mode&#xff09;进行约束定义、时钟树综合&#xff08;CTS&#xff09;和时序分析。跟随分…

java高级知识之集合

前言 集合是java开发中的重点内容&#xff0c;需要掌握的东西很多&#xff0c;面试中可问的东西很多&#xff0c;无论是深度还是广度。集合框架中Collection对应的实现类如下所示&#xff0c;这些都是要完全掌握&#xff0c;一个可以分为三大类List集合、Set‘集合以及Map集合…

51c自动驾驶~合集49

我自己的原文哦~ https://blog.51cto.com/whaosoft/13164876 #Ultra-AV 轨迹预测新基准&#xff01;清华开源&#xff1a;统一自动驾驶纵向轨迹数据集 自动驾驶车辆在交通运输领域展现出巨大潜力&#xff0c;而理解其纵向驾驶行为是实现安全高效自动驾驶的关键。现有的开…

Unity-Mirror网络框架-从入门到精通之MultipleMatches示例

文章目录 前言MultipleMatchesLobbyViewRoomViewMatchGUIPlayerGUI总结前言 在现代游戏开发中,网络功能日益成为提升游戏体验的关键组成部分。本系列文章将为读者提供对Mirror网络框架的深入了解,涵盖从基础到高级的多个主题。Mirror是一个用于Unity的开源网络框架,专为多人…

VMware Workstation创建虚拟机

目录 创建新的虚拟机 虚拟机快照功能 虚拟机添加空间 其他注意事项 创建新的虚拟机 打开VMware Workstation&#xff1a;启动软件后&#xff0c;点击“创建新的虚拟机”。 选择安装方式&#xff1a; 典型安装&#xff1a;适合大多数用户&#xff0c;会自动完成大部分配置…

DeepSeek AI R1推理大模型API集成文档

DeepSeek AI R1推理大模型API集成文档 引言 随着自然语言处理技术的飞速发展&#xff0c;大语言模型在各行各业的应用日益广泛。DeepSeek R1作为一款高性能、开源的大语言模型&#xff0c;凭借其强大的文本生成能力、高效的推理性能和灵活的接口设计&#xff0c;吸引了大量开发…

活泼瘤胃球菌(Ruminococcus gnavus)——多种疾病风险的潜在标志物

​ 前几日&#xff0c;南方医科大学深圳医院院长周宏伟教授团队在国际顶尖医学期刊《Nature Medicine》上发表了一项重要研究。首次揭示一种名为活泼瘤胃球菌(Ruminococcus gnavus)的细菌产生的物质——苯乙胺&#xff0c;在肝性脑病发生中的关键作用。 ​ 同时谷禾的人群检测数…

8.flask+websocket

http是短连接&#xff0c;无状态的。 websocket是长连接&#xff0c;有状态的。 flask中使用websocket from flask import Flask, request import asyncio import json import time import websockets from threading import Thread from urllib.parse import urlparse, pars…

qiime2:安装与使用

试一下docker安装 docker pull quay.io/qiime2/amplicon:2024.10 docker images docker run -v {挂载的目录}:/data quay.io/qiime2/amplicon:2024.10 qiime -h使用 import.txt docker run -v ~/diarrhoea/MJ/qingzhu:/data quay.io/qiime2/amplicon:2024.10 qiime tools imp…

技术实战|ELF 2学习板本地部署DeepSeek-R1大模型的完整指南(一)

DeepSeek作为国产AI大数据模型的代表&#xff0c;凭借其卓越的推理能力和高效的文本生成技术&#xff0c;在全球人工智能领域引发广泛关注。DeepSeek-R1作为该系列最新迭代版本&#xff0c;实现了长文本处理效能跃迁、多模态扩展规划、嵌入式适配等技术维度的突破。 RK3588作为…

DeepSeek本地部署_桌面版AnythingLLM本地知识库搭建

一.DeepSeek本地部署 1.下载并安装&#xff1a;ollama Download Ollama on macOSDownload Ollama for macOShttps://ollama.com/download 安装是否成功确认&#xff0c;管理员权限运行PowerShell&#xff1a; ollama -h 2.下载安装DeepSeek 管理员方式运行PowerShell&#…

BGP基础协议详解

BGP基础协议详解 一、BGP在企业中的应用二、BGP概述2.1 BGP的特点2.2 基本配置演示2.3 抓包观察2.4 BGP的特征三、BGP对等体关系四、bgp报文4.1 BGP五种报文类型(重点)4.2 BGP报文格式-报文头格式4.3 Open报文格式4.4 Update报文格式4.5 Notification报文格式4.6 Route-refre…

2025.2.10 每日学习记录3:技术报告只差相关工作+补实验

0.近期主任务线 1.完成小论文准备 目标是3月份完成实验点1的全部实验和论文。 2.准备教资笔试 打算留个十多天左右&#xff0c;一次性备考笔试的三个科目 1.实习申请技术准备&#xff1a;微调、Agent、RAG 据央视财经&#xff0c;数据显示&#xff0c;截至2024年12月…

算法 ST表

目录 前言 一&#xff0c;暴力法 二&#xff0c;打表法 三&#xff0c;ST表 四&#xff0c;ST表的代码实现 总结 前言 ST表的主要作用是在一个区间里面寻找最大值&#xff0c;具有快速查找的功能&#xff0c;此表有些难&#xff0c;读者可以借助我的文章和网上的课程结…