经常在Linux下面写C++程序,尤其是需要集成各种第三方库的工程,肯定对find_package指令不陌生。

这是条很强大的指令。可以直接帮我们解决整个工程的依赖问题,自动把头文件和动态链接文件配置好。比如说,在Linux下面工程依赖了OpenCV,只需要下面几行就可以完全配置好:

add_executable(my_bin src/my_bin.cpp)

find_package(OpenCV REQUIRED)

include_directories(${OpenCV_INCLUDE_DIRS})

target_link_libraries(my_bin, ${OpenCV_LIBS})

工作流程如下:

find_package在一些目录中查找OpenCV的配置文件。

找到后,find_package会将头文件目录设置到${OpenCV_INCLUDE_DIRS}中,将链接库设置到${OpenCV_LIBS}中。

设置可执行文件的链接库和头文件目录,编译文件。

到现在为止出现了第一个问题。那就是:

find_package会在哪些目录下面寻找OpenCV的配置文件?

find_package目录

为什么我们要知道这个问题呢?因为很多库,我们都是自己编译安装的。比如说,电脑中同时编译了OpenCV2和OpenCV3,我该如何让cmake知道到底找哪个呢?

其实这个问题在CMake官方文档中有非常详细的解答。

首先是查找路径的根目录。我把几个重要的默认查找目录总结如下:

_DIR

CMAKE_PREFIX_PATH

CMAKE_FRAMEWORK_PATH

CMAKE_APPBUNDLE_PATH

PATH

其中,PATH中的路径如果以bin或sbin结尾,则自动回退到上一级目录。

找到根目录后,cmake会检查这些目录下的

/(lib/|lib|share)/cmake/*/

/(lib/|lib|share)/*/

/(lib/|lib|share)/*/(cmake|CMake)/

cmake找到这些目录后,会开始依次找Config.cmake或Find.cmake文件。找到后即可执行该文件并生成相关链接信息。

现在回过头来看查找路径的根目录。我认为最重要的一个是PATH。由于/usr/bin/在PATH中,cmake会自动去/usr/(lib/|lib|share)/cmake/*/寻找模块,这使得绝大部分我们直接通过apt-get安装的库可以被找到。

另外一个比较重要的是_DIR。我们可以在调用cmake时将这个目录传给cmake。由于其优先级最高,因此cmake会优先从该目录中寻找,这样我们就可以随心所欲的配置cmake使其找到我们希望它要找到的包。而且除上述指定路径外,cmake还会直接进入_DIR下寻找。如我在3rd_parties目录下编译了一个OpenCV,那么执行cmake时可以使用

OpenCV_DIR=../../3rd-party/opencv-3.3.4/build/ cmake ..

这样做以后,cmake会优先从该目录寻找OpenCV。