首先,find_package 有兩種模式,一是Module模式,一是Config模式。
cmake本身不提供任何搜索庫的便捷方法,所有搜索庫並給變量賦值的操作必須由cmake代碼(自己寫的)完成,比如下面將要提到的FindXXX.cmake和XXXConfig.cmake。只不過,庫的作者通常會提供這兩個文件,以方便使用者調用。
兩種搜索模式:(其中 XXX 是模塊的名字)
- Module模式:搜索CMAKE_MODULE_PATH指定路徑下的FindXXX.cmake文件,執行該文件從而找到XXX庫。其中,具體查找庫並給XXX_INCLUDE_DIRS和XXX_LIBRARIES兩個變量賦值的操作由FindXXX.cmake模塊完成。
- Config模式:搜索XXX_DIR指定路徑下的XXXConfig.cmake文件,執行該文件從而找到XXX庫。其中具體查找庫並給XXX_INCLUDE_DIRS和XXX_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
它會自動查找FindXXX.cmake或XXXConfig.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。