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

本文详细讲解了CMake中静态库和动态库的区别,涉及Windows和Linux平台的编译后缀,以及如何在VSCode中配置和使用。还介绍了头文件的作用和OpenCV库的find_package使用方法。
摘要由CSDN通过智能技术生成

0.说明

b站合集:【新坑预警】相信我,我真的可以把CMake讲清楚

视频笔记,防止遗忘~

1.静态库&&动态库

Windows平台下有两种情况:
用MinGW来编译,静态库后缀为.dll.a,动态库后缀为.dll
用MSVC来编译,静态库后缀为.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

#include "../header/add.h"

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

add.cpp

int add(int a, int b)
{
    return a + b;
}

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

#include <iostream>
using namespace std;

int add(int a, int b);

CMakelists.txt:

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:

cmake_minimum_required(VERSION 3.5)

project(Cmake_test)

include_directories(header)

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

main.cpp:

#include "add.h"

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

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

(2)静态库

在CmakeLists中加入:

add_library(static_add src/add.cpp)

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

在这里插入图片描述
这下add.cpp这个函数文件就背封装到static_add.lib这个库文件中了。

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

在这里插入图片描述

这样的话CMakelists:

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中加入:

add_library(shared_add SHARED src/add.cpp)

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

在这里插入图片描述
跟刚才一样,将dll文件拿出来放到lib文件夹下,然后仿照lib的调用方法,书写CMakelists

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中:

__declspec(dllexport) int add(int a, int b)
{
    return a + b;
}

然后再跟一开始一样:

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一闪而过,运行成功!

Windows下exe运行动态库的加载顺序:当前目录->System32目录->Windows目录->指定的PATH环境变量

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

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

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

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

3.文件编译、链接分析

基本的文件结构,以上面的举例:main.cpp、add.cpp和add.h

先在main文件中用预处理器展开,包括头文件展开、宏替换、去掉注释等。

在makefile中写好g++的步骤后,对CmakeLists.txt进行cmake,会得到makefile文件,这时候再进行make编译:

在这里插入图片描述

借鉴视频:【CMake第四讲】:再探静态库与动态库(Linux)

g++和linux下后缀指令:https://getiot.tech/zh/linux-command/gcc#google_vignette

在这里插入图片描述

这里的.o文件可以转为库文件,在连接的时间就是main.o链接libadd_static.lib。

4.Ubuntu18.04平台

编译过程比较简单,没有上面特殊注意的地方,对于动态、静态库的编译和链接没什么特殊的地方。

注意的一个地方:
在Linux中动态库的加载顺序:环境变量->/usr/lib/下

5.find_package:事先加入path

如果没有这个命令,我们就要手动找到库目录地址,并且每一个执行命令都要链接一大堆东西,并且如果库地址更换了位置就要每个都要更改,否则会连接不到,还是保持一开始的减少重复的目的。

当这个库所在的***Config.cmake已经被包含在系统环境中时,find_package这条命令就会去找头文件和库的位置,找到之后像返回值一样将两个变量返回到 O p e n C V I N C L U D E D I R S 和 {OpenCV_INCLUDE_DIRS}和 OpenCVINCLUDEDIRS{OpenCV_LIBS}当中。

在Ubuntu18.04+OpenCV3.2.0下,OpenCVConfig.cmake已经写入环境变量中,截取部分命令:

find_package(OpenCV REQUIRED)
message("--------${OpenCV_INCLUDE_DIRS}---------")
message("--------${OpenCV_LIBS}---------")

打印output:

[cmake] --------/usr/include;/usr/include/opencv---------
[cmake]--------opencv_calib3d;opencv_core;opencv_features2d;opencv_flann;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_shape;opencv_stitching;opencv_superres;opencv_video;opencv_videoio;opencv_videostab;opencv_viz;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dpm;opencv_face;opencv_freetype;opencv_fuzzy;opencv_hdf;opencv_line_descriptor;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_reg;opencv_rgbd;opencv_saliency;opencv_stereo;opencv_structured_light;opencv_surface_matching;opencv_text;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto---------

在Windows11下,也是如此。

但是要提前把OpenCVConfig.cmake放入环境变量,

find_package(OpenCV REQUIRED)
message("---${OpenCV_INCLUDE_DIRS}---")
message("---${OpenCV_LIBS}---")

打印output:

[cmake] -- Found OpenCV: D:/Tools/opencv4.5.1/mingw_build/install (found version "4.5.1") 
[cmake] ---D:/Tools/opencv4.5.1/mingw_build/install/include---
[cmake] ---opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_world---

当然如果换成MSVC编译的:

[cmake] -- Found OpenCV: D:/Tools/opencv4.5.1/msvc_build/install (found version "4.5.1") 
[cmake] -- Configuring done (3.5s)
[cmake] ---D:/Tools/opencv4.5.1/msvc_build/install/include---
[cmake] ---opencv_calib3d;opencv_core;opencv_dnn;opencv_features2d;opencv_flann;opencv_gapi;opencv_highgui;opencv_imgcodecs;opencv_imgproc;opencv_ml;opencv_objdetect;opencv_photo;opencv_stitching;opencv_video;opencv_videoio;opencv_aruco;opencv_bgsegm;opencv_bioinspired;opencv_ccalib;opencv_datasets;opencv_dnn_objdetect;opencv_dnn_superres;opencv_dpm;opencv_face;opencv_fuzzy;opencv_hfs;opencv_img_hash;opencv_intensity_transform;opencv_line_descriptor;opencv_mcc;opencv_optflow;opencv_phase_unwrapping;opencv_plot;opencv_quality;opencv_rapid;opencv_reg;opencv_rgbd;opencv_saliency;opencv_shape;opencv_stereo;opencv_structured_light;opencv_superres;opencv_surface_matching;opencv_text;opencv_tracking;opencv_videostab;opencv_xfeatures2d;opencv_ximgproc;opencv_xobjdetect;opencv_xphoto---

注意这里的mingw编译的静态库,后缀名为.dll.a,这是mingw在Windows系统下的生成的;

如果用MSVC套件来编译,则后缀名为.lib。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值