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

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)

五、如何选择?

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

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


六、总结

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

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

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

相关文章:

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

环境 windows visual studio 2019 visual studio 2019创建cmake工程 1. 静态库.lib 1.1 静态库编译生成 以下是我创建的cmake工程文件结构&#xff0c;只关注高亮文件夹部分 libout 存放编译生成的.lib文件libsrc 存放编译用的源代码和头文件CMakeLists.txt 此次编译CMak…...

Chrome 浏览器 支持多账号登录和管理的浏览器容器解决方案

根据搜索结果&#xff0c;目前没有直接提到名为“chrometable”的浏览器容器或插件。不过&#xff0c;从功能描述来看&#xff0c;您可能需要的是一个能够支持多账号登录和管理的浏览器容器解决方案。以下是一些可能的实现方式&#xff1a; 1. 使用 Docker 容器化部署 Chrome …...

GrassWebProxy

GrassWebProxy第一版&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; using System.IO; using Newtonsoft.Json;…...

DeepSeek API 调用 - Spring Boot 实现

DeepSeek API 调用 - Spring Boot 实现 1. 项目依赖 在 pom.xml 中添加以下依赖&#xff1a; <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId></depe…...

【DeepSeek】Deepseek辅组编程-通过卫星轨道计算终端距离、相对速度和多普勒频移

引言 笔者在前面的文章中&#xff0c;介绍了基于卫星轨道参数如何计算终端和卫星的距离&#xff0c;相对速度和多普勒频移。 【一文读懂】卫星轨道的轨道参数&#xff08;六根数&#xff09;和位置速度矢量转换及其在终端距离、相对速度和多普勒频移计算中的应用 Matlab程序 …...

【kafka实战】05 Kafka消费者消费消息过程源码剖析

1. 概述 Kafka消费者&#xff08;Consumer&#xff09;是Kafka系统中负责从Kafka集群中拉取消息的客户端组件。消费者消费消息的过程涉及多个步骤&#xff0c;包括消费者组的协调、分区分配、消息拉取、消息处理等。本文将深入剖析Kafka消费者消费消息的源码&#xff0c;并结合…...

[EAI-033] SFT 记忆,RL 泛化,LLM和VLM的消融研究

Paper Card 论文标题&#xff1a;SFT Memorizes, RL Generalizes: A Comparative Study of Foundation Model Post-training 论文作者&#xff1a;Tianzhe Chu, Yuexiang Zhai, Jihan Yang, Shengbang Tong, Saining Xie, Dale Schuurmans, Quoc V. Le, Sergey Levine, Yi Ma 论…...

算法与数据结构(字符串相乘)

题目 思路 这道题我们可以使用竖式乘法&#xff0c;从右往左遍历每个乘数&#xff0c;将其相乘&#xff0c;并且把乘完的数记录在nums数组中&#xff0c;然后再进行进位运算&#xff0c;将同一列的数进行相加&#xff0c;进位。 解题过程 首先求出两个数组的长度&#xff0c;…...

DeepSeek从入门到精通:全面掌握AI大模型的核心能力

文章目录 一、DeepSeek是什么&#xff1f;性能对齐OpenAI-o1正式版 二、Deepseek可以做什么&#xff1f;能力图谱文本生成自然语言理解与分析编程与代码相关常规绘图 三、如何使用DeepSeek&#xff1f;四、DeepSeek从入门到精通推理模型推理大模型非推理大模型 快思慢想&#x…...

【Pytorch函数】PyTorch随机数生成全解析 | torch.rand()家族函数使用指南

&#x1f31f; PyTorch随机数生成全解析 | torch.rand()家族函数使用指南 &#x1f31f; &#x1f4cc; 一、核心函数参数详解 PyTorch提供多种随机数生成函数&#xff08;注意&#xff1a;无直接torch.random()函数&#xff09;&#xff0c;以下是常用函数及参数&#xff1a;…...

vue print 打印

vue 点击打印页面部分内容&#xff0c;或者打印弹窗内的内容 打印页面部分内容 <template><div><div id"print"><div class"info"><div class"bx_title">费用报销单<span class"code">NO.<s…...

【异常解决】在idea中提示 hutool 提示 HttpResponse used withoud try-with-resources statement

博主介绍&#xff1a;✌全网粉丝22W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…...

【Uniapp-Vue3】UniCloud云数据库获取指定字段的数据

使用where方法可以获取指定的字段&#xff1a; let db uniCloud.database(); db.collection("数据表").where({字段名1:数据, 字段名2:数据}).get({getOne:true}) 如果我们不在get中添加{getOne:true}&#xff0c;在只获取到一个数据res.result.data将会是一个数组&…...

信息科技伦理与道德3-2:智能决策

2.2 智能推荐 推荐算法介绍 推荐系统&#xff1a;猜你喜欢 https://blog.csdn.net/search_129_hr/article/details/120468187 推荐系统–矩阵分解 https://blog.csdn.net/search_129_hr/article/details/121598087 案例一&#xff1a;YouTube推荐算法向儿童推荐不适宜视频 …...

openssl使用

openssl使用 提取密钥对 数字证书pfx包含公钥和私钥&#xff0c;而cer证书只包含公钥。提取需输入证书保护密码 openssl pkcs12 -in xxx.pfx -nocerts -nodes -out pare.key提取私钥 openssl rsa -in pare.key -out pri.key提取公钥 openssl rsa -in pare.key -pubout -ou…...

Visual Studio 2022 中使用 Google Test

要在 Visual Studio 2022 中使用 Google Test (gtest)&#xff0c;可以按照以下步骤进行&#xff1a; 安装 Google Test&#xff1a;确保你已经安装了 Google Test。如果没有安装&#xff0c;可以通过 Visual Studio Installer 安装。在安装程序中&#xff0c;找到并选择 Googl…...

SpringBoot3 + Jedis5 + Redis集群 如何通过scan方法分页获取所有keys

背景: 由于需要升级老项目代码&#xff0c;从SpringBoot1.5.x 升级到 SpringBoot3.3.x&#xff0c;框架中引用的Jedis自动升级到了 5.x&#xff1b;正好代码中有需要获取Redis集群的所有keys的需求存在&#xff1b;代码就不适用了&#xff0c;修改如下&#xff1a; POM 由于…...

WGCLOUD监控系统部署教程

官网地址&#xff1a;下载WGCLOUD安装包 - WGCLOUD官网 第一步、环境配置 #安装jdk 1、安装 EPEL 仓库&#xff1a; sudo yum install -y epel-release 2、安装 OpenJDK 11&#xff1a; sudo yum install java-11-openjdk-devel 3、如果成功&#xff0c;你可以通过运行 java …...

协议-WebRTC-HLS

是什么&#xff1f; WebRTC&#xff08;Web Real-Time Communication&#xff09; 实现 Web 浏览器和移动应用程序之间通过互联网直接进行实时通信。允许点对点音频、视频和数据共享&#xff0c;而无需任何插件或其他软件。WebRTC 广泛用于构建视频会议、语音通话、直播、在线游…...

jQuery UI 下载指南

jQuery UI 下载指南 引言 jQuery UI 是一个基于 jQuery 的用户界面和交互库&#xff0c;它提供了一套丰富的交互组件和视觉效果&#xff0c;可以帮助开发者快速构建美观、交互性强的网页应用。本文将为您详细介绍如何下载 jQuery UI&#xff0c;并指导您进行安装和使用。 jQ…...

MySQL系列之数据类型(String)

导览 前言一、字符串类型知多少 1. 类型说明2. 字符和字节的转换 二、字符串类型的异同 1. CHAR & VARCHAR2. BINARY & VARBINARY3. BLOB & TEXT4. ENUM & SET 结语精彩回放 前言 MySQL数据类型第三弹闪亮登场&#xff0c;欢迎关注O。 本篇博主开始谈谈MySQ…...

Kotlin 2.1.0 入门教程(十)if、when

if 表达式 if 是一个表达式&#xff0c;它会返回一个值。 不存在三元运算符&#xff08;condition ? then : else&#xff09;&#xff0c;因为 if 在这种场景下完全可以胜任。 var max aif (a < b) max bif (a > b) {max a } else {max b }max if (a > b) a…...

编程式路由

<script> export default {name: video-Info1,created () {setTimeout(() > {this.$router.push({ name: home })}, 3000)} } </script> 编程式路由&#xff1a;实现 不需要用户点击router-link&#xff0c;由代码实现路由跳转。 应用场景&#xff1a;用户登录…...

openAI官方prompt技巧(一)

1. 使用最新的模型 2. 将指令放在提示词的开头&#xff0c;并使用 ### 或 """ 来分隔指令和上下文&#xff0c;例如 错误示范❌ 将下面的文本总结为一个要点列表&#xff0c;列出最重要的内容。 Summarize the text below as a bullet point list of the most…...

利用 Python 爬虫获取按关键字搜索淘宝商品的完整指南

在电商数据分析和市场研究中&#xff0c;获取商品的详细信息是至关重要的一步。淘宝作为中国最大的电商平台之一&#xff0c;提供了丰富的商品数据。通过 Python 爬虫技术&#xff0c;我们可以高效地获取按关键字搜索的淘宝商品信息。本文将详细介绍如何利用 Python 爬虫技术获…...

LeetCode 0080.删除有序数组中的重复项 II:双指针 - C++/Java5 行版

【LetMeFly】80.删除有序数组中的重复项 II&#xff1a;双指针 - C/Java5 行版 力扣题目链接&#xff1a;https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/ 给你一个有序数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使得出现次数超…...

【C++高并发服务器WebServer】-15:poll、epoll详解及实现

本文目录 一、poll二、epoll2.1 相对poll和select的优点2.2 epoll的api2.3 epoll的demo实现2.5 epoll的工作模式 一、poll poll是对select的一个改进&#xff0c;我们先来看看select的缺点。 我们来看看poll的实现。 struct pollfd {int fd; /* 委托内核检测的文件描述符 */s…...

MapReduce是什么?

MapReduce 是一种编程模型&#xff0c;最初由 Google 提出&#xff0c;旨在处理大规模数据集。它是分布式计算的一个重要概念&#xff0c;通常用于处理海量数据并进行并行计算。MapReduce的基本思想是将计算任务分解为两个阶段&#xff1a;Map 阶段和 Reduce 阶段。 Map 阶段&a…...

git提交到GitHub问题汇总

1.main->master git默认主分支是maser&#xff0c;如果是按照这个分支名push&#xff0c;GitHub会出现两个branch&#xff0c;与预期不符 解决方案&#xff1a;更改原始主分支名为main git config --global init.defaultBranch main2.git&#xff1a;OpenSSL SSL_read: SS…...

CNN-GRU卷积神经网络门控循环单元多变量多步预测,光伏功率预测(Matlab完整源码和数据)

代码地址&#xff1a;CNN-GRU卷积神经网络门控循环单元多变量多步预测&#xff0c;光伏功率预测&#xff08;Matlab完整源码和数据) CNN-GRU卷积神经网络门控循环单元多变量多步预测&#xff0c;光伏功率预测 一、引言 1.1、研究背景和意义 随着全球能源危机和环境问题的日…...