因为项目目前采用的程序和库的构建方式是把所有的库和可执行程序都安装到/opt/xxx/1.0.1/bin 或者/opt/xxx/1.0.1/lib 以及/opt/xxx/1.0.1/include目录下。但这种写死的方式肯定是不太合适的,因此有必要掌握常用的其他安装方式,比如说我们安装了OpenCV等常用库,它们会安装到何处,怎么使用它们。
基于Cmake编译的C++工程常见的一种第三方库文件的使用方式是find_package()函数,在使用时还是挺方便的。但是如何构建自己的模块并安装到系统中,在独立的项目中使用find_packag()来使用这个包,相关介绍比较少(网上大多是在相同的包中构建了test程序,并没有做到独立工程中使用find_package()来引用该包)。例如,从网上使用一些别人写好的库,大概步骤是先下载下来,在库的源文件夹中使用如下命令安装:
cd <libABC_path>
mkdir build
cd build
cmake ..
make
sudo make install
通过上面的一系列命令就把这个库安装到系统里了。如果我们在写其他C程序中调用了该库,那么我们就需要在编译该程序的CMakeLists中写如:
find_package(libABC REQUIRED)
1.find_package()
如果程序中使用了外部库,事先并不知道它的头文件和链接库的位置,就要给出头文件和链接库的查找方法,并将他们链接到程序中。
find_package(<name> [major.minor] [QUIET] [NO_MODULE]
[[REQUIRED|COMPONENTS] [componets...]])
find_package()的查找路径
find_package()命令首先会在模块路径中寻找 一个事先编译好的FindXXX.cmake文件,而且一般官方给出了很多,不需要自己编写这是查找库的一个典型方式。具体查找路径依次为CMake:
模块模式
- ${CMAKE_MODULE_PATH}中的所有目录。
- 模块目录 /share/cmake-x.y/Modules/ 。
配置模式
- ~/.cmake/packages/或/usr/local/share/中的各个包目录中查找,寻找<库名字的大写>Config.cmake 或者 <库名字的小写>-config.cmake (比如库Opencv,它会查找/usr/local/share/OpenCV中的OpenCVConfig.cmake或opencv-config.cmake)。
首先是查找路径的根目录。我把几个重要的默认查找根目录总结如下:
<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH
其中,PATH中的路径如果以bin或sbin结尾,则自动回退到上一级目录。找到根目录后(根目录作为下面的<prefix>),cmake会检查这些目录下的
<prefix>/(lib/<arch>|lib|share)/cmake/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/ (U)
<prefix>/(lib/<arch>|lib|share)/<name>*/(cmake|CMake)/ (U)
cmake找到这些目录后,会开始依次找<package>Config.cmake或Find<package>.cmake文件。找到后即可执行该文件并生成相关链接信息。
现在回过头来看查找路径的根目录。我认为最重要的一个是PATH。由于/usr/bin/在PATH中,cmake会自动去/usr/(lib/<arch>|lib|share)/cmake/<name>*/寻找模块(因为/usr/bin以bin结尾,所以自动回退到/usr/下作为根目录),这使得绝大部分我们直接通过apt-get安装的库可以被找到。
另外一个比较重要的是<package>_DIR。我们可以在调用cmake时将这个目录传给cmake。由于其优先级最高,因此cmake会优先从该目录中寻找,这样我们就可以随心所欲的配置cmake使其找到我们希望它要找到的包。而且除上述指定路径外,cmake还会直接进入<package>_DIR下寻找。如我在3rd_parties目录下编译了一个OpenCV(使用find_package时查找的包名是OpenCV),那么执行cmake时可以使用
OpenCV_DIR=../../3rd-party/opencv-3.3.4/build/ cmake ..
这样做以后,cmake会优先从该目录寻找OpenCV。
*.cmake文件定义变量
不管使用哪一种模式,只要找到.cmake,.cmake里面都会定义下面这些变量:
<NAME>_FOUND
<NAME>_INCLUDE_DIRS or <NAME>_INCLUDES
<NAME>_LIBRARIES or <NAME>_LIBRARIES or <NAME>_LIBS
<NAME>_DEFINITIONS
注意大部分包的这些变量中的包名是全大写的,如 LIBFOO_FOUND ,有些包则使用包的实际大小写,如 LibFoo_FOUND
添加头文件与链接库文件
如果找到这个包,则可以通过在工程的顶层目录中的CMakeLists.txt 文件添加 include_directories(XXX_INCLUDE_DIRS) 来包含库的头文件,添加target_link_libraries(源文件 _LIBRARIES)命令将源文件与库文件链接起来。
链接OpenCV的例子
创建t4目录添加cmake目录与main.cpp与CMakeList.txt文件
创建cmake目录添加FindOpenCV.cmake文件。
CMakeList.txt
cmake_minimum_required(VERSION 2.8)
PROJECT (HELLO)
SET(SRC_LIST main.cpp)
INCLUDE_DIRECTORIES(cmake)
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
#在${CMAKE_MODULE_PATH}中添加包含FindOpenCV.cmake目录
FIND_PACKAGE(OpenCV)
#获取OPENCV_FOUND OPENCV_INCLUDE_DIR OPENCV_LIBRARIES
INCLUDE_DIRECTORIES(${OPENCV_INCLUDE_DIR})
ADD_EXECUTABLE(hello ${SRC_LIST})
TARGET_LINK_LIBRARIES(hello ${OPENCV_LIBRARIES})
上述介绍了find_package的用法,以及find_package查找的路径和示例。但是怎么才能自己写一个模块,然后像OpenCV那样装到系统中给其他人用呢?
2.自定义模块
构建并安装自定义模块
首先建立一个文件夹cmake_tutorial1,在其中建立四个文件夹src include cmake_modules build,建立一个文件CMakeLists.txt。src用来放程序源文件,include用来放头文件,cmake_modules用来放描述模块的和安装相关的配置文件,稍后再解释。

在include中建立一个文件叫test_install.h,该源文件内容很简单。
#include <iostream>
class Print{
public:
void PrintHelloWorld();
};
定义了一个类,拥有一个print HelloWorld的函数。自然,在src中我们实现那个函数,在src中建立一个文件test_install.cpp,内容如下
#include <test_install.h>
void Print::PrintHelloWorld(){
std::cout<<"hello world "<<std::endl;
}
在cmake_modules中的几个文件分别叫做FindPackage.cmake, cmake_uninstall.cmake.in, install_package.cmake, PackageConfig.cmake.in, PackageConfigVersion.cmake.in, PkgConfig.pc.in。这些文件都是些毛啊?其实我也没有去关心他们具体的内容是什么,但是可以直接使用来他们安装我们的库,库不同也不用做什么修改,他们就好像CMake的自己的库。
FindPackage.cmake
SET( @PACKAGE_PKG_NAME@_LIBRARIES @PACKAGE_LINK_LIBS@ CACHE INTERNAL "@PACKAGE_PKG_NAME@ libraries" FORCE )
SET( @PACKAGE_PKG_NAME@_INCLUDE_DIRS @PACKAGE_INCLUDE_DIRS@ CACHE INTERNAL "@PACKAGE_PKG_NAME@ include directories" FORCE )
SET( @PACKAGE_PKG_NAME@_LIBRARY_DIRS @PACKAGE_LINK_DIRS@ CACHE INTERNAL "@PACKAGE_PKG_NAME@ library directories" FORCE )
mark_as_advanced( @PACKAGE_PKG_NAME@_LIBRARIES )
mark_as_advanced( @PACKAGE_PKG_NAME@_LIBRARY_DIRS )
mark_as_advanced( @PACKAGE_PKG_NAME@_INCLUDE_DIRS )
PackageConfig.cmake.in
SET( @PACKAGE_PKG_NAME@_LIBRARIES "@PACKAGE_LINK_LIBS@" CACHE INTERNAL "@PACKAGE_PKG_NAME@

最低0.47元/天 解锁文章
1341

被折叠的 条评论
为什么被折叠?



