cmake 的 find_package


首先,find_package 有兩種模式,一是Module模式一是Config模式

cmake本身不提供任何搜索庫的便捷方法,所有搜索庫並給變量賦值的操作必須由cmake代碼(自己寫的)完成,比如下面將要提到的FindXXX.cmake和XXXConfig.cmake。只不過,庫的作者通常會提供這兩個文件,以方便使用者調用。

兩種搜索模式:(其中 XXX 是模塊的名字)

  • Module模式:搜索CMAKE_MODULE_PATH指定路徑下的FindXXX.cmake文件,執行該文件從而找到XXX庫。其中,具體查找庫並給XXX_INCLUDE_DIRSXXX_LIBRARIES兩個變量賦值的操作由FindXXX.cmake模塊完成。
  • Config模式:搜索XXX_DIR指定路徑下的XXXConfig.cmake文件,執行該文件從而找到XXX庫。其中具體查找庫並給XXX_INCLUDE_DIRSXXX_LIBRARIES兩個變量賦值的操作由XXXConfig.cmake模塊完成。

cmake默認采取Module模式,如果Module模式未找到庫,才會采取Config模式。如果XXX_DIR路徑下找不到XXXConfig.cmake文件,則會找/usr/local/lib/cmake/XXX/中的XXXConfig.cmake文件。總之,Config模式是一個備選策略。通常,庫安裝時會拷貝一份XXXConfig.cmake到系統目錄中,因此在沒有顯式指定搜索路徑時也可以順利找到。

若XXX安裝時沒有安裝到系統目錄,因此無法自動找到XXXConfig.cmake,可以在CMakeLists.txt最前面添加XXX的搜索路徑。

set(Caffe_DIR /home/hzh/projects/Caffe/build)   #添加CaffeConfig.cmake的搜索路徑

為了能支持各種常見的庫和包,CMake自帶了很多模塊。可以通過命令 cmake –help-module-list (輸入cmake –help,然后雙擊Tab會有命令提示)得到你的CMake支持的模塊的列表:直接查看模塊路徑。比如Ubuntu linux上,模塊的路徑是 /usr/share/cmake/Modules/

1、指定 package 搜索輔助文件路徑

list(APPEND CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH}" "${CMAKE_CURRENT_LIST_DIR}/cmake")

set(Caffe_DIR /home/hzh/projects/Caffe/build)   #添加CaffeConfig.cmake的搜索路徑

2、使用 find_package

https://stackoverflow.com/questions/20746936/what-use-is-find-package-if-you-need-to-specify-cmake-module-path-anyway

它會自動查找FindXXX.cmakeXXXConfig.cmake文件。

重要,對Module模式,一般來說,Find<package>.cmake 文件放在自己工程的目錄,工程結構如下:

CMakeLists.txt
cmake/FindFoo.cmake
cmake/FindBoo.cmake

CMakeLists.txt 內容:

list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")
find_package(Foo REQUIRED) # FOO_INCLUDE_DIR, FOO_LIBRARIES
find_package(Boo REQUIRED) # BOO_INCLUDE_DIR, BOO_LIBRARIES

include_directories("${FOO_INCLUDE_DIR}")
include_directories("${BOO_INCLUDE_DIR}")
add_executable(Bar Bar.hpp Bar.cpp)
target_link_libraries(Bar ${FOO_LIBRARIES} ${BOO_LIBRARIES})

請注意,如果系統目錄(一般是 /usr/local/lib/cmake/ )里有一個Find<package>.cmake文件,但你卻不想使用默認的,想自己定義一個Find<package>.cmake,即想讓它繞過默認庫,則你可以指定 CMAKE_MODULE_PATH ,它的優先級比默認路徑要高。

Config模式<package>Config.cmake 一般放在外部目錄下,也就是說這個文件一般是庫的作者寫的,庫被安裝時,該文件被安裝在庫的安裝目錄里,供庫的使用者直接使用(如果未安裝在系統目錄,則使用方法是先設置 XXX_DIR,讓find_package能找得到XXXConfig.cmake)。示例:

foo library:

$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8)
project(Foo)

add_library(foo Foo.hpp Foo.cpp)
install(FILES Foo.hpp DESTINATION include)
install(TARGETS foo DESTINATION lib)
install(FILES FooConfig.cmake DESTINATION lib/cmake/Foo)

Simplified version of config file:

$ cat FooConfig.cmake 
add_library(foo STATIC IMPORTED)
find_library(FOO_LIBRARY_PATH foo HINTS "${CMAKE_CURRENT_LIST_DIR}/../../")
set_target_properties(foo PROPERTIES IMPORTED_LOCATION "${FOO_LIBRARY_PATH}")

By default project installed in CMAKE_INSTALL_PREFIX directory:

$ cmake -H. -B_builds
$ cmake --build _builds --target install
-- Install configuration: ""
-- Installing: /usr/local/include/Foo.hpp
-- Installing: /usr/local/lib/libfoo.a
-- Installing: /usr/local/lib/cmake/Foo/FooConfig.cmake

創建好Foo庫之后,如何使用Foo庫:

Use find_package(... CONFIG) to include FooConfig.cmake with imported target foo:

$ cat CMakeLists.txt 
cmake_minimum_required(VERSION 2.8)
project(Boo)

# import library target `foo`
find_package(Foo CONFIG REQUIRED)

add_executable(boo Boo.cpp Boo.hpp)
target_link_libraries(boo foo)
$ cmake -H. -B_builds -DCMAKE_VERBOSE_MAKEFILE=ON $ cmake --build _builds Linking CXX executable Boo /usr/bin/c++ ... -o Boo /usr/local/lib/libfoo.a

 

 

INSTALL 指令

代碼編譯后直接make install安裝。

介紹一個新的cmake 指令 INSTALL 和一個非常有用的變量CMAKE_INSTALL_PREFIX。 CMAKE_INSTALL_PREFIX變量類似於configure腳本的 –prefix,常見的使用方法看 起來是這個樣子:

cmake -DCMAKE_INSTALL_PREFIX=/usr .

INSTALL指令包含了各種安裝類型,我們需要一個個分開解釋:

目標文件的安裝

INSTALL(TARGETS targets...
        [[ARCHIVE|LIBRARY|RUNTIME]
                   [DESTINATION <dir>]
                   [PERMISSIONS permissions...]
                   [CONFIGURATIONS
        [Debug|Release|...]]
                   [COMPONENT <component>]
                   [OPTIONAL]
                ] [...])

目標類型也就相對應的有三種,ARCHIVE特指靜態庫,LIBRARY特指動態庫,RUNTIME特指可執行目標二進制。參數中的TARGETS后面跟的就是我們通過ADD_EXECUTABLE或者ADD_LIBRARY定義的目標文件,可能是可執行二進制、動態庫、靜態庫。

DESTINATION定義了安裝的路徑,如果路徑以/開頭,那么指的是絕對路徑,這時候 CMAKE_INSTALL_PREFIX其實就無效了。如果你希望使用CMAKE_INSTALL_PREFIX來定義安裝路徑,就要寫成相對路徑,即不要以/開頭,那么安裝后的路徑就是${CMAKE_INSTALL_PREFIX}/<destination定義的路徑>。

舉個例子:

INSTALL(TARGETS myrun mylib mystaticlib
       RUNTIME DESTINATION bin
       LIBRARY DESTINATION lib
       ARCHIVE DESTINATION libstatic
)

上面的例子會將:

可執行二進制myrun安裝到${CMAKE_INSTALL_PREFIX}/bin目錄。
動態庫libmylib安裝到${CMAKE_INSTALL_PREFIX}/lib目錄。
靜態庫libmystaticlib安裝到${CMAKE_INSTALL_PREFIX}/libstatic目錄。
特別注意的是你不需要關心TARGETS具體生成的路徑,只需要寫上TARGETS名稱就可以了。

普通文件的安裝

INSTALL(FILES files... DESTINATION <dir>
         [PERMISSIONS permissions...]
         [CONFIGURATIONS [Debug|Release|...]]
         [COMPONENT <component>]
         [RENAME <name>] [OPTIONAL])
#可用於安裝一般文件,並可以指定訪問權限,文件名是此指令所在路徑下的相對路徑。
#如果默認不定義權限PERMISSIONS,安裝后的權限為,OWNER_WRITE,OWNER_READ,
#GROUP_READ,和WORLD_READ,即644權限。

非目標文件的可執行程序安裝(比如腳本之類)

INSTALL(PROGRAMS files... DESTINATION <dir>
     [PERMISSIONS permissions...]
     [CONFIGURATIONS [Debug|Release|...]]
     [COMPONENT <component>]
     [RENAME <name>] [OPTIONAL])

跟上面的FILES指令使用方法一樣,唯一的不同是安裝后權限為:
OWNER_EXECUTE, GROUP_EXECUTE, 和WORLD_EXECUTE,即755權限

目錄的安裝

INSTALL(DIRECTORY dirs... DESTINATION <dir>
     [FILE_PERMISSIONS permissions...]
     [DIRECTORY_PERMISSIONS permissions...]
     [USE_SOURCE_PERMISSIONS]
     [CONFIGURATIONS [Debug|Release|...]]
     [COMPONENT <component>]
     [[PATTERN <pattern> | REGEX <regex>]
      [EXCLUDE] [PERMISSIONS permissions...]] [...])

這里主要介紹其中的DIRECTORY、PATTERN以及PERMISSIONS參數。
DIRECTORY后面連接的是所在Source目錄的相對路徑,但務必注意:
abc和abc/有很大的區別。 abc意味着abc這個目錄會安裝在目標路徑下;abc/意味着abc這個目錄的內容會被安裝在目標路徑下。PATTERN用於使用正則表達式進行過濾, PERMISSIONS用於指定PATTERN過濾后的文件權限。

看一個例子:

INSTALL(DIRECTORY icons scripts/ DESTINATION share/myproj
        PATTERN "CVS" EXCLUDE
        PATTERN "scripts/*"
        PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
        GROUP_EXECUTE GROUP_READ)

這條指令的執行結果是:

將icons目錄安裝到 <prefix>/share/myproj,將scripts/中的內容安裝到 <prefix>/share/myproj。
不包含目錄名為CVS的目錄,對於scripts/*文件指定權限為 OWNER_EXECUTE 不包含目錄名為CVS的目錄,對於scripts/*文件指定權限為 OWNER_EXECUTE OWNER_WRITE OWNER_READ GROUP_EXECUTE GROUP_READ。

 


免責聲明!

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



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