从零开始 CMake 学习笔记 (H)third-party-library
开始前先默念三遍口诀:
- Declare a target
- Declare target’s traits
- It’s all about targets
本系列主要根据GitHub上的 cmake-examples 项目进行翻译总结,同时对于不清晰的概念及函数进行查阅理解记录形成。
1 介绍
本示例展示了如何查找及支持第三方库。几乎所有大的项目都需要用到第三方库、头文件或程序。CMake支持使用 find_package() 函数来查找这个工具的路径。但是必须先为cmake配置查找配置的cmake模块,模块文件名称形如“FindXXX.cmake”,这些模块文件通常会放到一个指定的目录中,然后将CMAKE_MODULE_PATH 变量设置为该路径。Linux系统默认的路径为“/usr/share/cmake/Modules”。
本示例需要提前安装boost。
1.1 文件树
H-third-party-library $ tree . ├── CMakeLists.txt ├── main.cpp
1.2 文件简介
- CMakeLists.txt - 包含了你希望运行的 CMake 命令
cmake_minimum_required(VERSION 3.5)
project (third_party_include)
find_package(Boost 1.46.1 REQUIRED COMPONENTS filesystem system)
if(Boost_FOUND)
message ("boost found")
else()
message (FATAL_ERROR "Cannot find Boost")
endif()
add_executable(third_party_include main.cpp)
target_link_libraries( third_party_include
PRIVATE
Boost::filesystem
)
-main.cpp - main文件
#include <iostream>
#include <boost/shared_ptr.hpp>
#include <boost/filesystem.hpp>
int main(int argc, char *argv[])
{
std::cout << "Hello Third Party Include!" << std::endl;
boost::shared_ptr<int> isp(new int(4));
boost::filesystem::path path = "/usr/share/cmake/modules";
if(path.is_relative())
{
std::cout << "Path is relative" << std::endl;
}
else
{
std::cout << "Path is not relative" << std::endl;
}
return 0;
}
2 概念解析
2.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 - 要查找的库的最低版本要求;
- REQUIRED - 表示这是必须的,如果找不到就报错失败;
- COMPONENTS - 要查找的库中的组件或者子模块。
Boost 包含可以接受更多参数,也可以使用其他变量。
2.1.1 find_package()拓展
这里对find_package() 函数进行拓展学习,不感兴趣可以直接忽略。该函数的目的就是 找到一个库,并加载其功能。
根据官方文档,find_package() 分为 Module 模式(基本用法,Basic Signature)和 Config模式(完全用法,full signature)。
首先,这两个用法的参数不同,默认执行的就是 Module 模式,也就是基本用法。 而如何区分这两个模式,有下面三种情况出现,就是 Config 模式,其他都是 Module 模式:
find_package() 中指定 CONFIG 关键字;find_package() 中指定 NO_MODULE 关键字;find_package() 中使用了不在 “Basic Signature”(也就是 Moudle 模式下所支持的关键字)
这就是区分这两个模式的方法,那这两个模式到底是什么样的?
Module 模式
Module 模式下 find_package() 的详细参数如下:
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
Module模式下,相比于Config模式,可选配置参数少一些,并且如果按用户指定的配置却找不到包,就会自动进入Config模式。
关键字解释: version 和EXACT : 都是可选的,version 指定的是版本,如果指定就必须检查找到的包的版本是否和version 兼容。如果指定EXACT 则表示必须完全匹配的版本而不是兼容版本就可以。
QUIET 可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了REQUIRED 字段,则QUIET 无效,仍然会输出查找失败提示语)。
MODULE 可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了MODULE 选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。
REQUIRED 可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定REQUIRED 则cmake会继续执行。
COMPONENTS ,components :可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于REQUIRED ,导致cmake停止执行。
OPTIONAL_COMPONENTS 和components :可选的模块,找不到也不会让cmake停止执行。
Module模式查找顺序
Module模式下是要查找到名为Find<PackageName>.cmake 的文件。
先在CMAKE_MODULE_PATH 变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,比如/usr/local/share/cmake/Modules )查找。
Config 模式
Config 模式下 find_package() 的详细参数如下:
find_package(<PackageName> [version] [EXACT] [QUIET]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[CONFIG|NO_MODULE]
[NO_POLICY_SCOPE]
[NAMES name1 [name2 ...]]
[CONFIGS config1 [config2 ...]]
[HINTS path1 [path2 ... ]]
[PATHS path1 [path2 ... ]]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_PACKAGE_REGISTRY]
[NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH])
相比 Module 模式下多很多。它要找的文件名字也不一样,Config模式要找<PackageName>Config.cmake 或 <lower-case-package-name>-config.cmake 。查找顺序为: 名为 <PackageName>_ROOT 的cmake变量或环境变量。 注意:如果定义了 <PackageName>_DIR cmake 变量,那么 <PackageName>_ROOT 不起作用。 这个有点复杂,暂时先放着,用到了再看。
3 运行结果
H-third-party-library $ mkdir build
H-third-party-library $ cd build/
H-third-party-library $ cmake ..
-- The C compiler identification is GNU 9.4.0
-- The CXX compiler identification is GNU 9.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Boost version: 1.54.0
-- Found the following Boost libraries:
-- filesystem
-- system
boost found
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/H-third-party-library/build
H-third-party-library $ make
Scanning dependencies of target third_party_include
[100%] Building CXX object CMakeFiles/third_party_include.dir/main.cpp.o
Linking CXX executable third_party_include
[100%] Built target third_party_include
matrim@freyr:~/workspace/cmake-examples/01-basic/H-third-party-library/build$ ./
CMakeFiles/ third_party_include
matrim@freyr:~/workspace/cmake-examples/01-basic/H-third-party-library/build$ ./third_party_include
Hello Third Party Include!
Path is not relative
H-third-party-library $ cmake ..
-- The C compiler identification is GNU 4.8.4
-- The CXX compiler identification is GNU 4.8.4
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Boost version: 1.54.0
-- Found the following Boost libraries:
-- filesystem
-- system
boost found
-- Configuring done
-- Generating done
-- Build files have been written to: /home/matrim/workspace/cmake-examples/01-basic/H-third-party-library/build
H-third-party-library $ make
Scanning dependencies of target third_party_include
[100%] Building CXX object CMakeFiles/third_party_include.dir/main.cpp.o
Linking CXX executable third_party_include
[100%] Built target third_party_include
H-third-party-library $ ./third_party_include
Hello Third Party Include!
Path is not relative
|