【lib.dll.a.so】Windows和Linux两个系统下的库文件

1.静态库&&动态库

Windows平台下:静态库后缀为.lib,动态库后缀为.dll

Linux平台下:静态库格式为lib**.a,动态库格式为lib**.so

谈论两者区别之前,需要对程序编译和运行有一个大致认识:

代码想要输出结果,需要经过代码编译和可执行程序运行,就是编译和运行(链接)这两步。

两种类型的库在其中起着不同的作用,这也就是为什么有时候代码编译通过,但是无法运行(eg:缺失dll)

静态库和动态库的区别:

静态库在编译过程中就已经引用并链接到了,有问题编译这一步就会报错;动态库在编译过程中只是起到一个简单的引用,可以理解为单纯检查有没有引用,但是在可执行程序运行的过程中会进行链接。

编译:以一个函数为例,编译这个过程只检查这个函数声明与否,并不检查函数是否实现

2.Windows 11平台

编译器用的是VScode,编译套件用的是MSVC(一开始用的是mingw,但是生成的库怎么给我默认搞成Linux下的lib.a了,后来改成MSVC)

vscode下可以安装一个插件Output Colorizer,这个可以给output添加一些颜色,方便查看

就用很简单的代码结构来试验,

Ctrl+shift+p:打开cmake configure,下面会出现选择编译器和生成调试按钮

(1)直接用cpp

main.cpp

cpp 复制代码
#include "../header/add.h"

int main()
{
    int result = 0;
    int a = 1, b = 2;
    result = add(a, b);
    cout << result << endl;
}

add.cpp

cpp 复制代码
int add(int a, int b)
{
    return a + b;
}

add.h,头文件就是负责声明的

cpp 复制代码
#include <iostream>
using namespace std;

int add(int a, int b);

CMakelists.txt:

bash 复制代码
cmake_minimum_required(VERSION 3.5)

project(Cmake_test)

add_executable(main src/main.cpp src/add.cpp)

没有用到任何库文件,只是将两个cpp文件生成了一个main.exe可执行程序

思考一个问题:c++为什么要用头文件?

当然可以不写头文件,只在main.cpp中声明一下int add()就好,但是不符合规范,使用头文件能减少重复

这个add.h头文件中就只有一个add函数声明,无法体现。假设需要100个函数,如果还不用头文件就需要在所有需要用到某个函数的cpp文件中声明,工作量极大,如果这时还要修改某个函数的实现...更是离谱

头文件只是起到一个预编译的作用,在编译之前把各个函数的声明放到include头文件的cpp中

但是 main.cpp中头文件这样表示很难看,太具体反而更换头文件路径后还要更改,这样一来又违背了我们说的减少重复原则。

所以,在Cmake中有一条命令*:include_directories*,这条命令是指定一个头文件的路径(是包含头文件的路径不是指定具体头文件!),让工程中需要的头文件在这个路径下找。

CMakelists:

bash 复制代码
cmake_minimum_required(VERSION 3.5)

project(Cmake_test)

include_directories(header)

add_executable(main src/main.cpp src/add.cpp)

main.cpp:

cpp 复制代码
#include "add.h"

int main()
{
    int result = 0;
    int a = 1, b = 2;
    result = add(a, b);
    cout << result << endl;
}

逐渐向我们看到正常的工程项目写法接近了,一般没有将头文件那样写的,因为如果要用第三方库,路径是很长的...

(2)静态库

在CmakeLists中加入:

bash 复制代码
add_library(static_add src/add.cpp)

点击生成ALL_BUILD,记得编译套件要不要用Windows下默认的mingw,在build/Debug中可以看到:

这下add.cpp这个函数文件就背封装到static_add.lib这个库文件中了。

将编译好的库单独拿出来保存到lib中:

这样的话CMakelists:

bash 复制代码
cmake_minimum_required(VERSION 3.5)

project(Cmake_test)

include_directories(header)

link_directories(./lib)

add_executable(main src/main.cpp)

target_link_libraries(main static_add)

这就是静态库的编译和调用,没那么多花里胡哨的东西,至于像OpenCV开源库里会提供debug和release两个版本的lib,根据情况自行调用即可。

(3)动态库(共享库)

在CmakeLists中加入:

bash 复制代码
add_library(shared_add SHARED src/add.cpp)

比静态库lib的编译中间多了一个SHARED标识,代表前面的shared_add是一个动态库文件

跟刚才一样,将dll文件拿出来放到lib文件夹下,然后仿照lib的调用方法,书写CMakelists

bash 复制代码
cmake_minimum_required(VERSION 3.5)

project(Cmake_test)

include_directories(header)

link_directories(./lib)

add_executable(main src/main.cpp)

target_link_libraries(main shared_add)

报错:

刚才说编译过程中链接的是lib文件,所以不能用dll文件来链接。但是编译动态库的过程中也没提供shared_add.lib啊

原因:

Windows 下,并且用MSVC 套件来做编译,需要在add.cpp这种函数前加一个符号,来告诉Cmake这个是要编译动态库的函数,需要提供dll和lib:

add.cpp中:

cpp 复制代码
__declspec(dllexport) int add(int a, int b)
{
    return a + b;
}

然后再跟一开始一样:

bash 复制代码
add_library(shared_add SHARED src/add.cpp)

这样会发现,在Debug目录中出现了shared_add.dll和shared_add.lib:

拿出来放到lib目录中,这样就可以用shared_add.lib做链接了!

编译,通过!

还有一个小问题,之前在编译qt的时候,导出的exe双击运行总是提示缺少各种dll。其实就是在exe这个 路径下没有dll这个动态库,因为程序在运行的时候才链接dll库,所以可以编译通过。这时候缺啥就把啥放到exe这个目录下酒没问题了!

如上面编译好的exe,因为我将dll单独拿了出来并且注释掉了add_libraries,所以生成的exe目录下并没有dll库文件,

所以再将其放回Debug目录中(之前是故意拿出来的_):

双击运行exe试一下,果然!

将dll放回,双击exe一闪而过,运行成功!

总结:

静态库就是正常编译,将生成的lib在编译过程中链接到即可,由于只有一个lib库一个编译过程,所以不分先后。

动态库有点特殊,加了标识符后,编译动态库既会生成dll,还会伴随生成一个lib(dll中一些编译必要的东西)。后续编译exe过程中是需要先链接lib,然后在运行的时候与exe同级目录下不能缺dll(或者加入环境变量)。

除此以外,Windows下MSVC编译还需要加个标识符 __declspec(dllexport) 来告诉Cmake这个是动态库需要的~,然后在头文件中的声明下要加__declspec(dllimport),这是规范写法,我上面没写。

具体视频29min处:【CMake第二讲】:静态库与动态库;使用OpenCV

相关推荐
小晶晶京京14 分钟前
day34-LNMP详解
linux·运维·服务器
画个太阳作晴天15 分钟前
A12预装app
linux·服务器·前端
fengyehongWorld1 小时前
Linux crontab定时任务
linux·运维
shuangrenlong1 小时前
ubuntu更新chrome版本
linux·chrome·ubuntu
碎像1 小时前
Linux上配置环境变量
linux·运维·服务器
cpsvps2 小时前
美国服务器环境下Windows容器工作负载基于指标的自动扩缩
windows
敲上瘾2 小时前
Linux系统cgroups资源精细化控制基础
linux·测试工具·docker·压力测试·cgroups
起个昵称吧3 小时前
线程相关编程、线程间通信、互斥锁
linux·算法
sunflower_w3 小时前
linux I2C核心、总线与设备驱动
linux·运维·服务器
Ronin3054 小时前
【Linux系统】进程间通信:System V IPC——共享内存
linux·服务器·system v 共享内存