当前位置: 首页 > ds >正文

如何优雅的使用CMake中的FindPkgConfig模块

背景

如果你遇到下面的场景,那么FindPkgConfig模块可以用来解决我们引用上游库的问题。

  • 上游库没有提供CMake的配置文件。
  • CMake没有提供相应的查找模块,即Find<PackageName>.cmake的文件。
  • 上游库提供了pkg-config使用的.pc文件。

如果上面三个条件都不满足,不用担心,可以参考《Linux中使用CMake导入第三方开发库》导入上游库。

FindPkgConfig模块介绍

FindPkgConfig模块提供了pkg_get_variable(), pkg_check_modules()pkg_search_module()三个命令。普通用户还是接触后两个命令最多。

pkg_check_modules()pkg_search_module()的签名一样。不同之处在于pkg_check_modules()要求每个<moduleSpec>都满足要求,才认为命令执行成功,而pkg_search_module()要求只要有一个<moduleSpec>满足要求,命令就算执行成功。

pkg_check_modules(<prefix>[REQUIRED] [QUIET][NO_CMAKE_PATH][NO_CMAKE_ENVIRONMENT_PATH][IMPORTED_TARGET [GLOBAL]]<moduleSpec> [<moduleSpec>...])pkg_search_module(<prefix>[REQUIRED] [QUIET][NO_CMAKE_PATH][NO_CMAKE_ENVIRONMENT_PATH][IMPORTED_TARGET [GLOBAL]]<moduleSpec> [<moduleSpec>...])

举一个实际例子,说明pkg_check_modules()pkg_search_module()之间的差异。

include(FindPkgConfig)
pkg_check_modules(CHECK_DEPS REQUIRED gtk+-3.0 glib-2.0)# 必须gtk+-3.0和glib-2.0都存在,CHECK_DEPS_FOUND的值才为TRUE
if(CHECK_DEPS_FOUND)message(STATUS "找到 GTK3 和 Glib2")
else()message(WARNING "未找到依赖库!")
endif()# 只要gtk+-3.0或glib-2.0存在,SEARCH_DEPS_FOUND的值为TRUE
pkg_search_modules(SEARCH_DEPS REQUIRED gtk+-3.0 glib-2.0)if(SEARCH_DEPS_FOUND)message(STATUS "找到 GTK3 或 Glib2")
else()message(WARNING "未找到依赖库!")
endif()

如果需要检测的<moduleSpec>只有一个,那这两个命令的实际使用效果是一样的。

基本用法

pkg_check_modules()为例,大部分的用法如下所示。借助该模块提供的变量<XXX>_LIBRARY_DIRS<XXX>_LIBRARIES<XXX>_INCLUDE_DIRS,在项目中使用上游库。

cmake_minimum_required(VERSION 3.10)
project(MyGTKApp)include(FindPkgConfig)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0>=3.18)add_executable(my_app main.c)
# 包含头文件路径
target_include_directories(my_app PRIVATE ${GTK3_INCLUDE_DIRS})
# 链接库路径和库文件
target_link_directories(my_app PRIVATE ${GTK3_LIBRARY_DIRS})
target_link_libraries(my_app PRIVATE ${GTK3_LIBRARIES})

进阶用法

其实,pkg_check_modules()提供了符合CMake风格的用法,使用IMPORTED_TARGET参数将上游库以PkgConfig::<prefix>的名称,作为一个导入目标(imported target),直接使用target_link_libraries()命令链接PkgConfig::<prefix>即可。可以与上面的基本用法对比,写法更加简洁、专业。
如果我们需要这个导入的上游库在整个项目中可见(可用),可以在IMPORTED_TARGET后追加一个参数GLOBAL

cmake_minimum_required(VERSION 3.13)
project(MyGTKApp)include(FindPkgConfig)
pkg_check_modules(GTK3 REQUIRED IMPORTED_TARGET [GLOBAL] gtk+-3.0>=3.18)add_executable(my_app main.c)
target_link_libraries(my_app PRIVATE PkgConfig::GTK3)

IMPORTED_TARGET的内部实现

查看/usr/share/cmake-3.22/Modules/FindPkgConfig.cmake这个文件的_pkg_create_imp_target函数,我们可以看到使用IMPORTED_TARGET时,CMake到底做了什么。源码一看,原来也是简单命令的组合,只是CMake帮我们写了很多。

# create an imported target from all the information returned by pkg-config
function(_pkg_create_imp_target _prefix _imp_target_global)if (NOT TARGET PkgConfig::${_prefix})if(${_imp_target_global})set(_global_opt "GLOBAL")else()unset(_global_opt)endif()add_library(PkgConfig::${_prefix} INTERFACE IMPORTED ${_global_opt})if(${_prefix}_INCLUDE_DIRS)set_property(TARGET PkgConfig::${_prefix} PROPERTYINTERFACE_INCLUDE_DIRECTORIES "${${_prefix}_INCLUDE_DIRS}")endif()if(${_prefix}_LINK_LIBRARIES)set_property(TARGET PkgConfig::${_prefix} PROPERTYINTERFACE_LINK_LIBRARIES "${${_prefix}_LINK_LIBRARIES}")endif()if(${_prefix}_LDFLAGS_OTHER)set_property(TARGET PkgConfig::${_prefix} PROPERTYINTERFACE_LINK_OPTIONS "${${_prefix}_LDFLAGS_OTHER}")endif()if(${_prefix}_CFLAGS_OTHER)set_property(TARGET PkgConfig::${_prefix} PROPERTYINTERFACE_COMPILE_OPTIONS "${${_prefix}_CFLAGS_OTHER}")endif()endif()
endfunction()

参考资料

https://cmake.org/cmake/help/latest/module/FindPkgConfig.html

最后

分享CMake使用中的小技巧。如果文章对您有帮助,不妨关注、收藏和转发,感谢。

http://www.xdnf.cn/news/5862.html

相关文章:

  • 验证回文串1
  • Linux sysvinit 系统启动
  • 【三】 空域滤波的基础与空域中的低通滤波器(2)【830数字图像处理】
  • 解构赋值
  • RuoYi 中使用 PageUtils.startPage() 实现分页查询的完整解析
  • 数字ic后端设计从入门到精通4(含fusion compiler, tcl教学)CMOS VLSI Design
  • Baumer工业相机堡盟工业相机的工业视觉是否可以在室外可以做视觉检测项目
  • 【系统架构师】2025论文《基于架构的软件设计方法》【最新】
  • telnetlib源码深入解析
  • Java面试终极篇:Sentinel+Seata+Kafka Streams高并发架构实战
  • Adobe Acrobat pro在一份PDF中插入空白页
  • 【基于ALS模型的教育视频推荐系统(Java实现)】
  • java反序列化commons-collections链6
  • 邮件营销应对高退信率的策略
  • 一键解锁嵌入式UI开发——LVGL的“万能配方”
  • AI驱动网络范式革新:Smart Switch与智能路由的协同进化
  • 《飞飞重逢》手游:暴力治疗与团队赋能的战场艺术!
  • feign.RequestInterceptor 简介-笔记
  • 深入浅出:Java 中的动态类加载与编译技术
  • 2025.5.12 APIO 模拟赛总结
  • 小结: Port Security,DHCP Snooping,IPSG,DAI,
  • python opencv 将不同shape尺寸的图片制作video视频
  • 法国蒙彼利埃大学团队:运用元动力学模拟与马尔可夫状态模型解锁 G 蛋白偶联受体构象动态机制
  • Linux 服务器用 SSH 拉取多个 Git 工程
  • LeRobot 项目部署运行逻辑(七)—— ACT 在 Mobile ALOHA 训练与部署
  • 开发工具分享: Web前端编码常用的在线编译器
  • Matlab 基于滑模自抗扰的高速列车自动驾驶算法研究
  • Linux 软硬连接详解
  • linux下minio的进程管理脚本
  • LMFD格子多相流体力学仿真机:超级计算如何实现平民化?