本文共 6677 字,大约阅读时间需要 22 分钟。
find_package()有Module模式(基本用法)和Config模式(完全用法),其中Module模式是基础,Config模式则提供复杂高级功能。
find_package是否使用Config模式可以通过下列条件判断:(1)find_package()中指定CONFIG关键字(2)find_package()中指定NO_MODULE关键字(3)find_package()中使用了不再Module模式下所有支持配置的关键字find_package([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)查找。find_package([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_PATHCMAKE_FRAMEWORK_PATHCMAKE_APPBUNDLE_PATH
可以通过设定NO_CMAKE_PATH来关闭特定缓存变量的查找顺序
(3)CMake特定的环境变量PackageName_DIRCMAKE_PREFIX_PATHCMAKE_FRAMEWORK_PATHCMAKE_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_PATHCMAKE_SYSTEM_FRAMEWORK_PATHCMAKE_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字段指定的路径中查找。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(<name> [major.minor] [QUIET] [NO_MODULE] [[REQUIRED | COMPONENTS] [componets …]])
用来调用预定义在CMAKE_MODULE_PATH下的Findname.cmake模块,可以自己定义Findname模块,通过SET(CMAKE_MODULE_PATH dir)将其放入工程的某个目录供工程使用。 FIND_LIBRARY(libX X11 /usr/lib)IF (NOT libx) MESSAGE(FATAL_ERROR "libX not found")ENDIF(NOT libX)
系统预定义了各种模块,通常需要使用INCLUDE指令显式的调用, 但FIND_PACKAGE指令是一个特例,可以直接调用预定义的模块。
每一个模块都会定义以下3个变量:_FOUND _INCLUDE_DIR or _INCLUDES _LIBRARY or _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)
工程实践中使用示例如下:
#通过_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文件:
#includeint 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.转载于:https://blog.51cto.com/9291927/2396884