首先,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。