find_package()有Module模式(基本用法)和Config模式(徹底用法),其中Module模式是基礎,Config模式則提供複雜高級功能。
find_package是否使用Config模式能夠經過下列條件判斷:
(1)find_package()中指定CONFIG關鍵字
(2)find_package()中指定NO_MODULE關鍵字
(3)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(<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
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)將其放入工程的某個目錄供工程使用。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.