CMake 踩坑之依赖其他静态库生成动态库

3,155 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第23天,点击查看活动详情

在研究了 CMake 一系列用法之后,一些简单的工程都可以用 CMake 构建了,但是对于一些复杂的工程,比如我公司的代码,我搞了很久,都有问题,希望这可以成为一点点经验帮助大家在以后的CMake构建之路少走弯路。

言归正传,问题出在哪呢?就是我的工程中的一个模块生成的动态库需要依赖其他模块生成的静态库!或者依赖一些已有的静态库。所以组织大型C++程序,模块之间的依赖关系也是十分重要的!!!

下面我们先看一些编译链接的基础知识。

一、编译链接相关基础

1.1 编译过程

graph LR
A[".h .cppy源文件"] --> B["预编译"]-->C["编译"]-->D["汇编"]-->E["链接"]-->G["可执行文件"]
F["静态库.a/.lib 动态库.so/.dll"]-->E["链接"]

1.2 链接

链接的作用就就是将我们编译出来的目标文件(target)和我们代码所用到的库文件一起打包成一个可执行文件的过程。

这里链接的方式有两种,一种是静态链接,一种是动态链接。因此静态库和动态库区别就来自于采用了何种处理的库的方式。

所以所谓静态、动态是指链接。

1.3 静态库VS动态库

在 cmake 中,我们使用 add_library 结合 SHARED 生成动态链接库;结合 STATIC 生成静态链接库。

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。add_library 使用 SHARED 生成动态链接库;使用STATIC 生成静态链接库。

静态库动态库
后缀不同:Linux.a.so
后缀不同:windows.lib.dll
载入时间不同静态库的代码在编译的过程中已经载入到可执行文件中,所以最后生成的可执行文件相对较大动态库的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,所以最后生成的可执行文件相对较小
生成可执行文件大小较大较小
链接的不同静态库链接的时候把库直接加载到程序中动态库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度和降低程序的耦合度
编译运行不同静态库在程序编译时被连接到目标代码(target)中,程序运行时将不再需要该静态库动态库在程序编译时并不会被链接到目标代码(target)中,而是在程序运行时才被载入,因此在程序运行时还需要动态库的存在

二、CMake中的相关用法

2.1 CMake 生成静态库/动态库

在 cmake 中,我们使用 add_library 结合 SHARED 生成动态链接库;结合 STATIC 生成静态链接库。

比如,这里生成一个名为 testDll 的动态库,采用 ${DIR_TESTDLL_SRCS} 路径下的源码。

add_library(testDll SHARED ${DIR_TESTDLL_SRCS})

2.2 CMake 添加动态库依赖

由于生成上面的 testDll 需要依赖其他模块生成的静态库, 比如这里其他模块生成的名为 lib_hello 的静态库;同时还依赖系统工程目录下 library 文件夹下的 libssl.lib 和libcrypto.lib(目前先只考虑 Windows 系统下的编译)

add_library(lib_hello STATIC ${DIR_LIBHELLO_SRCS})

那么我们该如何添加这些依赖呢?