1. 程式人生 > >find_package與CMake如何查詢連結庫詳解

find_package與CMake如何查詢連結庫詳解

如果編譯軟體使用了外部庫,事先並不知道它的標頭檔案和連結庫的位置。得在編譯命令中加上包含它們的查詢路徑。CMake使用 find_package 命令來解決這個問題。本文討論瞭如何在CMake專案中使用外部庫,以及如何給沒有查詢模組的庫寫一個。

1 FIND_PACKAGE

FIND_PACKAGE( <name> [version] [EXACT] [QUIET] [NO_MODULE] [ [ REQUIRED | COMPONENTS ] [ componets... ] ] )

用來呼叫預定義在 CMAKE_MODULE_PATH 下的 Find<name>.cmake 模組。

也可以自己定義 Find<name>模組,將其放入工程的某個目錄中,通過 SET(CMAKE_MODULE_PATH dir)設定查詢路徑,供工程FIND_PACKAGE使用。

這條命令執行後,CMake 會到變數 CMAKE_MODULE_PATH 指示的目錄中查詢檔案 Findname.cmake 並執行。

version引數

需要一個版本號,它是正在查詢的包應該相容的版本號(格式是major[.minor[.patch[.tweak]]])。

EXACT選項

要求版本號必須精確匹配。如果在find-module內部對該命令的遞迴呼叫沒有給定[version]引數,那麼[version]和EXACT選項會自動地從外部呼叫前向繼承。對版本的支援目前只存在於包和包之間(詳見下文)。


QUIET 引數:

會禁掉包沒有被發現時的警告資訊。對應於Find<name>.cmake模組中的 NAME_FIND_QUIETLY。

REQUIRED 引數

其含義是指是否是工程必須的,表示如果報沒有找到的話,cmake的過程會終止,並輸出警告資訊。對應於Find<name>.cmake模組中的 NAME_FIND_REQUIRED 變數。

COMPONENTS引數

在REQUIRED選項之後,或者如果沒有指定REQUIRED選項但是指定了COMPONENTS選項,在它們的後面可以列出一些與包相關(依賴)的部件清單(components list)


示例:

FIND_PACKAGE( libdb_cxx REQUIRED)

這條命令執行後,CMake 會到變數 CMAKE_MODULE_PATH 指示的目錄中查詢檔案 Findlibdb_cxx.cmake 並執行。

find_package() 命令會在模組路徑中尋找 Find<name>.cmake ,這是查詢庫的一個典型方式。首先CMake檢視${CMAKE_MODULE_PATH} 中的所有目錄,然後再檢視它自己的模組目錄 <CMAKE_ROOT>/share/cmake-x.y/Modules/ 。

如果沒找到這樣的檔案,會尋找 <Name>Config.cmake 或者 <lower-case-name>-config.cmake ,它們是假定庫會安裝的檔案(但是目前還沒有多少庫會安裝它們)。不做檢查,直接包含安裝的庫的固定值。

前面的稱為模組模式,後面的稱為配置模式。配置模式的檔案的編寫見 這裡的文件 。可能還會用到 importing and exporting targets 這篇文件。

模組系統好像還沒有文件,所以本文主要討論這方面的內容。

不管使用哪一種模式,只要找到包,就會定義下面這些變數:

<NAME>_FOUND
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
<NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
<NAME>_DEFINITIONS

這些都在 Find<name>.cmake 檔案中。

現在,在你的程式碼(要使用庫 <name> 的程式碼)的頂層目錄中的 CMakeLists.txt 檔案中,我們檢查變數<NAME>_FOUND 來確定包是否被找到。大部分包的這些變數中的包名是全大寫的,如 LIBFOO_FOUND ,有些包則使用包的實際大小寫,如 LibFoo_FOUND 。如果找到這個包,我們用 <NAME>_INCLUDE_DIRS 呼叫 include_directories() 命令,用 <NAME>_LIBRARIES 呼叫 target_link_libraries() 命令。

這些約定的文件在CMake模組目錄中的 readme.txt 檔案中。

REQUIRED 和其他可選的 find_package 的引數被 find_package 傳給模組,模組由此確定操作。

使用者程式碼總體上應該使用上述的簡單呼叫格式查詢需要的包。本命令文件的剩餘部分則詳述了find_package的完整命令格式以及具體的查詢過程。期望通過該命令查詢並提供包的專案維護人員,我們鼓勵你能繼續讀下去。

  該命令在搜尋包時有兩種模式:“模組”模式和“配置”模式。當該命令是通過上述的精簡格式呼叫的時候,用的就是模組模式。在該模式下,CMake搜尋所有名為Find<package>.cmake的檔案,這些檔案的路徑由安裝CMake時指定的CMAKE_MODULE_PATH變數指定。如果查詢到了該檔案,它會被CMake讀取並被處理。該模式對查詢包,檢查版本以及生成任何別的必須資訊負責。許多查詢模組(find-module)僅僅提供了有限的,甚至根本就沒有對版本化的支援;具體資訊檢視該模組的文件。如果沒有找到任何模組,該命令會進入配置模式繼續執行。

 完整的配置模式下的命令格式是:

  find_package(<package> [version] [EXACT] [QUIET]
               [[REQUIRED|COMPONENTS] [components...]] [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_CMAKE_ENVIRONMENT_PATH]
               [NO_CMAKE_PATH]
               [NO_SYSTEM_ENVIRONMENT_PATH]
               [NO_CMAKE_PACKAGE_REGISTRY]
               [NO_CMAKE_BUILDS_PATH]
               [NO_CMAKE_SYSTEM_PATH]
               [CMAKE_FIND_ROOT_PATH_BOTH |
                ONLY_CMAKE_FIND_ROOT_PATH |
                NO_CMAKE_FIND_ROOT_PATH])

  NO_MODULE可以用來明確地跳過模組模式。它也隱含指定了不使用在精簡格式中使用的那些選項。

  配置模式試圖查詢一個由待查詢的包提供的配置檔案的位置。包含該檔案的路徑會被儲存在一個名為<package>_DIR的cache條目裡。預設情況下,該命令搜尋名為<package>的包。如果指定了NAMES選項,那麼其後的names引數會取代<package>的角色。該命令會為每個在names中的name搜尋名為<name>Config.cmake或者<name全小寫>-config.cmake的檔案。

通過使用CONFIGS選項可以改變可能的配置檔案的名字。以下描述搜尋的過程。如果找到了配置檔案,它將會被CMake讀取並處理。由於該檔案是由包自身提供的,它已經知道包中內容的位置。配置檔案的完整地址儲存在cmake的變數<package>_CONFIG中。

  所有CMake要處理的配置檔案將會搜尋該包的安裝資訊,並且將該安裝匹配的適當版本號(appropriate version)儲存在cmake變數<package>_CONSIDERED_CONFIGS中,與之相關的版本號(associated version)將被儲存在<package>_CONSIDERED_VERSIONS中。

  如果沒有找到包配置檔案,CMake將會生成一個錯誤描述檔案,用來描述該問題——除非指定了QUIET選項。如果指定了REQUIRED選項,並且沒有找到該包,將會報致命錯誤,然後配置步驟終止執行。如果設定了<package>_DIR變數被設定了,但是它沒有包含配置檔案資訊,那麼CMake將會直接無視它,然後重新開始查詢。

  如果給定了[version]引數,那麼配置模式僅僅會查詢那些在命令中請求的版本(格式是major[.minor[.patch[.tweak]]])與包請求的版本互相相容的那些版本的包。如果指定了EXACT選項,一個包只有在它請求的版本與[version]提供的版本精確匹配時才能被找到。CMake不會對版本數的含義做任何的轉換。包版本號由包自帶的版本檔案來檢查。對於一個備選的包配置檔案<config-file>.cmake,對應的版本檔案的位置緊挨著它,並且名字或者是<config-file>-version.cmake或者是<config-file>Version.cmake。如果沒有這個版本檔案,那麼配置檔案就會認為不相容任何請求的版本。當找到一個版本檔案之後,它會被載入然後用來檢查(find_package)請求的版本號。版本檔案在一個下述變數被定義的巢狀域中被載入:

   PACKAGE_FIND_NAME          = <package>名字。
   PACKAGE_FIND_VERSION       = 請求的完整版本字串
   PACKAGE_FIND_VERSION_MAJOR = 如果被請求了,那麼它是major版本號,否則是0。
   PACKAGE_FIND_VERSION_MINOR = 如果被請求了,那麼它是minor版本號,否則是0。
   PACKAGE_FIND_VERSION_PATCH = 如果被請求了,那麼它是patch版本號,否則是0。
   PACKAGE_FIND_VERSION_TWEAK = 如果被請求了,那麼它是tweak版本號,否則是0。
   PACKAGE_FIND_VERSION_COUNT = 版本號包含幾部分,0到4。

  版本檔案會檢查自身是否滿足請求的版本號,然後設定了下面這些變數:

  PACKAGE_VERSION            = 提供的完整的版本字串。
  PACKAGE_VERSION_EXACT      = 如果版本號精確匹配,返回true。
  PACKAGE_VERSION_COMPATIBLE = 如果版本號相相容,返回true。
  PACKAGE_VERSION_UNSUITABLE = 如果不適合任何版本,返回true。

  下面這些變數將會被find_package命令檢查,用以確定配置檔案是否提供了可接受的版本。在find_package命令返回後,這些變數就不可用了。如果版本可接受,下述的變數會被設定:

  <package>_VERSION       = 提供的完整的版本字串。
  <package>_VERSION_MAJOR = 如果被請求了,那麼它是major版本號,否則是0。
  <package>_VERSION_MINOR = 如果被請求了,那麼它是minor版本號,否則是0。
  <package>_VERSION_PATCH = 如果被請求了,那麼它是patch版本號,否則是0。
  <package>_VERSION_TWEAK = 如果被請求了,那麼它是tweak版本號,否則是0。
  <package>_VERSION_COUNT = 版本號包含幾部分,0到4。

然後,對應的包配置檔案才會被載入。當多個包配置檔案都可用時,並且這些包的版本檔案都與請求的版本相容,選擇哪個包將會是不確定的。不應該假設cmake會選擇最高版本或者是最低版本。(以上的若干段是對find_package中版本匹配步驟的描述,並不需要使用者干預——譯註。)

  配置模式提供了一種高階介面和搜尋步驟的介面。這些被提供的介面的大部分是為了完整性的要求,以及在模組模式下,包被find-module載入時供內部使用。大多數使用者僅僅應該呼叫:

  find_package(<package> [major[.minor]] [EXACT] [REQUIRED|QUIET])

來查詢包。鼓勵那些需要提供CMake包配置檔案的包維護人員應該命名這些檔案並安裝它們,這樣下述的整個過程將會找到它們而不需要使用附加的選項。

  CMake為包構造了一組可能的安裝字首。在每個字首下,若干個目錄會被搜尋,用來查詢配置檔案。下述的表格展示了待搜尋的路徑。每個條目都是專門為Windows(W),UNIX(U)或者Apple(A)約定的安裝樹指定的。

    <prefix>/                                               (W)
   <prefix>/(cmake|CMake)/                                 (W)
   <prefix>/<name>*/                                       (W)
   <prefix>/<name>*/(cmake|CMake)/                         (W)
   <prefix>/(share|lib)/cmake/<name>*/                     (U)
   <prefix>/(share|lib)/<name>*/                           (U)
   <prefix>/(share|lib)/<name>*/(cmake|CMake)/             (U)

  在支援OS X平臺和Application Bundles的系統上,包含配置檔案的框架或者bundles會在下述的路徑中被搜尋:

    <prefix>/<name>.framework/Resources/                    (A)
   <prefix>/<name>.framework/Resources/CMake/              (A)
   <prefix>/<name>.framework/Versions/*/Resources/         (A)
   <prefix>/<name>.framework/Versions/*/Resources/CMake/   (A)
   <prefix>/<name>.app/Contents/Resources/                 (A)
   <prefix>/<name>.app/Contents/Resources/CMake/           (A)

  在所有上述情況下,<name>是區分大小寫的,並且對應於在<package>或者由NAMES給定的任何一個名字。

  這些路徑集用來與那些在各自的安裝樹上提供了配置檔案的工程協作。上述路徑中被標記為(W)的是專門為Windows上的安裝設定的,其中的<prefix>部分可能是一個應用程式的頂層安裝路徑。那些被標記為(U)的是專門為UNIX平臺上的安裝設定的,其中的<prefix>被多個包共用。這僅僅是個約定,因此,所有(W)和(U)路徑在所有平臺上都仍然會被搜尋。那些被標記為(A)的路徑是專門為Apple平臺上的安裝設定的。CMake變數CMAKE_FIND_FRAMEWORK和CMAKE_FIND_APPBUNDLE確定了偏好的順序,如下所示:

  安裝字首是通過以下步驟被構建出來的。如果指定了NO_DEFAULT_PATH選項,所有NO_*選項都會被啟用。

  1、搜尋在cmake特有的cache變數中指定的搜尋路徑。這些變數是為了在命令列中用-DVAR=value選項指定而設計的。通過指定NO_CMAKE_PATH選項可以跳過該搜尋路徑。搜尋路徑還包括:

    CMAKE_PREFIX_PATH
   CMAKE_FRAMEWORK_PATH
   CMAKE_APPBUNDLE_PATH

  2、搜尋cmake特有的環境變數。這些變數是為了在使用者的shell配置中進行配置而設計的。通過指定NO_CMAKE_ENVIRONMENT_PATH選項可以跳過該路徑。搜尋的路徑包括:

   <package>_DIR
   CMAKE_PREFIX_PATH
   CMAKE_FRAMEWORK_PATH
   CMAKE_APPBUNDLE_PATH

  3、搜尋HINTS選項指定的路徑。這些路徑應該是由作業系統內省時計算產生的,比如由其它已經找到的項的位置而提供的線索。硬編碼的參考路徑應該在PATHS選項中指定。

  4、搜尋標準的系統環境變數。如果指定了NO_SYSTEM_ENVIRONMENT_PATH選項,這些路徑會被跳過。以"/bin"或"/sbin"結尾的路徑條目會被自動轉換為它們的父路徑。搜尋的路徑包括:

   PATH

  5、搜尋在CMake GUI中最新配置過的工程的構建樹。可以通過設定NO_CMAKE_BUILDS_PATH選項來跳過這些路徑。這是為了在使用者正在依次構建多個相互依賴的工程時而準備的。

  6、搜尋儲存在CMake使用者包登錄檔中的路徑。通過設定NO_CMAKE_PACKAGE_REGISTRY選項可以跳過這些路徑。當CMake嗲用export(PACKAGE<name>)配置一個工程時,這些路徑會被儲存在登錄檔中。參見export(PACKAGE)命令的文件閱讀更多細節。

  7、搜尋在當前系統的平臺檔案中定義的cmake變數。可以用NO_CMAKE_SYSTEM_PATH選項跳過這些路徑。

   CMAKE_SYSTEM_PREFIX_PATH

   CMAKE_SYSTEM_FRAMEWORK_PATH

   CMAKE_SYSTEM_APPBUNDLE_PATH

  8、搜尋由PATHS選項指定的路徑。這些路徑一般是硬編碼的參考路徑。

  在Darwin或者支援OS X 框架的系統上,cmake變數CMAKE_FIND_FRAMEWORK可以用來設定為空,或者下述值之一:
     "FIRST"  - 在標準庫或標頭檔案之前查詢框架。在Darwin系統上這是預設選項。
     "LAST"   - 在標準庫或標頭檔案之後查詢框架。
     "ONLY"   - 僅僅查詢框架。
     "NEVER" - 從不查詢框架。

  在Darwin或者支援OS X Application Bundles的系統,cmake變數CMAKE_FIND_APPBUNDLE可以被設定為空或者下面這些值中的一個:

      "FIRST"  - 在標準庫或標頭檔案之前查詢application bundles。在Darwin系統上這是預設選項。
     "LAST"   - 在標準庫或標頭檔案之後查詢application bundles。
     "ONLY"   - 僅僅查詢application bundles。
     "NEVER" - 從不查詢application bundles。

  CMake變數CMAKE_FIND_ROOT_PATH指定了一個或者多個優先於其他搜尋路徑的搜尋路徑。該變數能夠有效地重新定位在給定位置下進行搜尋的根路徑。該變數預設為空。當使用交叉編譯時,該變數十分有用:用該變數指向目標環境的根目錄,然後CMake將會在那裡查詢。預設情況下,在CMAKE_FIND_ROOT_PATH中列出的路徑會首先被搜尋,然後是“非根”路徑。該預設規則可以通過設定CMAKE_FIND_ROOT_PATH_MODE_LIBRARY做出調整。在每次呼叫該命令之前,都可以通過設定這個變數來手動覆蓋預設行為。如果使用了NO_CMAKE_FIND_ROOT_PATH變數,那麼只有重定位的路徑會被搜尋。

  預設的搜尋順序的設計邏輯是按照使用時從最具體到最不具體。通過多次呼叫find_library命令以及NO_*選項,可以覆蓋工程的這個預設順序:

     find_library(<VAR> NAMES name PATHS paths... NO_DEFAULT_PATH)
    find_library(<VAR> NAMES name)

  只要這些呼叫中的一個成功返回,結果變數就會被設定並且被儲存到cache中;這樣隨後的呼叫都不會再行搜尋。如果那找到的庫是一個框架,VAR將會被設定為指向框架“<完整路徑>/A.framework” 的完整路徑。當一個指向框架的完整路徑被用作一個庫檔案,CMake將使用-framework A,以及-F<完整路徑>這兩個選項將框架連線到目標上。

  參見cmake_policy()命令的文件中關於NO_POLICY_SCOPE選項討論。



為了能支援各種常見的庫和包,CMake自帶了很多模組。可以通過命令 cmake --help-module-list (輸入cmake --help,然後雙擊Tab會有命令提示)得到你的CMake支援的模組的列表:

cmake version 2.8.12.2
AddFileDependencies
BundleUtilities
CMakeAddFortranSubdirectory
CMakeBackwardCompatibilityCXX
CMakeDependentOption
CMakeDetermineVSServicePack
CMakeExpandImportedTargets
CMakeFindFrameworks
CMakeFindPackageMode
CMakeForceCompiler
CMakeGraphVizOptions
CMakePackageConfigHelpers
CMakeParseArguments
CMakePrintHelpers
CMakePrintSystemInformation
CMakePushCheckState
CMakeVerifyManifest
CPack
CPackBundle
CPackComponent
CPackCygwin
CPackDMG
CPackDeb
CPackNSIS
CPackPackageMaker
CPackRPM
CPackWIX
CTest
CTestScriptMode
CTestUseLaunchers
CheckCCompilerFlag
CheckCSourceCompiles
CheckCSourceRuns
CheckCXXCompilerFlag
CheckCXXSourceCompiles
CheckCXXSourceRuns
CheckCXXSymbolExists
CheckFortranFunctionExists
CheckFunctionExists
CheckIncludeFile
CheckIncludeFileCXX
CheckIncludeFiles
CheckLanguage
CheckLibraryExists
CheckPrototypeDefinition
CheckStructHasMember
CheckSymbolExists
CheckTypeSize
CheckVariableExists
Dart
DeployQt4
Documentation
ExternalData
ExternalProject
FeatureSummary
FindALSA
FindASPELL
FindAVIFile
FindArmadillo
FindBISON
FindBLAS
FindBZip2

...

...

或者直接檢視模組路徑。比如Ubuntu Linux上,模組的路徑是 ls /usr/share/cmake/Modules/:

AddFileDependencies.cmake                                       CPackDeb.cmake                    FindOpenThreads.cmake
AutomocInfo.cmake.in                                            CPackNSIS.cmake                   FindPHP4.cmake
BasicConfigVersion-AnyNewerVersion.cmake.in                     CPackPackageMaker.cmake           FindPNG.cmake
BasicConfigVersion-ExactVersion.cmake.in                        CPackRPM.cmake                    FindPackageHandleStandardArgs.cmake
BasicConfigVersion-SameMajorVersion.cmake.in                    CPackWIX.cmake                    FindPackageMessage.cmake
BundleUtilities.cmake                                           CPackZIP.cmake                    FindPerl.cmake
CMake.cmake                                                     CTest.cmake                       FindPerlLibs.cmake
CMakeASM-ATTInformation.cmake                                   CTestScriptMode.cmake             FindPhysFS.cmake
CMakeASMCompiler.cmake.in                                       CTestTargets.cmake                FindPike.cmake
CMakeASMInformation.cmake                                       CTestUseLaunchers.cmake           FindPkgConfig.cmake
CMakeASM_MASMInformation.cmake                                  CheckCCompilerFlag.cmake          FindPostgreSQL.cmake
CMakeASM_NASMInformation.cmake                                  CheckCSourceCompiles.cmake        FindProducer.cmake
CMakeAddFortranSubdirectory                                     CheckCSourceRuns.cmake            FindProtobuf.cmake

FindBZip2.cmake

...

...

讓我們以bzip2庫為例。CMake中有個 FindBZip2.cmake 模組。只要使用 find_package(BZip2) 呼叫這個模組,cmake會自動給一些變數賦值,然後就可以在CMake指令碼中使用它們了。變數的列表可以檢視cmake模組檔案,或者使用命令 cmake --help-module FindBZip2 :

cmake version 2.8.12.2
  FindBZip2
       Try to find BZip2

       Once done this will define

         BZIP2_FOUND - system has BZip2
         BZIP2_INCLUDE_DIR - the BZip2 include directory
         BZIP2_LIBRARIES - Link these to use BZip2
         BZIP2_NEED_PREFIX - this is set if the functions are prefixed with BZ2_
         BZIP2_VERSION_STRING - the version of BZip2 found (since CMake 2.8.8)

       Defined in: /usr/share/cmake-2.8/Modules/FindBZip2.cmake

比如一個使用bzip2的簡單程式,編譯器需要知道 bzlib.h 的位置,連結器需要找到bzip2庫(動態連結的話,Unix上是 libbz2.so 類似的檔案,Windows上是 libbz2.dll )。

cmake_minimum_required(VERSION 2.8)
project(helloworld)
add_executable(helloworld hello.c)
find_package (BZip2)
if (BZIP2_FOUND)
  include_directories(${BZIP_INCLUDE_DIRS})
  target_link_libraries (helloworld ${BZIP2_LIBRARIES})
endif (BZIP2_FOUND)

可以用 cmake 和 make VERBOSE=1 來驗證傳給編譯器和連結器的flag是否正確。也可以用ldd或者dependency walker之類的工具在編譯後驗證 helloworld 連結的檔案。

假設你想要使用LibXML++庫。在寫本文時,CMake還沒有一個libXML++的查詢模組。但是可以在網上搜索到一個( FindLibXML++.cmake )。在 CMakeLists.txt 中寫:

find_package(LibXML++ REQUIRED)
include_directories(${LibXML++_INCLUDE_DIRS})
set(LIBS ${LIBS} ${LibXML++_LIBRARIES})

如果包是可選的,可以忽略 REQUIRED 關鍵字,通過 LibXML++_FOUND 布林變數來判斷是否找到。檢測完所有的庫後,對於連結目標有:

target_link_libraries(exampleProgram ${LIBS})

為了能正常的工作,需要把 FindLibXML++.cmake 檔案放到CMake的模組路徑(/usr/share/cmake/Modules/)。因為CMake還不包含它,需要在專案中指定。在自己的專案根目錄下建立一個 cmake/Modules/ 資料夾,並且在主 CMakeLists.txt 中包含下面的程式碼:

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/")

把剛才的需要用到的CMake模組放到這個資料夾下。

一般來說就是這樣。有些庫可能還需要些其他的什麼,所以要再看一下 FindSomething.cmake 檔案的文件。

有些庫不是一個整體,還包含一些依賴的庫或者元件。一個典型的例子是Qt庫,它其中包含QtOpenGL和QtXml元件。使用下面的 find_package 命令來使用這些元件:

find_package(Qt COMPONENTS QtOpenGL QtXml REQUIRED)

如果包是可選的,這裡同樣可以忽略 REQUIRED 關鍵字。這時可以使用 <PACKAGE>_<COMPONENT>_FOUND 變數(如Qt_QtXml_FOUND )來檢查元件是否被找到。下面的 find_package 命令是等價的:

find_package(Qt COMPONENTS QtOpenGL QtXml REQUIRED)
find_package(Qt REQUIRED COMPONENTS QtOpenGL QtXml)
find_package(Qt REQUIRED QtOpenGL QtXml)

如果包中的元件有些是必需的,有些不是,可以呼叫 find_package 兩次:

find_package(Qt COMPONENTS QtXml REQUIRED)
find_package(Qt COMPONENTS QtOpenGL)

或者也可以不加 REQUIRED 關鍵字用 find_package 同時查詢全部元件,然後再顯式地檢查必需的元件:

find_package(Qt COMPONENTS QtOpenGL QtXml)
if ( NOT Qt_FOUND OR NOT QtXml_FOUND )
  message(FATAL_ERROR "Package Qt and component QtXml required, but not found!")
endif( NOT Qt_FOUND OR NOT QtXml_FOUND )

pkg-config是個用來幫助構建的工具,它基於記錄庫檔案和標頭檔案位置的 .pc 檔案。主要用在類Unix系統上。可以在pkg-config的網站 找到更多的資訊。CMake可以利用pkg-config,可以在CMake的模組目錄下的 FindPkgConfig.cmake 檔案中找到相關的文件。這在當你處理一個沒有cmake指令碼的庫的時候,或者遇到CMake的查詢指令碼失效的情況,非常有幫助。

但是,直接使用pkg-config的結果需要非常小心。一個主要原因是對於ccmake手動定義的庫路徑,可能覆蓋到或者發生衝突。此外,也有可能pkg-config提供了錯誤的資訊(錯誤的編輯器等)。對於這些情況,讓CMake不依賴pkg-config做檢測,而只用pkg-config作為查詢路徑的提示。

首先,注意傳給 find_package 的名字或者字首,是用於全部變數的部分檔名和字首。這很重要,名字必須完全匹配。不幸的是很多情況下,即使是CMake自帶的模組,也有不匹配的名字,導致各種問題。

模組的基本操作應該大體按下面的順序:

  • 使用 find_package 檢測庫依賴的其他的庫
    • 需要轉發 QUIETLY 和 REQUIRED 引數(比如,如果當前的包是 REQUIRED 的,它的依賴也應該是)
  • 可選地使用pkg-config來檢測 include/library 的路徑(如果pkg-config可用的話)
  • 分別使用 find_path 和 find_library 尋找標頭檔案和庫檔案
    • pkg-config提供的路徑只用來作為查詢位置的提示
    • CMake也有很多其他查詢路徑是寫死的
    • 結果應該儲存在 <name>_INCLUDE_DIR 和 <name>_LIBRARY 變數中(注意不是複數形式)
  • 設定 <name>_INCLUDE_DIRS 到 <name>_INCLUDE_DIR <dependency1>_INCLUDE_DIRS ...
  • 設定 <name>_LIBRARIES 到 <name>_LIBRARY <dependency1>_LIBRARIES ...
    • 依賴使用複數形式,包自身使用 find_path 和 find_library 定義的單數形式
  • 呼叫 find_package_handle_standard_args() 巨集來設定 <name>_FOUND 變數,並列印一條成功或者失敗的訊息
# - Try to find LibXml2
# Once done this will define
#  LIBXML2_FOUND - System has LibXml2
#  LIBXML2_INCLUDE_DIRS - The LibXml2 include directories
#  LIBXML2_LIBRARIES - The libraries needed to use LibXml2
#  LIBXML2_DEFINITIONS - Compiler switches required for using LibXml2

find_package(PkgConfig)
pkg_check_modules(PC_LIBXML QUIET libxml-2.0)
set(LIBXML2_DEFINITIONS ${PC_LIBXML_CFLAGS_OTHER})

find_path(LIBXML2_INCLUDE_DIR libxml/xpath.h
          HINTS ${PC_LIBXML_INCLUDEDIR} ${PC_LIBXML_INCLUDE_DIRS}
          PATH_SUFFIXES libxml2 )

find_library(LIBXML2_LIBRARY NAMES xml2 libxml2
             HINTS ${PC_LIBXML_LIBDIR} ${PC_LIBXML_LIBRARY_DIRS} )

set(LIBXML2_LIBRARIES ${LIBXML2_LIBRARY} )
set(LIBXML2_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR} )

include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LIBXML2_FOUND to TRUE
# if all listed variables are TRUE
find_package_handle_standard_args(LibXml2  DEFAULT_MSG
                                  LIBXML2_LIBRARY LIBXML2_INCLUDE_DIR)

mark_as_advanced(
            
           

相關推薦

find_packageCMake如何查詢連結

如果編譯軟體使用了外部庫,事先並不知道它的標頭檔案和連結庫的位置。得在編譯命令中加上包含它們的查詢路徑。CMake使用 find_package 命令來解決這個問題。本文討論瞭如何在CMake專案中使用外部庫,以及如何給沒有查詢模組的庫寫一個。 1 FIND_PACKAGE FIND_PACKAGE( &l

Linux動態連結那點事兒(`cmake find_package,linux shared library`路徑

Motivation 經常在Linux下面寫C++程式,尤其是需要整合各種第三方庫的工程,肯定對find_package指令不陌生。 這是條很強大的指令。可以直接幫我們解決整個工程的依賴問題,自動把標頭檔案和動態連結檔案配置好。比如說,在Linux下面工程依賴了OpenCV,只需

exp/expdp imp/impdp命令導入導出數據

鏈接 lena attach 64bit lap 路徑 定時 存放位置 traints 一、exp命令導出數據庫 如何使exp的幫助以不同的字符集顯示:set nls_lang=simplified chinese_china.zhs16gbk,通過設置環境變量,可以讓ex

C++靜態動態使用

這次分享的宗旨是——讓大家學會建立與使用靜態庫、動態庫,知道靜態庫與動態庫的區別,知道使用的時候如何選擇。這裡不深入介紹靜態庫、動態庫的底層格式,記憶體佈局等,有興趣的同學,推薦一本書《程式設計師的自我修養——連結、裝載與庫》。 什麼是庫 庫是寫好的現有的,成熟的,可以複用的程式碼。現實中每個程式都要依

自己編寫連結串列函式

標頭檔案 #ifndef _LINKLIST_H #define _LINKLIST_H #define SUCCESS 10000 #define FAILURE 10001 #define TRUE 10002 #define FALSE 10003

CMake如何查詢連結,路徑錯誤

cmake中文實踐指南中,第九章編寫屬於自己的FindHello模組中遇到錯誤。 windows下用CMake如何查詢連結庫,FIND_PATH(HELLO_INCLUDE_DIR hello.h E:\cmake\t3\include)語句出現錯誤,如圖 把反斜槓改為斜

php冒泡排序快速排序實例

lag ++ function 開始 ret light 記錄 php冒泡排序 php $a=array(‘3‘,‘8‘,‘1‘,‘4‘,‘11‘,‘7‘); print_r($a); $len = count($a); //從小到大 for($i=1;$i<$le

3dsmax2014的下載、安裝註冊激活教程

com cor 殺毒 系統 3dmax http 後退 tar 輸入 3dsmax2014的下載、安裝與註冊激活教程,雖然網上類似的教程文章不勝枚舉,但大多比較粗枝大葉,沒有詳細的步驟,尤其對於電腦小白來說,更是不易參考,今天我就教大家如何註冊破解3dsmax2014吧!

UML類圖類的關系--轉

position 好的 -a erp 生命 靜態 pan 雙向 單選 http://www.uml.org.cn/oobject/201104212.asp 原文地址 UML類圖與類的關系詳解 2011-04-21 來源:網絡

C++11 std::chrono

toolbar space max mil exp 值類型 cond 精度 ++i 所謂的詳解只不過是參考www.cplusplus.com的說明整理了一下,因為沒發現別人有詳細講解。   chrono是一個time library, 源於boost,現在已經是C++標準。

mysql數據 之 自學成才1

簡化 註意 可能 方法 after 字符型 專題 mar 建議 一、學習目錄 1.認識數據庫和mysql 2.mysql連接 3.入門語句 4.詳解列類型 5.增刪改查 INSERT INTO 表名(列1,…… 列n) VALUES(值 1,…… 值 n); *(列

TCP協議的3次握手4次揮手過程

進行 發送數據 不存在 信息 隊列 協議 標識 方式 ar9 所謂三次握手(Three-Way Handshake)即建立TCP連接,就是指建立一個TCP連接時,需要客戶端和服務端總共發送3個包以確認連接的建立。所謂四次揮手(Four-Way Wavehand)即終止TCP

css-浮動清除浮動的原理(清除浮動的原理你知道嗎)

alt col ges mage all strong splay height http float元素A的特點: 脫離文檔流 靠向left或right float元素會和塊盒子重疊 準確來說,是塊盒子和A重疊,但塊盒子內容會浮動在A周圍 不會和inline元素重

UML類圖類的關系

enc pla 分享 包含關系 影響 基礎 rem 建模 基本組件 UML類圖與類的關系詳解 在畫類圖的時候,理清類和類之間的關系是重點。類的關系有泛化(Generalization)、實現(Realizati

使用JDBC連接數據

found 註冊 加載驅動 創建數據庫 delete ole red dsta 庫存 JDBC連接數據庫詳細流程 ?創建一個以JDBC連接數據庫的程序,包含7個步驟: 1、加載JDBC驅動程序: 在連接數據庫之前,首先要加載想要連接的數據庫的驅

10.javaweb核心標簽

bean對象 靜態 管理 請求 技術 範例 begin odin url 一、JSTL簡介及在項目中安裝配置 1, 簡介 使用JSTL標簽的目的就是不希望jsp中出現java邏輯代碼 分類 2, JSTL的安裝配置 首先將jar包中的各個標簽庫配置

13.javaweb xml標簽

方便 2.3 http 進行 log 標簽庫 xml文件 for 路徑 一、XML標簽簡介 1, 作用 2, 標簽分類 XPath 路徑標記 查找節點元素示例 2.1<x:out> 2.

Flask(十)flash前臺交互post

ace for pos pre 視圖 bmi temp 做的 輸入 Project name :Flask_Plan templates:templates static:static POST提交方式,首先要有表單 老實去改模板文件吧。 查詢窗口我準備放在頁面最頂上,就改

PHPJava集成開發(一)

new 編程語言 到你 其中 web-inf request 測試 add 輸入 很久以前,有人從www上看到看到天空上一個很亮的亮點,它就是Java語言,與此同時,在另一個地方一位夢想家也看到了一個亮點,它就是PHP。 時間一天天過去,這兩個亮點也變得越來越亮,很快,它

【轉】Quartz.net持久化集群部署開發

疑惑 sum 常用 drive wid res net github hub 轉自:http://www.cnblogs.com/knowledgesea/p/5145239.html 序言 我前邊有幾篇文章有介紹過quartz的基本使用語法與類庫。但是他的執行計劃都是被寫