GNU开发工具——CMake模块

GNU开发工具——CMake模块

1、find_packge高级功能

一、find_package的模式

find_package()有Module模式(基本用法)和Config模式(彻底用法),其中Module模式是基础,Config模式则提供复杂高级功能。
find_package是否使用Config模式能够经过下列条件判断:
(1)find_package()中指定CONFIG关键字
(2)find_package()中指定NO_MODULE关键字
(3)find_package()中使用了再也不Module模式下全部支持配置的关键字缓存

二、find_package工做流程

GNU开发工具——CMake模块

三、find_package的Module模式

find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE] [REQUIRED] [[COMPONENTS] [components...]] [OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])

version和EXACT,可选,version指定版本,若是指定就必须检查找到的包的版本是否和version兼容。若是指定EXACT则表示必须彻底匹配的版本而不是兼容版本就能够。
QUIET,可选字段,表示若是查找失败,不会在屏幕进行输出(但若是指定了REQUIRED字段,则QUIET无效,仍然会输出查找失败提示语)。
MODULE,可选字段。前面提到说“若是Module模式查找失败则回退到Config模式进行查找”,可是假如设定了MODULE选项,那么就只在Module模式查找,若是Module模式下查找失败并不回落到Config模式查找。
REQUIRED可选字段。表示必定要找到包,找不到的话就当即停掉整个cmake。而若是不指定REQUIRED则cmake会继续执行。
COMPONENTS,components:可选字段,表示查找的包中必需要找到的组件(components),若是有任何一个找不到就算失败,相似于REQUIRED,致使cmake中止执行。
Module模式下须要查找到名为FindPackageName.cmake的文件。
先在CMAKE_MODULE_PATH变量对应的路径中查找。若是路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,好比/usr/local/share/cmake/Modules)查找。ide

四、find_package的Config模式

find_package(<PackageName> [version] [EXACT] [QUIET]
[REQUIRED] [[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])

Config模式下的查找顺序,比Module模式下要多得多,新版本的CMake比老版本的有更多的查找顺序(新增的在最优先的查找顺序)。Config模式下须要查找到名为lower-case-package-name-config.cmake或PackageNameConfig.cmake文件。查找顺序以下:
(1)名为PackageName_ROOT的cmake变量或环境变量。CMake3.12新增。设定CMP0074 Policy来关闭。若是定义了PackageName_DIR cmake变量,那么PackageName_ROOT 不起做用。工具

cmake_minimum_required(VERSION 3.13)
project(OpenCVDemo)
set(OpenCV_ROOT "/usr/local/lib/opencv_249/build")
set(OpenCV_DIR "/usr/local/lib/opencv_300/build")

find_package(OpenCV QUIET
    NO_MODULE
    NO_DEFAULT_PATH
    NO_CMAKE_PATH
    NO_CMAKE_ENVIRONMENT_PATH
    NO_SYSTEM_ENVIRONMENT_PATH
    NO_CMAKE_PACKAGE_REGISTRY
    NO_CMAKE_BUILDS_PATH
    NO_CMAKE_SYSTEM_PATH
    NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
)
message(STATUS "OpenCV library status:")
message(STATUS "    version: ${OpenCV_VERSION}")
message(STATUS "    libraries: ${OpenCV_LIBS}")
message(STATUS "    include path: ${OpenCV_INCLUDE_DIRS}")

上述代码会找到opencv300,OpenCV_DIR变量的值有效OpenCV_ROOT变量无效。
(2)cmake特定的缓存变量开发工具

CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH

能够经过设定NO_CMAKE_PATH来关闭特定缓存变量的查找顺序
(3)CMake特定的环境变量ui

PackageName_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH

能够经过NO_CMAKE_ENVIRONMENT_PATH来跳过。
(4)HINT字段指定的路径
(5)搜索标准的系统环境变量PATH。
其中若是是以/bin或者/sbin结尾的,会自动转化为其父目录。
经过指定NO_SYSTEM_ENVIRONMENT_PATH来跳过。
(6)存储在CMake的"User Package Registry"(用户包注册表)中的路径。
经过设定NO_CMAKE_PACKAGE_REGISTRY,或设定CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY为true,来避开。
(7)设定为当前系统定义的cmake变量:
CMAKE_SYSTEM_PREFIX_PATH
CMAKE_SYSTEM_FRAMEWORK_PATH
CMAKE_SYSTEM_APPBUNDLE_PATH
经过设定NO_CMAKE_SYSTEM_PATH来跳过。
(8)在cmake的"System Package Registry"(系统包注册表)中查找。
经过设定NO_CMAKE_SYSTEM_PACKAGE_REGISTRY跳过,或者经过设定CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY为true避开。
(9)从PATHS字段指定的路径中查找。code

2、CMake自定义模块

一、find_xxx指令

FIND_FILE(VAR name path1 path2 …)
VAR变量表明找到的文件全路径,包含文件名。
FIND_LIBRARY(VAR name path1 path2 …)
VAR变量表明找到的库全路径,包含库文件名。
FIND_PATH(VAR name path1 path2 …)
VAR变量表明包含文件的路径
FIND_PROGRAM(VAR name path1 path2 …)
VAR变量表明包含程序的全路径
FIND_PACKAGE(&lt;name&gt; [major.minor] [QUIET] [NO_MODULE] [[REQUIRED | COMPONENTS] [componets …]])
用来调用预约义在CMAKE_MODULE_PATH下的Findname.cmake模块,能够本身定义Findname模块,经过SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录供工程使用。component

FIND_LIBRARY(libX X11 /usr/lib)
IF (NOT libx)
    MESSAGE(FATAL_ERROR "libX not found")
ENDIF(NOT libX)

二、系统预约义模块使用

系统预约义了各类模块,一般须要使用INCLUDE指令显式的调用, 但FIND_PACKAGE指令是一个特例,能够直接调用预约义的模块。
每个模块都会定义如下3个变量:blog

<name>_FOUND
<name>_INCLUDE_DIR or <name>_INCLUDES
<name>_LIBRARY or <name>_LIBRARIES

所以,能够经过name_FOUND来判断模块是否被找到,若是没有找到,按照工程的须要关闭某些特性、给出提醒或者停止构建。
对于系统预约义的Findname.cmake模块,使用方法以下:开发

FIND_PACKAGE(NAME)
IF(NAME_FOUND)
    INCLUDE_DIRECTORIES(${NAME_INCLUDE_DIR})
    TARGET_LINK_LIBRARIES(targetname ${NAME_LIBRARY})
ELSE(NAME_FOUND)
    MESSAGE(FATAL_ERROR ”NAME library not found”)
ENDIF(NAME_FOUND)

工程实践中使用示例以下:get

#经过<name>_FOUND来控制工程特性:
SET(SOURCES Viewer.cpp)
SET(OptionalSources)
SET(OptionalLibs)
FIND_PACKAGE(JPEG)
IF(JPEG_FOUND)
    SET(OptionalSources ${OptionalSources} JPEGView.cpp)
    INCLUDE_DIRECTORIES( ${JPEG_INCLUDE_DIR} )
    SET(optionalLibs ${OptionalLibs} ${JPEG_LIBRARIES} )
    ADD_DEFINITIONS(-DENABLE_JPEG_SUPPORT)
ENDIF(JPEG_FOUND)

IF(PNG_FOUND)
    SET(OptionalSources ${OptionalSources} PNGView.cpp)
    INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )
    SET(OptionalLibs ${OptionalLibs} ${PNG_LIBRARIES} )
    ADD_DEFINITIONS(-DENABLE_PNG_SUPPORT)
ENDIF(PNG_FOUND)

ADD_EXECUTABLE(viewer ${SOURCES} ${OptionalSources} )
TARGET_LINK_LIBRARIES(Viewer ${OptionalLibs})
#经过判断系统是否提供了JPEG、PNG模块来决定程序是否支持JPEG、PNG功能。

三、自定义模块实现

本文基于libHello动态库,编写一个FindHelo.cmake模块。
建立一个FindHello项目目录,进入FindHello。
建立一个Hello目录,进入Hello目录,建立FindHelo.cmake文件,FindHelo.cmake文件以下:

#查找hello库头文件的安装路径
FIND_PATH(HELLO_INCLUDE_DIR Hello.h /usr/local/include/hello)
#查找hello库的安装路径
FIND_LIBRARY(HELLO_LIBRARY NAMES hello /usr/local/lib/libhello.so)

IF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)
    SET(HELLO_FOUND TRUE)
ENDIF (HELLO_INCLUDE_DIR AND HELLO_LIBRARY)

IF (HELLO_FOUND)
    IF (NOT HELLO_FIND_QUIETLY)
    MESSAGE(STATUS "Found Hello: ${HELLO_LIBRARY}")
    ENDIF (NOT HELLO_FIND_QUIETLY)
ELSE (HELLO_FOUND)
    IF (HELLO_FIND_REQUIRED)
    MESSAGE(FATAL_ERROR "Could not find hello library")
    ENDIF (HELLO_FIND_REQUIRED)
ENDIF (HELLO_FOUND)

返回FindHello目录,建立main.cpp文件:

#include <Hello.h>

int main(int argc, char* argv[])
{
    Hello hello;
    hello.Print();
    return 0;
}

建立工程CMakeLists.txt文件以下:

cmake_minimum_required(VERSION 2.8)
PROJECT(FindHello)
# 设置自定义模块路径
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/Hello/")
MESSAGE(STATUS "CMAKE_MODULE_PATH " ${PROJECT_SOURCE_DIR}/Hello)
#查找自定义Hello模块
FIND_PACKAGE(Hello)
IF(HELLO_FOUND)
    ADD_EXECUTABLE(hello main.cpp)
    INCLUDE_DIRECTORIES(${HELLO_INCLUDE_DIR})
    MESSAGE(STATUS "LINK " ${HELLO_LIBRARY})
    TARGET_LINK_LIBRARIES(hello ${HELLO_LIBRARY})
ELSE(HELLO_FOUND)
    MESSAGE(STATUS "Could not find hello library")
ENDIF(HELLO_FOUND)

建立build目录,进行build目录进行构建。cmake ../make./hello结果打印出Hello world.

相关文章
相关标签/搜索