CMake教程(二)- 添加静态库文件和动态库文件

什么是库文件

一般来说,一个程序,通常都会包含目标文件和若干个库文件。经过汇编得到的目标文件再经过和库文件的链接,就能构成可执行文件。库文件像是一个代码仓库或代码组件的集合,为目标文件提供可直接使用的变量、函数、类等。

库文件包含了静态链接库动态链接库两种。两者最根本的区别在与在程序编译的过程中,如何处理库文件和目标文件的链接关系。
在这里插入图片描述

静态链接库

静态链接库在Linux系统中以.a文件的形式存在。

在上图程序编译的链接阶段静态库会完全复制到可执行文件中,一旦可执行文件构建完成,就不再需要静态库的存在,可执行文件在后续的使用中,也不再依赖这个静态库。

动态链接库

虽然静态库非常容易理解且不会引入依赖问题,但是试想一下,如果你在统筹构建一个无比庞大的工程,这时,其中一个开发者升级了他所开发的库。这时,你就需要花费很长的时间来重新构建这个如此庞大的工程。这时,你就可以使用动态库来避免这个问题。

动态库在程序编译的链接阶段,仅将一些重要的信息,如重定位和符号表信息复制到可执行文件中,可执行文件在后面执行的过程中,如果需要引用这个库文件,就会根据这些信息从系统中寻找对应的库文件以实现对应的功能。

静态库和动态库的区别

区别静态库动态库
可执行文件大小较大
(因为动态库的内容会被完全复制到可执行文件中)
较小
占用磁盘大小较大
(如果有多个可执行文件都用到同一个静态库,这个静态库会被多次复制到不同的可执行文件中)
较小
(即使多个可执行文件都需要用到同一个动态库,他们也只是共用同一个动态库文件)
拓展性与兼容性全量更新
(库文件的更新会引起整个可执行文件的重新编译及发布)
增量更新
(不需要重新编译可执行文件,只需发布动态库文件)
依赖问题无依赖问题
(已构建的可执行文件不依赖其他静态库文件)
有依赖问题
(可执行文件的执行需要系统存在依赖的动态库文件)
复杂程度简单复杂
(会引起很多问题,例如如何在运行时确定地址,库文件版本管理等)
加载速度

如何在CMake中添加库文件

下面是一个C++工程,包含了一个主程序文件和两个准备用于生成库文件的源文件。
在这里插入图片描述
这里有一个简单的主程序,其中调用了两个来自库文件的函数:print_char()print_int(),其中print_char()来自静态库文件,print_int()来自动态库文件。

#include <iostream>
#include "printer_char.hpp"
#include "printer_int.hpp"

using namespace std;

int main(int argc, char* argv)
{
    // 静态库 + 动态库
    print_char('A');        // print_char() 来自静态库
    print_int(5);           // print_int() 来自动态库
    return 0;
}

使用CMake来构建MakeFile,并将指定的源文件制作为静态库和动态库。

cmake_minimum_required(VERSION 3.10)

# 设置项目名
project(CMakeTutorial VERSION 1.2)

# 添加头文件搜索路径
include_directories(
${PROJECT_SOURCE_DIR}/inc
)

# 生成库
add_library(PrinterChar STATIC src/printer_char.cpp)    # 静态库
add_library(PrinterInt SHARED src/printer_int.cpp)      # 动态库

# 添加需要构建的可执行文件
#------方法对比 1.1 - 不用库的写法
# add_executable(LinkLibraryDemo link_library_demo.cpp src/printer_char.cpp src/printer_int.cpp)
#------方法对比 1.2 - 用库的写法
add_executable(LinkLibraryDemo demo/link_library_demo.cpp)
target_link_libraries(LinkLibraryDemo PRIVATE PrinterChar)   # 为目标添加静态库
target_link_libraries(LinkLibraryDemo PRIVATE PrinterInt)    # 为目标添加动态库

然后执行下面的命令来生成库文件和可执行文件

本人习惯在工程的根目录下创建一个cmake目录用于构建工程,以避免污染根目录。是在cmake目录下执行的cmake指令,所以指定的CMakeLists.txt文件是在当前目录的上一级目录。请根据你的工程目录结构选择正确的cmake指令的目录。

cmake ..
make

在这里插入图片描述
可见编译生成了两个库文件,静态库libPrinterChar.a和动态库libPrinterInt.so。此时可执行文件能够成功运行。

尝试一下删除静态库libPrinterChar.a,并再次运行程序,发现程序依然能成功运行。这说明可执行文件的运行并不依赖静态库文件存在。
在这里插入图片描述
再尝试把动态库文件删掉,再运行可执行文件,运行失败,提示找不到对应的.so动态库文件。说明可执行文件的运行依赖对应的动态库文件的存在。
在这里插入图片描述

CMake 中 target_link_libraries 的 PRIVATE,PUBLIC 和 INTERFACE 的区别

情况使用参数
只有源文件(.cpp)中包含了库文件PRIVATE
只有头文件(.hpp)中包含了库文件INTERFACE
源文件和头文件都包含了库文件PUBLIC

关于这个问题可以参考这里

  • 18
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值