cmake:find_package 添加依赖库

此文为:轻松入门cmake系列教程

引入库文件时,我们必须知道头文件的路径还有库文件的路径

在cmake某个程序的时候,经常会提示找不到某个所依赖的库,那么这是时候我们就需要检查我们引入依赖库的路径对不对了, Cmake中一个自动寻找函数find_package()可以帮我们实现这个功能。

实践

例子:Boost

实例

cmake_minimum_required(VERSION 3.5)

# Set the project name
project (third_party_include)


# find a boost install with the libraries filesystem and system
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)

# check if boost was found
if(Boost_FOUND)
    message ("boost found")
else()
    message (FATAL_ERROR "Cannot find Boost")
endif()

# Add an executable
add_executable(${PROJECT_NAME} main.cpp)

# link against the boost libraries
target_link_libraries( ${PROJECT_NAME}
    PRIVATE
        Boost::filesystem
)

这将从默认系统位置搜索boost

理论

(1)查找一个包

  • find_package()函数将从CMAKE_MODULE_PATH中的文件夹列表中搜索格式为FindXXX.cmake的CMake模块。find_package的参数的确切格式将取决于你要查找的模块。这通常记录在文件FindXXX.cmake的顶部
  • 下面是查找Boost的基本示例:
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
  • 参数说明:
    • Boost -库的名称。这是用于查找模块文件FindBoost.cmake的一部分。
    • 1.46.1 - 要查找的Boost的最低版本。
    • REQUIRED - 告诉模块这是必需的,如果失败,则编译通不过。
    • COMPONENTS - 要查找的库列表。

(2)检查是否找到该包

  • 大多数包含的软件包都会设置一个变量XXX_FOUND,该变量可用于检查该软件包在系统上是否可用。
if(Boost_FOUND)
    message ("boost found")
    include_directories(${Boost_INCLUDE_DIRS})
else()
    message (FATAL_ERROR "Cannot find Boost")
endif()

(3)导出变量

  • 在找到包之后,它通常会导出变量,这些变量可以告诉用户在哪里可以找到库、头文件或可执行文件。
  • 与XXX_FOUND变量类似,它们是特定于包的,通常记录在FindXXX.cmake文件的顶部。
  • 本例中导出的变量包括:
    • Boost_INCLUDE_DIRS - Boost头文件的路径
  • 在某些情况下,你还可以通过使用ccmake或cmake-gui检查缓存来检查这些变量。

(3)别名/导入目标

  • 较新版本的CMake允许你使用导入的别名目标链接第三方库。
  • 导入目标是由FindXXX模块导出的只读目标(例如Boost::filesystem)。
  • 要包括Boost文件系统,你可以执行以下操作:
 target_link_libraries( third_party_include
      PRIVATE
          Boost::filesystem
  )
  • 这将自动链接Boost::FileSystem和Boost::System库,同时还包括Boost include目录(即不必手动添加include目录)。
  • 关于Boost::filesystem,是因为boost库中,所有目标通过使用标识符Boost::加子模块的名字来导出。比如:
    • Boost::system 对于Boost系统库
    • Boost::filesystem 对于文件系统库
  • 与下面不同的是,这些目标包含它们的依赖项,也就是不需要手动target_include_directories了

(3)非别名目标

  • 虽然大多数现代库使用导入的目标,但并非所有模块都已更新。在库尚未更新的情况下,你通常会发现以下变量可用:

    • xxx_INCLUDE_DIRS - 指向库的include目录的变量
    • xxx_LIBRARY - 指向库路径的变量.
  • 然后,可以将这些文件添加到target_include_directory和target_link_library中:

# Include the boost headers
target_include_directories( third_party_include
    PRIVATE ${Boost_INCLUDE_DIRS}
)

# link against the boost libraries
target_link_libraries( third_party_include
    PRIVATE
    ${Boost_SYSTEM_LIBRARY}
    ${Boost_FILESYSTEM_LIBRARY}
)

例子:opencv

find_package( OpenCV REQUIRED )
if (OpenCV_FOUND)
	include_directories( ${OpenCV_INCLUDE_DIRS} )
	target_link_libraries( ${PROJECT_NAME} ${OpenCV_LIBS} )
endif (OpenCV_FOUND)	

例子:bzip2

find_package (BZip2)
if (BZIP2_FOUND)
    include_directories(${BZIP_INCLUDE_DIRS})
    target_link_libraries (test ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)

总结:

现在用 XXX 代表要查找的 package 名字
find_pacakge(XXX REQUIRED)会设置一系列变量。

XXX_FOUND 代表库是否查找成功
XXX_INCLUDE_DIRS 代表头文件的路径
XXX_LIBRARIES 代表库文件的路径

例子:单独引入某些组件

一个库可能由好多个组件构成,cmake 可以单独引入这些组件

find_package(Qt5 5.1.0 COMPONENTS Widgets Xml Sql)

引入了 Qt5 中的 Widgets Xml Sql 组件。

理论

语法

实际上,通过 find_package() 可以顺利查找任何符合 cmake package 标准的外部工程。

find_pacage()方法签名如下:

find_package(<package> [version] [EXACT] [QUIET] [MODULE]
             [REQUIRED] [[COMPONENTS] [components...]]
             [OPTIONAL_COMPONENTS components...]
             [NO_POLICY_SCOPE])
  • versionEXACT: 都是可选的,version指定的是版本,如果指定就必须检查找到的包的版本是否和version兼容。如果指定EXACT则表示必须完全匹配的版本而不是兼容版本就可以。
  • QUIET 可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)
  • MODULE可选字段。默认“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了MODULE选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。
  • REQUIRED可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定REQUIRED则cmake会继续执行。
  • COMPONENTS:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于REQUIRED,导致cmake停止执行
  • OPTIONAL_COMPONENTS:可选的模块,找不到也不会让cmake停止执行。

原理

首先,cmake本身不提供任何搜索库的便捷方法,所有搜索库并给变量赋值的操作必须由cmake代码完成,比如FindXXX.cmake和XXXConfig.cmake。只不过,库的作者通常会提供这两个文件,以方便使用者调用。
find_package采用两种模式搜索库:

  • Module模式:搜索CMAKE_MODULE_PATH指定路径下的FindXXX.cmake文件,执行该文件从而找到XXX库。其中,具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由FindXXX.cmake模块完成(先搜索当前项目里面的Module文件夹里面提供的*FindXXX.cmake,然后再搜索系统路径/usr/local/share/cmake-x.y/Modules/FindXXX.cmake)
  • Config模式:搜索XXX_DIR指定路径下的XXXConfig.cmake文件,执行该文件从而找到XXX库。其中具体查找库并给XXX_INCLUDE_DIRS和XXX_LIBRARIES两个变量赋值的操作由XXXConfig.cmake模块完成。
  • 对于可能没有***.cmake和***Config.cmake的库文件,可以直接找到其头文件和库文件所在文件夹,直接进行路径赋值:
SET(LAPACK_DIR /usr/local/lib/) 
SET(LAPACK_INCLUDE_DIRS /usr/local/include) 
SET(LAPACK_LIBRARIES /usr/local/lib)

你可能感兴趣的:(C++,c++,c语言,开发语言)