使用第三方库有两种方式,一种是使用cmake文件导入的方式,另一种是使用pc文件导入的方式
cmake文件导入
cmake文件查找
使用findPackage函数来查找cmake文件并执行cmake文件的代码,查找cmake文件的方式有两种,一种是Config模式,一种是Module模式
Config模式
这种模式一般是由第三方库自己生成的cmake文件,直接使用就行了
cmake文件的搜索路径 <lib_name>_DIR
和 CMAKE_CMAKE_PREFIX_PATH
cmake文件的文件名是<lib_name>Config.cmake
或<lib_name>-config.cmake
使用方法:
list(APPEND CMAKE_CMAKE_PREFIX_PATH "<lib_name>Config.cmake文件所在目录")
或
set(<lib_name>_DIR "<lib_name>Config.cmake文件所在目录")
#1.单模块
find_package(<lib_name> [version] [EXACT] [QUIET] [MODULE])#包名
#2.多模块
find_package(<lib_name> [version] [EXACT] [QUIET] [MODULE] #包名
[REQUIRED] [[COMPONENTS] [components...]] #模块名
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
在后面的《cmake安装》这里会介绍单模块和多模块cmake文件的生成和安装方法
Module模式
这种模式一般是由于第三方库自己没有生成cmake文件,需要自己手动写cmake文件
cmake文件的搜索路径为CMAKE_MODULE_PATH
cmake文件的文件名是Find<lib_name>.cmake
使用方法:
- 在最外层的CMakeLists.txt文件所在的目录创建cmake文件夹
- 在cmake文件夹下添加
Find<lib_name>.cmake
文件 - 在最外层的CMakeLists.txt文件中添加如下代码
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") #添加cmake文件夹到CMAKE_MODULE_PATH变量中 find_package(<lib_name> [version] [EXACT] [QUIET] [MODULE])
cmake文件内容
cmake文件的代码的目的是获得第三方库的属性,并能够被创建的目标使用,属性包括库文件路径,头文件路径等等
获取第三方库属性
find_path文档:https://cmake.org/cmake/help/v3.19/command/find_path.html?highlight=find_path
# 搜索头文件路径,如果(搜索目录/suffix)目录下存在name的头文件,则VAR变量设置为(搜索目录/suffix)
find_path(<VAR>
name | NAMES name1 [name2 ...] #查找的头文件名称,可以带目录如XX/YY.h
[HINTS path1 [path2 ... ENV var]] #在默认路径前搜索的目录
[PATHS path1 [path2 ... ENV var]] #在默认路径后搜索的目录
[PATH_SUFFIXES suffix1 [suffix2 ...]]) #搜索目录=搜索目录/suffix
VAR变量的名称一般设置为<lib_name>_INCLUDE_DIRS
find_library文档:https://cmake.org/cmake/help/v3.19/command/find_library.html?highlight=find_library
# 搜索头文件路径,如果(搜索目录/suffix)目录下存在lib<name>.so的库文件,则VAR变量设置为(搜索目录/suffix)
find_library (<VAR>
name | NAMES name1 [name2 ...] [NAMES_PER_DIR] #查找的库文件名称
[HINTS path1 [path2 ... ENV var]] #在默认路径前搜索的目录
[PATHS path1 [path2 ... ENV var]] #在默认路径后搜索的目录
[PATH_SUFFIXES suffix1 [suffix2 ...]]) #搜索目录=搜索目录/suffix
VAR变量的名称一般设置为<lib_name>_LIBRARIES
判断是否查找成功
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(<PackageName>
[FOUND_VAR <result-var>] #如果required-var都有定义,result-var设置成TRUE,否则设置FALSE
[REQUIRED_VARS <required-var>...])
required-var配置上面的两个变量名
result-var的名称一般设置成<lib_name>_FOUND
输出第三方库属性
为了之后创建的目标能够使用这些属性,有两种方式来输出这些属性,一种是把这些属性设置到变量中,另一种是创建IMPRTED类型的目标,并把这些属性设置到目标的属性中
设置变量
#设置这些变量为缓存变量,即是全局变量
mark_as_advanced([CLEAR|FORCE] <var1> ...)
上面一步已经将属性设置到变量中了,新创建的目标可以使用
target_link_libraries(<target_name> <lib_name>_LIBRARIES)
来链接第三方库的库文件
target_include_directories(<target_name> <lib_name>_INCLUDE_DIRS)
来使用第三方库的头文件
创建IMPRTED类型目标
if(<lib_name>_FOUND AND NOT TARGET <lib_name>) #头文件目录和库文件目录都找到了
add_library(<lib_name> UNKNOWN IMPORTED) #创建IMPRTED类型目标
set_target_properties(<lib_name> PROPERTIES
IMPORTED_LOCATION "${<lib_name>_LIBRARIES}"
INTERFACE_INCLUDE_DIRECTORIES "${<lib_name>_INCLUDE_DIRS}") #设置头文件目录和库文件目录到目标的属性中
endif()
新创建的目标可以使用
target_link_libraries(<target_name> <lib_name>)
来链接第三方库的库文件和使用第三方库的头文件
pc导入
# 创建IMPRTED类型目标
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(<lib_name> QUIET IMPORTED_TARGET <pc_name>)
if(<lib_name>_FOUND)
#创建了一个名为PkgConfig::<lib_name>的IMPRTED类型目标,与上面一样处理就行
endif()
endif()
endif()
pkg_check_modules:在/usr/local/lib/pkgconfig或/usr/lib/pkgconfig目录下查找名为<pc_name>.pc的文件解析库文件位置,头文件位置以及依赖库的名称,并输出这些属性到IMPRTED类型目标<lib_name>中
# 输出到变量
find_package(PkgConfig QUIET)
if(PkgConfig_FOUND)
pkg_check_modules(<lib_name> QUIET <pc_name>)
if(<lib_name>_FOUND)
#输出到变量中,与上面一样处理就行
endif()
endif()
endif()
pkg_check_modules:在/usr/local/lib/pkgconfig或/usr/lib/pkgconfig目录下查找名为<pc_name>.pc的文件解析库文件位置,头文件位置以及依赖库的名称,并输出这些属性到变量中
库文件路径:<lib_name>_LIBRARIES
头文件路径: <lib_name>_INCLUDE_DIRS
pc文件内容解析
prefix=/usr/local/ffmpeg #库的安装根目录
exec_prefix=${prefix} #执行文件的安装路径,通常与prefix相同
libdir=${exec_prefix}/lib #库文件所在的目录
includedir=${prefix}/include #头文件所在的目录
Name: libavformat #库文件的名称
Description: A simple example library #描述
Version: 1.0.0
Requires: zib yaml-cpp #依赖的库名称,会继续寻找这些依赖库的pc文件
Cflags: -I${includedir} #编译参数
Libs: -L${libdir} -lavformat #链接参数