此文为:轻松入门cmake系列教程
理论
是什么?
pkg_check_modules
是 CMake 自己的 pkg-config
模块的一个用来简化的封装:你不用再检查 CMake 的版本,加载合适的模块,检查是否被加载,等等,参数和传给 find_package 的一样:先是待返回变量的前缀,然后是包名(pkg-config 的)。这样就定义了<prefix>_INCLUDE_DIRS
和其他的这类变量,后续的用法就与find_package
一致。
工作原理
当安装某些库时(例如从RPM,deb或其他二进制包管理系统),会包括一个后缀名为 pc 的文件,它会放入某个文件夹下(依赖于系统设置,例如,Linux 为该库文件所在文件夹/lib/pkgconfig),并把该子文件夹加入pkg-config的环境变量PKG_CONFIG_PATH
作为搜索路径。
pkg_check_modules
实质上是检测系统中的 pkg-config
是否存在指定的 .pc 文件。
关于PKG_CONFIG_PATH
会在目录${PKG_CONFIG_PATH}
寻找.pc文件
在环境变量中设置
执行echo $PKG_CONFIG_PATH
echo $PKG_CONFIG_PATH
解决:
1、查看自己的 pkgconfig 路径在哪里
find / -name pkgconfig
可以看出有三个,随意选择一个就可以
2、设置路径
export PKG_CONFIG_PATH=/usr/lib64/pkgconfig/:$PKG_CONFIG_PATH
在cmakelists.txt中设置
set(ENV{PKG_CONFIG_PATH}
${CMAKE_SOURCE_DIR}/libs/lib/pkgconfig:/opt/ffmpeg/lib/pkgconfig:$ENV{PKG_CONFIG_PATH})
what is the difference between find_package and pkg_search_module
-
pkg_search_module使用pkg-config工具确定请求的库的位置。这在已经使用pkg-config的系统上最有用,因此您不需要为CMake复制所有信息。请注意,此方法存在潜在的可移植性问题,因为它要求在构建计算机上正确设置pkg-config。
-
另一方面,find_package是CMake自己解决相同问题的机制。为此,您可能需要一个用于请求的库的CMake查找脚本(CMake已经附带了其中的两个,但您可以轻松编写自己的脚本),或者是由请求的库本身提供的软件包配置脚本。无论哪种情况,您都可能需要调整CMAKE_MODULE_PATH才能使CMake能够找到相应的脚本。
使用哪种选择非常简单:
- 如果库提供的话,优先选择软件包配置脚本。
- 使用查找脚本作为不了解CMake的库的后备。
- 如果要利用pkg-config的协同作用,请使用pkg_search_module。特别是,请注意,可以使用pkg_search_module来实现查找脚本,作为获取所需信息的一种方法。
使用示例
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBUV REQUIRED libuv)
set(NETDATA_COMMON_CFLAGS ${NETDATA_COMMON_CFLAGS} ${LIBUV_CFLAGS_OTHER})
set(NETDATA_COMMON_LIBRARIES ${NETDATA_COMMON_LIBRARIES} ${LIBUV_LIBRARIES})
set(NETDATA_COMMON_INCLUDE_DIRS ${NETDATA_COMMON_INCLUDE_DIRS} ${LIBUV_INCLUDE_DIRS})
前提:安装了libuv,并且将libuv.pc
复制到了/usr/lib64/pkgconfig/
路径下。否则出错: – Checking for module ‘libuv’
– No package ‘libuv’ found
官网翻译
FindPkgConfig
CMake的pkg-config模块。
找到pkg-config可执行文件并添加pkg_get_variable()、pkg_check_modules()和pkg_search_module()命令。以下变量也将被设置:
- PKG_CONFIG_FOUND:是否找到pkg-config可执行文件
- PKG_CONFIG_EXECUTABLE:pkg-config程序的路径
- PKG_CONFIG_VERSION_STRING:pkg-config版本(自CMake 2.8.8以来)
pkg_check_modules
检查所有给定的模块,在调用范围内设置各种结果变量。
pkg_check_modules(<prefix>
[REQUIRED] [QUIET]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[IMPORTED_TARGET [GLOBAL]]
<moduleSpec> [<moduleSpec>...])
(0)<prefix>
。举个例子
pkg_check_modules(SDL2 IMPORTED_TARGET sdl2)
- 意思是:
- 我们要去默认路径下找叫做sdl2模块的库
- 如果找到了,就生成一个叫做
PkgConfig:SDL2
的导入目标,这个目标可以直接用到target_link_libraries
语句中 - 当
pkg_check_modules(....)
执行完毕之后,会生成如下变量(SDL2就是<prefix>
,可以自己起一个容易记住的名字,随便起):
SDL2_FOUND:如果模块存在,则设置为1
SDL2_LIBRARIES:只有库(没有“-l”)
SDL2_LINK_LIBRARIES:库及其绝对路径
SDL2_LIBRARY_DIRS:库的路径(没有“-L”)
SDL2_LDFLAGS:所有必需的链接器标志
.....
- 然后,我们就可以这样利用了
pkg_check_modules(SDL2 IMPORTED_TARGET sdl2)
if (SDL2_FOUND)
include_directories(${SDL2_INCLUDE_DIRS})
link_directories(${SDL2_LIBRARY_DIRS})
list(APPEND LINK_LIB_LIST ${SDL2_LIBRARIES})
target_link_libraries(${PROJECT_NAME} PkgConfig::SDL2)
message(STATUS "found library:${SDL2_LIBRARIES}")
endif ()
再举个例子,如下:
pkg_check_modules(ffmpeg REQUIRED IMPORTED_TARGET libavcodec libavformat libavutil)
- 去默认路径下,libavcodec libavformat libavutil这三个库,如果都找到了,那么,会生成如下变量:
ffmpeg_FOUND:如果模块存在,则设置为1
ffmpeg_LIBRARIES:只有库(没有“-l”)
......
(1) REQUIRED
:可选。意为“必须”
- 如果找不到模块,命令将失败并报错,并停止运行
- 如果不选择,那么没有找到这个模块,那么就跳过
(2)QUIET
:也是可选的。意为“安静”,当填写此参数,将会静默输出,不会打印任何信息
(3)NO_CMAKE_PATH
和NO_CMAKE_ENVIRONMENT_PATH
,也是可选的
- 默认情况下,CMAKE_PREFIX_PATH、CMAKE_FRAMEWORK_PATH和CMAKE_APPBUNDLE_PATH缓存和环境变量将被添加到pkg-config搜索路径。
- 如果填写了这两个参数,
NO_CMAKE_PATH
和NO_CMAKE_ENVIRONMENT_PATH
参数就不去缓存路径和环境变量路径中搜索了
(4)[IMPORTED_TARGET [GLOBAL]]
IMPORTED_TARGET
参数将创建一个名为PkgConfig::< prefix>
的导入目标,该目标可以作为参数直接传递给target_link_libraries()。GLOBAL
参数将使导入的目标在全局作用域中可用。
(5)< moduleSpec >
- 每个< moduleSpec >可以是裸模块名,也可以是带有版本约束的模块名(支持运算符=、<、>、<=和>=)。以下是具有各种约束的名为foo的模块的示例:
- Foo匹配任何版本。
- Foo <2只匹配2之前的版本。
- Foo >=3.1匹配3.1或更高版本的任何版本。
- Foo =1.2.3要求Foo必须是1.2.3版本。
(6)返回值
返回时可以设置以下变量。存在两组值:一组用于普通情况(< XXX > = < prefix>),另一组用于pkg-config在使用——static选项调用时提供的信息(< XXX > = < prefix>_STATIC)。
< XXX > _FOUND:如果模块存在,则设置为1
< XXX > _LIBRARIES:只有库(没有“-l”)
< XXX > _LINK_LIBRARIES:库及其绝对路径
< XXX > _LIBRARY_DIRS:库的路径(没有“-L”)
< XXX > _LDFLAGS:所有必需的链接器标志
< XXX > _LDFLAGS_OTHER:所有其他链接器标志
< XXX > _INCLUDE_DIRS:预处理器标记’-I’(没有’-I’)
< XXX > _CFLAGS:所有必需的cflags
< XXX > _CFLAGS_OTHER:其他编译器标志
< YYY > _VERSION:模块版本
< YYY > _PREFIX:模块的前缀目录
< YYY > _INCLUDEDIR:包含模块的目录
< YYY > _LIBDIR:模块的Lib目录
例子:
pkg_check_modules(ffmpeg REQUIRED IMPORTED_TARGET libavcodec libavformat libavutil)
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::ffmpeg)
例子:
pkg_check_modules (GLIB2 glib-2.0)
查找任何版本的glib2。如果找到,输出变量GLIB2_VERSION将保存找到的实际版本。
pkg_check_modules (GLIB2 glib-2.0>=2.10)
查找glib2至少2.10版本。如果找到,输出变量GLIB2_VERSION将保存找到的实际版本。
pkg_check_modules (FOO glib-2.0>=2.10 gtk+-2.0)
查找glib2-2.0(至少2.10版本)和gtk2±2.0的任何版本。只有当两者都被找到时,才会认为FOO被找到。FOO_glib-2.0_VERSION和FOO_gtk±2.0_VERSION变量将被设置为它们各自找到的模块版本。
pkg_check_modules (XRENDER REQUIRED xrender)
这句话的意思是“你可以去路径中找xrender这个库,任何版本都可以”。如果能够找到,那么就会设置宏XRENDER_LIBRARIES,XRENDER_STATIC_LIBRARIES。举个例子 :
XRENDER_LIBRARIES=Xrender;X11
XRENDER_STATIC_LIBRARIES=Xrender;X11;pthread;Xau;Xdmcp
pkg_search_module
此命令的行为与pkg_check_modules()相同,不同之处是它只搜索第一个成功匹配的模块,而不是检查所有指定的模块。
pkg_search_module(<prefix>
[REQUIRED] [QUIET]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[IMPORTED_TARGET [GLOBAL]]
<moduleSpec> [<moduleSpec>...])
3.16新版功能:如果找到一个模块,< prefix >_MODULE_NAME变量将包含匹配模块的名称。如果需要运行pkg_get_variable(),可以使用这个变量。
例子:
pkg_search_module (BAR libxml-2.0 libxml2 libxml>=2)
pkg_get_variable
3.4新版功能。
检索pkg-config变量varName的值,并将其存储在调用范围内的结果变量resultVar中。
pkg_get_variable(<resultVar> <moduleName> <varName>)
如果pkg-config返回指定变量的多个值,resultVar将包含一个;-list。
例如:
pkg_get_variable(GI_GIRDIR gobject-introspection-1.0 girdir)