Cmake中寻库文件的路径

在cmake的世界中,进行查找库文件的方式一般就有三种

find_package(cmake原生支持)

很多著名的库在进行安装的时候都会进行带一个 库名config.cmake 的文件,通过这个 config.cmake文件 cmake就能够进行找到这个库文件以及相关依赖的路径。

使用 find_package 进行使用第三方库的一般步骤(三部曲)

bash 复制代码
find /usr -name "*Config.cmake" | grep -i dbus

1. 寻找库

复制代码
find_package(库的名字 REQURIED)

如果是通过 apt - get install 进行安装的库,该库的config.cmake文件一般存在的路径是:/usr/lib/架构/cmake/库名/

实质作用:

确认库是否被安装,如果库没有被安装 并且设置了REQURIED这个字段则会编译报错,防止后续的无效编译。

如果查找到库已安装,cmake会进行解析这个cmake文件,并在内存中进行创建变量,最重要的两个变量就是

  • ${库名_INCLUDE_DIRS}:记录头文件在哪
  • ${库名_LIBRARIES}:记录库文件在哪

2. 关联头文件

复制代码
target_include_directories(程序名 PRIVATE ${库名字_INCLUDE_DIRS})

他会把**{库名_INCLUDE_DIRS}** 转化成gcc -I 后的参数,编译器默认去/usr/include/路径下进行查找代码中包含的头文件,如果没有找到则去**{库名_INCLUDE_DIRS}**的路径进行查找。

这里使用 PRIVATE 是因为只有这个程序本身需要这个头文件,如果后续有人进行链接了该程序,他们不需要去自动获取这个程序的头文件。

3. 链接库文件

复制代码
target_link_libraries(程序名 PRIVATE ${库名称_LIBRARIES})

在编译的最后一步,它会将 ${库名称_LIBRARIES} 进行指向的 .so 动态库进行传给链接器

PkgConfig(Linux标准方式)

使用PkgConfig 是cmake非原生使用第三方库的工具,但是这个工具是Linux下非常古老但是健壮性和稳定性非常好的工具。

和find_package一样在使用apt-get install 进行安装开发版本的库文件时,会在 /usr/lib/架构/pkgconfig/库名称 有一个.pc 后缀的文件。

使用PkgConfig 进行使用第三方库的四部曲

1. 查找系统是否安装了PkgConfig这个工具

bash 复制代码
find_package(PkgConfig REQUIRED)

cmake本身是读不懂 .pc 为后缀的文件的,需要进行使用外援工具PkgConfig 来及逆行读取

2. 寻找库

bash 复制代码
pkg_check_modules(自定义变量名 REQUIRED 库名)

这里的库名可以使用

bash 复制代码
sudo find /usr -name "*.pc" | grep -i 库名
/usr/lib/x86_64-linux-gnu/pkgconfig/实际的库名

这个命令来进行查看

例如:

寻找库 pkg_check_modules 的第一个参数 自定义变量名 是将进行查找库的相关信息都进行存到 自定义变量名_ 为前缀的变量中,以dbus库举个例子:

pkg_check_modules(DBUS REQUIRED dbus-1)

PkgConfig 进行查找到的dbus库的头文件的路径会进行存放到 DBUS_INCLUDE_DIRS 变量中, 库文件路径会进行存放到 DBUS_LIBRARIES 中

3. 关联头文件

bash 复制代码
target_include_directories(程序名 PRIVATE ${库名称_INCLUDE_DIRS})

4. 链接库文件

bash 复制代码
target_link_libraries(程序名 PRIVATE ${库名称_LIBRARIES})

find_path/find_libraries(手动地毯式搜索)

1. 寻找头文件

bash 复制代码
find_path(库名称_INCLUD_DIRS NAMES 库名称.h PATHS 指定路径)

告诉编译器去指定路径去找一个名字为 库名称.h 的头文件,如果找到就将路径进行放到 库名称_INCLUDE_DIRS 这个变量中。

这里存到变量中的是文件夹,并不是文件本身

2. 寻找库文件

bash 复制代码
find_library(库名称_LIBRARIES NAMES 二进制库名称 PATHS 指定路径)

告诉编译器去指定路径下去找一个名字为 二进制库名称的 二进制库文件,如果找到就将路径进行放到 库名称_LIBRARIES 这个变量中。

这里变量中是存的是文件的完整路径

3. 进行安全检查

bash 复制代码
if(NOT 库名称_INCLUDE_DIRS OR NOT 库名称_LIBRARUES)  ...  end if()

示例代码

假设你自己写了一个库叫 mymath,存放在 /opt/mymath 下:

复制代码
# 1. 尝试找头文件
# 如果找到了,MYMATH_INCLUDE_DIR 就会变成 "/opt/mymath/include"
find_path(MYMATH_INCLUDE_DIR 
    NAMES mymath.h 
    PATHS /opt/mymath/include
)

# 2. 尝试找库文件
# 如果找到了,MYMATH_LIBRARY 就会变成 "/opt/mymath/lib/libmymath.so"
find_library(MYMATH_LIBRARY 
    NAMES mymath 
    PATHS /opt/mymath/lib
)

# 3. 安全检查(核心步骤)
# NOT 后面跟着变量名,意思是"如果没有找到..."
if(NOT MYMATH_INCLUDE_DIR)
    message(FATAL_ERROR "错误:找不到 mymath.h!请检查 /opt/mymath/include 路径。")
endif()

if(NOT MYMATH_LIBRARY)
    message(FATAL_ERROR "错误:找不到 libmymath.so!请检查 /opt/mymath/lib 路径。")
endif()

# 4. 如果程序运行到这里,说明上面都找到了,可以放心使用
add_executable(my_app main.cpp)
target_include_directories(my_app PRIVATE ${MYMATH_INCLUDE_DIR})
target_link_libraries(my_app PRIVATE ${MYMATH_LIBRARY})

这里进行message进行输出的时候,还进行设置了 FATAL_ERROR 字段 ,这是message进行输出的最高级警告

  • 如果不加:camke找不到库时也会进行尝试配置,最后在链接时报出一堆让人看不懂的底层错误
  • 如果加了:cmake在编译时如果没有找到对应的文件就会直接报错,从而不在向下进行。

4. 链接头文件和库文件

bash 复制代码
target_include_directories(...)
target_link_libraries(...)

这里可能都会有一个疑问:既然前面那两种方式这么好用,那这个手动式地毯搜索还有什么作用呢??

这种方主要是应对自动化工具失灵或者环境受限的场景,例如:

1. 使用第三方提供的"离线"预编译库

这是最典型的场景。比如某个硬件厂商给你提供了一个 SDK,里面只有两个文件夹:includelib

  • 原因 :这类库通常不是通过 apt install 安装的,没有 .pc 文件,也没有 Config.cmake 脚本。

  • 做法 :你把这些文件夹拷贝到项目里的 3rdparty 目录下,然后用 find_pathfind_library 准确地把它们"挖"出来。

2. 交叉编译(嵌入式开发)

如果你在 PC 上编写代码,但目标运行环境是 ARM 开发板(如树莓派、高性能嵌入式芯片)。

  • 原因 :此时你不能让 CMake 去找你 PC 系统里的 /usr/lib(那是 X86 架构的库)。你需要指向你下载好的 交叉编译工具链(Toolchain) 里的库目录。

  • 做法:你会手动指定编译器去某个特定的 SDK 路径下寻找对应的头文件和二进制库。

3. 多版本库并存与切换

假设你的系统里安装了 OpenCV 4.0,但某个旧项目必须使用你手动下载并解压在 /home/ys/opencv-3.4 的旧版本。

  • 原因 :默认的 find_package 可能会优先找到系统全局的 4.0 版本。

  • 做法:为了"强行"指定版本,你会直接用手动模式精准定位到那个特定路径,确保编译器不会找错人。

4. 内部自研库(非子目录模式)

有时候你的公司内部有多个独立的仓库,库 A 已经编译好了变成了 .so 文件放在服务器上,你不想把库 A 的源代码通过 add_subdirectory 塞进你的项目里。

  • 原因:为了保持项目整洁,你只引用库 A 的成品。

  • 做法:通过手动模式,指定库 A 的二进制路径进行链接。

5. 高度定制或极端精简的系统

在某些金融、军事或极简的生产环境服务器上,可能连 pkg-config 工具都没有安装。

  • 原因:环境极其封闭,自动化探测工具全部失效。

  • 做法:这是"最后的一道防线"。只要文件在硬盘上,你就能通过手动模式把它找出来并完成编译。

相关推荐
txinyu的博客1 小时前
解析muduo源码之 Buffer.h & Buffer.cc
c++
代码AI弗森1 小时前
Git Bash 与 PowerShell:定位差异、使用场景与选择建议
开发语言·git·bash
阿猿收手吧!1 小时前
【C++】异常处理:catch块执行后程序如何继续
服务器·网络·c++
代码游侠1 小时前
C语言核心概念复习(一)
c语言·开发语言·c++·笔记·学习
Once_day1 小时前
C++之《Effective C++》读书总结(3)
c语言·c++
蜕变的土豆1 小时前
grpc-通关速成
开发语言·c++
-To be number.wan1 小时前
Python数据分析:英国电商销售数据实战
开发语言·python·数据分析
xb11322 小时前
C#生产者-消费者模式
开发语言·c#
电商API&Tina2 小时前
乐天平台 (Rakuten) 数据采集指南
大数据·开发语言·数据库·oracle·json
今儿敲了吗2 小时前
10| 扫雷
c++·笔记·学习