cmake集成第三方庫


https://ukabuer.me/blog/manage-deps-with-cmake

https://zhuanlan.zhihu.com/p/102050750

 

  1. add_subdirectory(thirdParty/abc_path  ${DEPS_PATH}/libs)   #添加第三方被依賴項目Cmake及庫的安裝路徑

   # add_library(abc_static STATIC ${abc_SRCS})  #生成的第三方庫

 

  1. add_executable(xxx_server ${SRC_LIST})

TARGET_LINK_LIBRARIES( abc_static )    #把第三方庫連接進去

 


 

在 C/C++ 項目中使用第三方庫有兩種方式:

  1. 第三方庫在項目外部單獨構建:從庫的官網或是系統包管理程序上下載預編譯好的包,或者事先在項目外部的其他路徑下使用庫的源碼進行編譯
  2. 第三方庫的構建集成到項目的構建過程里,從源碼開始編譯

 

第一種方式對外部環境編譯的要求是不確定的,很可能會打擊構建項目的積極性,畢竟並不是所有的平台/發行版/系統版本都能輕松完成各種庫的編譯和安裝。但這種方式很適合編譯時間久或者工具鏈復雜的第三方庫,比如說 Qt、V8、OSPRay 等。

第二種方式對開發者比較友好,簡單粗暴的實現方式是使用 Git Submodule 拉取依賴源碼,或者編寫一些腳本管理第三方庫。 但如果是使用 CMake 作為構建系統的項目,我們可以利用 CMake 的 FetchContent 模塊來管理依賴。 FetchCotent 是 CMake 3.11 版本開始引入的依賴管理模塊,和其他方式相比主要有以下幾個優點:

  1. 支持 Git Clone、下載源碼壓縮包等多種方式獲取代碼
  2. 可以處理依賴樹中存在的重復依賴
  3. 在 CMake Configure 階段拉取代碼,build 階段編譯代碼,符合 CMake 原有機制,減少了執行多個命令的麻煩
  4. 用 CMake 一套工具控制一切編譯、安裝任務

上面提到了兩種使用第三方庫的方式,在 CMake 項目中還可以分出兩種子情況,即第三方庫是否也使用 CMake 作為構建系統,下面就介紹如何處理這四種情況。

1、第三方庫使用 CMake, 並集成到項目的構建過程里

這種情況可以使用FetchContent模塊獲取第三方庫的源碼,核心函數只有兩個:FetchContent_DeclareFetchContent_Populate,前者用於聲明信息,后者用於下載代碼

下面的例子聲明了兩個依賴,AAA 和 bbb:

include(FetchContent) # 引入該CMake模塊 FetchContent_Declare( # 聲明依賴的相關信息 AAA GIT_REPOSITORY https://github.com/AAA/AAA.git GIT_TAG v1.0.0 GIT_SHALLOW TRUE # 不拉取完整歷史,相當於`git clone --depth=1` ) FetchContent_Declare( bbb URL https://bbb.com/v2.0.0/bbb.tar.gz HASH qwerty # 可選,確保文件的正確性 )

但僅聲明不會有代碼被下載,還需要執行FetchContent_Populate才能使代碼能在 Configure 階段被下載,下載前也可以設置一些變量對子 CMake 項目進行控制:

set(AAA_BUILD_TESTS OFF) # 設置好變量用於關掉AAA項目的測試 FetchContent_GetProperties(AAA) if(NOT AAA_POPULATED) # 確保只拉取一次 FetchContent_Populate(AAA) # 此函數執行后將設置AAA_POPULATED變量 # fetchContent通過AAA_SOURCE_DIR和AAA_BINARY_DIR就可以拿到源碼所在目錄的路徑以及編譯產物的目標路徑  # 此外還有其他變量可以用,見CMake FetchContent文檔 add_subdirectory(${AAA_SOURCE_DIR} ${AAA_BINARY_DIR}) endif () FetchContent_GetProperties(bbb) if(NOT bbb_POPULATED) FetchContent_Populate(bbb) add_subdirectory(${bbb_SOURCE_DIR} ${bbb_BINARY_DIR}) endif ()

add_subdirectory后,AAA 項目的 target 都會進入到當前項目的作用域里,使用target_link_libraries即可完成關聯。 (如果不了解 target 的概念,可以看我的另一篇文章:現代 CMake 的設計理念和使用。)

AAA_POPULATED這個變量會被FetchContent_Populate設置,可以用於確保同名依賴只被拉取一次。 因此當依賴樹中存在同名的重復依賴時,最先被拉取的將會覆蓋其他的版本。 假設上面的 AAA 和 bbb 兩個依賴,同時使用FetchContent_Declare聲明依賴了不同版本的 Ccc。如果 AAA 項目先執行FetchContent_Populate,則最終 Ccc 項目會使用 AAA 項目中定義的版本。 除此之外,我們還可以在聲明 AAA 和 bbb 兩個依賴前,提前 populate 特定版本的 Ccc,就可以實現版本的覆蓋。

順帶一提,所有使用 FetchContent 模塊下載的源碼相關目錄都在 build 目錄下的_deps文件夾里。

2、第三方庫未使用 CMake,將其集成到項目的構建過程里

使用的第三方庫不一定使用了 CMake,或者使用不是現代 CMake。這些情況下利用FetchContent_GetProperties可以拿到依賴庫的各種目錄,結合 CMake 的其他命令完成各種操作。

比如Eigen這個 header-only 庫,雖然使用了 CMake,但項目中測試相關的 target 過多,並且難以方便的禁用,我們可以在拿到源代碼路徑后自己創建一個簡單的 target

include(FetchContent) FetchContent_Declare( eigen3 URL https://gitlab.com/libeigen/eigen/-/archive/3.3.7/eigen-3.3.7.tar.bz2 URL_MD5 b9e98a200d2455f06db9c661c5610496 ) FetchContent_GetProperties(eigen3) if (NOT eigen3_POPULATED) FetchContent_Populate(eigen3) endif () add_library(eigen INTERFACE) target_include_directories(eigen INTERFACE ${eigen3_SOURCE_DIR})

還有很多使用 make 作為編譯工具的項目,我們可以通過拿到源碼目錄后,使用add_custom_commandadd_custom_target原地編譯,並創建一個簡單的 imported target。 這里以uWebSockets為例,這個庫本身是 header-only 的,但使用 Git Submodules 依賴了一個使用 make 的子項目 uSockets:

# 常規操作,declare后polulate
include(FetchContent) FetchContent_Declare( uWebSockets-git GIT_REPOSITORY https://github.com/uNetworking/uWebSockets.git GIT_TAG v18 ) FetchContent_GetProperties(uWebSockets-git) if (NOT uWebSockets-git_POPULATED) FetchContent_Populate(uWebSockets-git) endif () # 創建一個命令用於編譯出uSockets的靜態庫,並且創建好頭文件目錄 add_custom_command( OUTPUT ${uWebSockets-git_SOURCE_DIR}/uSockets/uSockets.a COMMAND cp -r src uWebSockets && make WORKING_DIRECTORY ${uWebSockets-git_SOURCE_DIR} COMMENT "build uSockets" VERBATIM ) # 創建一個自定義target,依賴上面自定義命令的OUTPUT,但這樣CMake還不會編譯這個target,還需要一個真正的target依賴此target add_custom_target(uSockets DEPENDS ${uWebSockets-git_SOURCE_DIR}/uSockets/uSockets.a) # 創建一個imported target,依賴上面的自定義target,從而確保在使用這個imported target時,上面的編譯命令能被執行 add_library(uWebSockets STATIC IMPORTED) set_property(TARGET uWebSockets PROPERTY IMPORTED_LOCATION ${uWebSockets-git_SOURCE_DIR}/uSockets/uSockets.a) set_target_properties( uWebSockets PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${uWebSockets-git_SOURCE_DIR};${uWebSockets-git_SOURCE_DIR}/uSockets/src" ) add_dependencies(uWebSockets uSockets) # 見上面add_custom_target的說明

總之當拿到源碼目錄后,可以結合 CMake 的其他命令完成各種操作,畢竟我們需要的可以只有頭文件和鏈接庫文件。

3、第三方庫使用 CMake,在項目外部構建

一個靠譜的 CMake Library 項目應該在 install package 時提供xxx-config.cmake或者XXXConfig.cmake文件,其中包含項目相關的 imported target, 或者設置鏈接庫路徑等 CMake 變量。 (具體怎么做可以參考 CMake 官方的這個教程: Adding Export Configuration (Step 11),或者這篇更詳細的指導:Tutorial: Easily supporting CMake install and find_package())

這種情況下可以使用find_package命令來尋找依賴。假設庫的名稱為Aaa,調用find_package(Aaa 1.0.0)時,CMake 會嘗試在/usr/lib/cmake默認路徑下尋找Aaa-config.cmake或者AaaConfig.cmake,這個文件可以放在以Aaa*為前綴的文件夾下來支持多版本並存。(Linux 用戶可以執行ls /usr/lib/cmake看看)

當然,這個第三方庫不一定就安裝在默認路徑,那么用戶可以設置Aaa_DIR這個變量,用於提示 CMake 應該去哪里尋找 config 文件。 在找到該文件后,Aaa_FOUND變量會被設置,同時 config 文件中包含的 target 以及 CMake 變量都會存在於fink_packge之后的的作用域里,可以按需使用。

4、第三方庫未使用 CMake,在項目外部構建

現實並不總是那么美好,第三方庫安裝時可能沒有提供 config 文件,比如使用make作為構建工具的項目。

我們可以直接使用find_pathfind_library兩個命令來尋找頭文件以及鏈接庫所在的路徑,CMake 會嘗試到默認路徑下尋找, 但同樣的,庫不一定被安裝在默認路徑下,於是我們可以允許使用一個變量來提示位置:

# 可以設置POCO_INCLUDE_DIR這個變量進行路徑的提示
find_path( POCO_INCLUDE_PATH NAMES Poco.h Poco/Poco.h HINTS ${POCO_INCLUDE_DIR} "${CMAKE_PREFIX_PATH}/include" ) # 可以設置POCO_LIB_DIR這個變量進行路徑的提示 find_library( POCO_FOUNDATION_LIB NAMES PocoFoundation HINTS ${POCO_LIB_DIR} "${CMAKE_PREFIX_PATH}/lib" )

在找到頭文件以及鏈接庫后,我們可以直接用,或者創建個 imported target 使用。

add_library(Poco)STATIC IMPORTED) set_property(TARGET Poco PROPERTY IMPORTED_LOCATION ${POCO_FOUNDATION_LIB}) set_target_properties( Poco PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${POCO_INCLUDE_DIR} )

更優雅的方式是向 CMake 提供一個FindXxx.cmake腳本,其中可以使用各種方法(比如find_pathfind_library)找到庫,並並導出庫的信息。

上一節提到find_package(Aaa 1.0.0)會去尋找 config 文件,這個描述實際上並不完整。 find_packageMODULECONFIG兩種模式,MODULE模式尋找FindXxx.cmake文件,CONFIG模式尋找 config 文件。 如果像本文里沒有指定模式,CMake 優先按MODULE模式尋找庫,沒找到的話 fallback 到CONFIG模式。(詳見Basic Signature and Module Mode)。兩者一個重要的區別在於,config 腳本由庫的開發者提供,find 腳本由使用者提供。

很多基於 make 構建工具的第三方庫都可以在網上可以找到 find 腳本,同時 CMake 官方也為我們寫好了很多常用庫的Find 腳本,比如 OpenGL, JPEG, ZLIB,對於這些庫無需編寫 find 腳本直接使用find_package就可以了。

尋找 find 腳本時,CMake 會優先到CMAKE_MODULE_PATH變量對應的路徑找,隨后是 CMake 自帶的 find 腳本目錄。 如果我們准備好了某個庫的 find 腳本,可以把其所在的目錄加到CMAKE_MODULE_PATH里,這樣find_package就能找到他。

list(APPEND CMAKE_MODULE_PATH "./cmake/") find_package(MyLib) if (MyLib_FOUND) # ...

5、創建對下游友好的 CMake 項目

目前想到了下面這幾點,對於最佳實踐的追求總是沒有盡頭的,但希望大家可以一起建設更友好的 C/C++ 開發生態:

  1. 使用基於 target 的現代 CMake
  2. 作為庫的開發者,在預編譯的 package 里提供 config 腳本
  3. 代碼倉庫里不要放太多代碼無關的大文件,避免下載時間過長
  4. 打好版本 tag,方便控制版本

 


https://zhuanlan.zhihu.com/p/60479441

CMake的find_package指令用於查找並載入一個外部包的設置。

基本調用形式和模塊模式

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

查找並載入一個外部包的設置。查找是否成功可以通過<PackageName>_FOUND變量的值得到。成功查找到包后,我們就可以導入包中的目標。使用QUIET選項可以不顯示查詢過程中產生的信息,比如如果沒有使用REQUIRED選項,即使包沒有被找到,也不會顯示任何信息。使用REQUIRED選項后,如果包沒有被找到,就會產生一個錯誤信息,中斷處理。

對於必須的包組件可以在COMPONENTS選項后列出(如果使用了REQUIRED選項,也可以在REQUIRED選項后列出)。對於可選的包組件可以在OPTIONAL_COMPONENTS選項后列出。包自身定義了可用的包組件和包被認為找到的條件。

[version]選項用於指定要查找的包的版本(版本格式為major[.minor[.patch[.tweak]]])。使用EXACT選項后,查找的包的版本需要和指定的版本准確匹配。如果沒有使用[version]選項,沒有給出需要的包組件列表,就會使用外部調用的相應參數(包括[version]的EXACT選項)。

find_package指令有兩種查找包的模式:一種是模塊(Module)模式,一種是配置(Config)模式。默認情況下,首先使用模塊(Module)模式,如果沒有找到對應的模塊(Module),就會使用配置(Config)模式。如果使用了MODULE選項,使用模塊模式失敗后,不會繼續使用配置(Config)模式。

模塊(Module)模式下,CMake會搜索一個名為Find<PackageName>.cmake。首先使用CMAKE_MODULE_PATH中的路徑搜索,然后搜索CMake自帶的Find模塊。找到Find<PackageName>.cmake后,CMake會讀取處理這個文件。這個文件包含了要查找的包的信息。

完整調用形式和配置模式

一般而言,用戶只需要使用find_package指令的基本調用形式即可。find_package指令的完整調用形式主要是用來對搜索過程進行更加准確詳細的設置。

find_package指令的完整調用形式如下:

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選項或它的同義詞NO_MODULE選項,以及其它沒有在find_package的基本調用形式中出現的選項都會強制find_package指令直接使用配置(Config)模式,跳過模塊模式處理。

配置模式下,CMake會搜索一個由包提供的配置文件。

指令返回后,<PackageName>_DIR變量保存了包含這一配置文件的目錄名。

默認情況下,find_package指令使用<PackageName>作為包名進行搜索。

如果使用了NAMES選項,就會使用NAMES選項后的列表中的名稱作為包名搜索<PackageName>Config.cmake文件/<package-name>-config.cmake 文件。

可以使用CONFIGS選項替換使用的配置文件名稱。找到配置文件后,配置文件會被CMake讀取並執行。配置文件是由包自身提供,所以具備了包的所有信息。配置文件的完整路徑會被存儲在<PackageName>_CONFIG變量中。

在搜索過程中所有被查找過的可能被使用的包的配置文件會被存儲在<PackageName>_CONSIDERED_CONFIGS變量中,包的版本會被存儲在<PackageName>_CONSIDERED_VERSIONS變量中。

如果最后沒有找到包的配置文件,並且沒有使用QUIET選項,那么CMake就會產生一條描述這一錯誤的信息。

如果使用了REQUIRED選項,包沒有被找到就會導致CMake產生一個致命錯誤,中斷處理。如果<PackageName>_DIR變量已經被設置為一個不包含包配置文件的目錄,CMake會忽略掉它,重新開始搜索。

包配置文件應該被安裝在下面的搜索過程小節提到的搜索路徑來方便查找。

 

包名大小寫無關

message("gflags_CONFIG: ${gflags_CONFIG}")
message("GFLAGS_CONFIG: ${gflags_CONFIG}")
message("gflags_INCLUDE_DIR: ${GFLAGS_INCLUDE_DIR}")
message("GFLAGS_LIB: ${GFLAGS_LIB}")

 

版本選擇

配置模式下,如果使用了[version]選項,將會搜索與指定的版本相匹配的包(版本格式為major[.minor[.patch[.tweak]]])。如果使用了EXACT選項,則會搜索與指定版本准確匹配的包。CMake沒有對版本號有任何約定。包的版本號由包自身提供的版本文件得到。對於一個候選的包配置文件<config-file>.cmake,它對應的版本文件<config-file>-version.cmake/<config-file>Version.cmake在同一目錄下。如果對應的版本文件不存在,包配置文件假設包與任何指定的版本都不匹配。可以使用CMakePackageConfigHelpers模塊創建一個最基本的版本文件。版本文件找到后,會被讀取用來檢測包的版本號。版本文件會被在一個包含了以下變量的內部作用域下讀取執行:

  • PACKAGE_FIND_NAME:<PackageName>
  • PACKAGE_FIND_VERSION:完整的版本字符串
  • PACKAGE_FIND_VERSION_MAJOR:主版本號,如果沒有指定則為0
  • PACKAGE_FIND_VERSION_MINOR:次版本號,如果沒有指定則為0
  • PACKAGE_FIND_VERSION_PATCH:補丁版本號,如果沒有指定則為0
  • PACKAGE_FIND_VERSION_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指令返回后不可用。如果包的版本可以被接收,下面這些變量會被設置:

  • <PackageName>_VERSION:包的完整版本字符串
  • <PackageName>_VERSION_MAJOR:主版本號,如果沒有提供則為0
  • <PackageName>_VERSION_MINOR:次版本號,如果沒有提供則為0
  • <PackageName>_VERSION_PATCH:補丁版本號,如果沒有提供則為0
  • <PackageName>_VERSION_TWEAK:調整版本號,如果沒有提供則為0
  • <PackageName>_VERSION_COUNT:使用的版本號數量,值為0到4

當多個包配置文件匹配指定的包版本時,如果沒有設置CMAKE_FIND_PACKAGE_SORT_ORDER變量進行排序,哪一個包被選定是未定義的,

使用CMAKE_FIND_PACKAGE_SORT_ORDER和CMAKE_FIND_PACKAGE_SORT_DIRECTION變量可以控制find_package指令的檢測順序。比如,為了選擇版本最高的包,可以在調用find_package指令前按照下面這樣設置:

SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL) SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)

搜索過程

CMake包含了一組前綴用於查找安裝的包。這一組前綴之后連接了多個用於查找配置文件的目錄。下面列出了這些目錄。W代表在Windows下使用,U代表在UNIX下使用,A代表在Apple下使用的目錄:

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

對於macOS系統,會使用下面的目錄搜索配置文件:

<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>(大小寫無關)對應我們在find_package指令中指定的名稱(<PackageName>和使用NAMES選項指定的名稱)。

如果設置了CMAKE_LIBRARY_ARCHITECTURE變量,就會啟用lib/<arch>這一搜索路徑。lib*包含了類似lib64、lib32、libx32和lib(按這一順序搜索)這些值:

  • 如果FIND_LIBRARY_USE_LIB64_PATHS變量被設置為TRUE,會啟用lib64搜索路徑。
  • 如果FIND_LIBRARY_USE_LIB32_PATHS變量被設置為TRUE,會啟用lib32搜索路徑。
  • 如果FIND_LIBRARY_USE_LIBX32_PATHS變量被設置為TRUE,會啟用libx32搜索路徑。
  • lib搜索路徑總是被使用。

如果使用了PATH_SUFFIXES選項,指定的后綴會被加到W和U類型目錄名稱之后。

這一組目錄主要用於和在安裝樹中提供了配置文件的程序進行協作。

上面標記了W的目錄主要用於Windows系統,通常是程序的安裝目錄。標記了U的目錄主要用於UNIX系統,通常是系統的默認包目錄。

但實際上標記了W和U的目錄會被所有平台搜索。標記了A的目錄主要用於蘋果平台。CMAKE_FIND_FRAMEWORK和CMAKE_FIND_APPBUNDLE變量決定了蘋果平台的搜索順序。

這一組目錄的前綴由下面得到。

如果使用了NO_DEFAULT_PATH選項,那么所有NO_*選項都會被啟用。

1.CMake變量<PackageName>_ROOT和環境變量<PackageName>_ROOT中指定的搜索路徑(<PackageName>是要搜索的包名)。

包的root路徑變量以棧的形式維護,如果沒有使用NO_PACKAGE_ROOT_PATH選項,在一個搜索模塊中調用find_package指令,來自搜索模塊的root路徑也會被搜索。

 

2.CMake的隱含變量指定的搜索路徑。主要是在命令行上使用-DVAR=value來指定。指定的搜索路徑以分號分割。可以使用NO_CMAKE_PATH選項跳過這一搜索路徑:

CMAKE_PREFIX_PATH CMAKE_FRAMEWORK_PATH CMAKE_APPBUNDLE_PATH

 

3.使用CMake的環境變量指定的搜索路徑。主要來自用戶的終端配置,指定的搜索路徑以原生的路徑分隔符(在Windows上是;,在UNIX上是:)進行分割。可以使用NO_CMAKE_ENVIRONMENT_PATH跳過這一搜索路徑:

<PackageName>_DIR CMAKE_PREFIX_PATH CMAKE_FRAMEWORK_PATH CMAKE_APPBUNDLE_PATH

 

4.使用HINTS選項指定的搜索路徑。這一搜索路徑通常由計算得到。比如使用一個已有信息作為搜索路徑的提示。

如果要使用硬編碼的路徑信息應該使用PATHS選項

 

5.系統的環境變量指定的搜索路徑。使用NO_SYSTEM_ENVIRONMENT_PATH選項可以跳過這一搜索路徑。路徑中以/bin和/sbin結尾的目錄會被自動轉換為它們的父目錄:

PATH

 

6.CMake的用戶包注冊表指定的搜索路徑。使用NO_CMAKE_PACKAGE_REGISTRY選項或設置CMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY變量為TRUE可以跳過這一搜索路徑。

 

7.當前系統平台的CMake變量指定的搜索路徑。使用NO_CMAKE_SYSTEM_PATH可以跳過這一搜索路徑:

CMAKE_SYSTEM_PREFIX_PATH CMAKE_SYSTEM_FRAMEWORK_PATH CMAKE_SYSTEM_APPBUNDLE_PATH

 

8.CMake的系統包注冊表指定的搜索路徑。使用NO_CMAKE_SYSTEM_PACKAGE_REGISTRY選項或設置CMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRY變量為TRUE可以跳過這一搜索路徑。

 

9.使用PATHS選項指定的搜索路徑。也就是硬編碼的搜索路徑。

使用CMake變量CMAKE_FIND_ROOT_PATH可以指定一個或多個目錄作為其它搜索路徑的前綴。使用它我們可以重定位整個搜索路徑。使用CMAKE_STAGING_PREFIX變量衍生的搜索路徑是一個系統平台特定路徑,不會被重定位。默認情況下,CMAKE_FIND_ROOT_PATH變量的值為空。

使用CMAKE_SYSROOT變量也可以指定一個搜索路徑前綴。

這些變量對於跨平台編譯有很大的作用。默認情況下,CMake首先使用CMAKE_FIND_ROOT_PATH中的路徑,然后使用CMAKE_SYSROOT中的路徑,接着使用非根路徑。可以通過設置CMAKE_FIND_ROOT_PATH_MODE_PACKAGE變量調整這一默認搜索方式。可以使用下面這些選項針對單個find_package指令進行控制:

  • CMAKE_FIND_ROOT_PATH_BOTH:按照上面的描述進行搜索。
  • NO_CMAKE_FIND_ROOT_PATH:不使用CMAKE_FIND_ROOT_PATH變量進行搜索。
  • ONLY_CMAKE_FIND_ROOT_PATH:只搜索重定位的目錄和 CMAKE_STAGING_PREFIX變量衍生的目錄。

默認情況下的搜索順序滿足大多數使用場景。一般情況下,我們只需要使用NO_*類選項多次調用find_package指令就可以按照我們的要求來搜索包

find_package (<PackageName> PATHS paths... NO_DEFAULT_PATH) find_package (<PackageName>)

上面的兩次find_package指令只要有一次成功找到了包,就不會再次搜索這個包。

默認情況下,存儲在結果變量中的值是最后找到的文件路徑。在使用find_package指令前設置CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS變量的值為TRUE,可以將找到的符號鏈接解析為真實的文件路徑。

通過設置CMAKE_DISABLE_FIND_PACKAGE_<PackageName>變量為TRUE可以讓非REQUIRED的find_package指令調用失效。

包文件接口變量

載入一個搜索模塊或包配置文件時,find_package指令設置了一些有關調用參數的變量(find_package指令調用返回后,這些變量會被還原):

  • CMAKE_FIND_PACKAGE_NAME:搜索的包名
  • <PackageName>_FIND_REQUIRED:如果使用了REQUIRED選項,值為TRUE
  • <PackageName>_FIND_QUIETLY:如果使用了QUIET選項,值為TRUE
  • <PackageName>_FIND_VERSION:搜索的包的完整版本字符串
  • <PackageName>_FIND_VERSION_MAJOR:包的主版本號,如果沒有指定則為0
  • <PackageName>_FIND_VERSION_MINOR:包的次版本號,如果沒有指定則為0
  • <PackageName>_FIND_VERSION_PATCH:包的補丁版本號,如果沒有指定則為0
  • <PackageName>_FIND_VERSION_TWEAK:包的調整版本號,如果沒有指定則為0
  • <PackageName>_FIND_VERSION_COUNT:包使用的版本數量,值為0到4
  • <PackageName>_FIND_VERSION_EXACT:如果使用了EXACT選項,值為TRUE
  • <PackageName>_FIND_COMPONENTS:搜索的包的組件
  • <PackageName>_FIND_REQUIRED_<c>:如果組件<c>被指定為必須,值為TRUE。如果組件<c>是可選的,值為FALSE

在模塊(Module)模式下,被加載的搜索模塊負責查找滿足這些信息的包。在配置(Config)模式下,find_package指令會自動處理REQUIRED、QUIET和[version]選項,然后讓包配置文件自己處理組件需求。包配置文件通過設置<PackageName>_FOUND變量為FALSE表明組件需求不能夠被滿足。

 

  if(MINGW)
    option(WITH_GFLAGS "build with GFlags" OFF)
  else()
    option(WITH_GFLAGS "build with GFlags" ON)
  endif()
  set(GFLAGS_LIB)
  if(WITH_GFLAGS)
    # set(gflags_ROOT /home/gitSrc/google/gflags-2.2.0)
    set(gflags_DIR /home/gitSrc/google/gflags-2.2.0/build)
    # Config with namespace available since gflags 2.2.2
    option(GFLAGS_USE_TARGET_NAMESPACE "Use gflags import target with namespace." ON)
    find_package(gflags CONFIG
        PATHS /home/gitSrc/google/gflags-2.2.0
        NO_DEFAULT_PATH)
    if(gflags_FOUND)
      message("=======gflags found========")
      if(TARGET ${GFLAGS_TARGET})
        # Config with GFLAGS_TARGET available since gflags 2.2.0
        set(GFLAGS_LIB ${GFLAGS_TARGET})
      else()
        # Config with GFLAGS_LIBRARIES available since gflags 2.1.0
        set(GFLAGS_LIB ${gflags_LIBRARIES})
      endif()
    else()
      message("=======gflags not found========")
      find_package(gflags REQUIRED
          PATHS /home/gitSrc/google/gflags-2.2.0
          NO_DEFAULT_PATH)
      set(GFLAGS_LIB gflags::gflags)
    endif()
    include_directories(${GFLAGS_INCLUDE_DIR})
    list(APPEND THIRDPARTY_LIBS ${GFLAGS_LIB})
    add_definitions(-DGFLAGS=1)
    message("gflags_CONFIG: ${gflags_CONFIG}")
    message("GFLAGS_CONFIG: ${gflags_CONFIG}")
    message("gflags_INCLUDE_DIR: ${GFLAGS_INCLUDE_DIR}")
    message("GFLAGS_LIB: ${GFLAGS_LIB}")
  endif()



CMake Error at CMakeLists.txt:142 (find_package):
  Could not find a package configuration file provided by "gflags" with any
  of the following names:

    gflagsConfig.cmake
    gflags-config.cmake

  Add the installation prefix of "gflags" to CMAKE_PREFIX_PATH or set
  "gflags_DIR" to a directory containing one of the above files.  If "gflags"
  provides a separate development package or SDK, be sure it has been
  installed.



set(gflags_DIR /home/gitSrc/google/gflags-2.2.0/build)  #有gflagsconfig.cmake的直接路徑

  

find_package(gflags REQUIRED
  PATHS /home/gitSrc/google/gflags-2.2.0
  COMPONENTS static   #使用靜態庫
  NO_DEFAULT_PATH)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM