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。

 

posted @ 2020-03-07 13:28  微信公众号--共鸣圈  阅读(2395)  评论(0编辑  收藏  举报