cmake添加查找目录_cmake find_package路径详解
Motivation
经常在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/*/ (U)
/(lib/|lib|share)/*/ (U)
/(lib/|lib|share)/*/(cmake|CMake)/ (U)
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。
配置好编译好了以后,我感兴趣的是另一个问题:
我现在编译出了可执行文件,并且这个可执行文件依赖于opencv里的动态库。这个动态库是在cmake时显式给出的。那么,该执行文件在运行时是如何找到这个动态库的?
如果我把可执行文件移动了,如何让这个可执行文件依然能找到动态库?
如果我把该动态库位置移动了,如何让这个可执行文件依然能找到动态库?
如果我把可执行文件复制到别的电脑上使用,我该把其链接的动态库放到新电脑的什么位置?
可执行文件如何寻找动态库
在ld的官方文档中,对这个问题有详尽的描述。The linker uses the following search paths to locate required
shared libraries:
1. Any directories specified by -rpath-link options.
2. Any directories specified by -rpath options. The difference
between -rpath and -rpath-link is that directories specified by
-rpath options are included in the executable and used at
runtime, whereas the -rpath-link option is only effective at
link time. Searching -rpath in this way is only supported by
native linkers and cross linkers which have been configured
with the --with-sysroot option.
3. On an ELF system, for native linkers, if the -rpath and
-rpath-link options were not used, search the contents of the
environment variable "LD_RUN_PATH".
4. On SunOS, if the -rpath option was not used, search any
directories specified using -L options.
5. For a native linker, the search the contents of the environment
variable "LD_LIBRARY_PATH".
6. For a native ELF linker, the directories in "DT_RUNPATH" or
"DT_RPATH" of a shared library are searched for shared
libraries needed by it. The "DT_RPATH" entries are ignored if
"DT_RUNPATH" entries exist.
7. The default directories, normally /lib and /usr/lib.
8. For a native linker on an ELF system, if the file
/etc/ld.so.conf exists, the list of directories found in that
file.
If the required shared library is not found, the linker will issue
a warning and continue with the link.
最重要的是第一条,即rpath。这个rpath会在编译时将动态库绝对路径或者相对路径(取决于该动态库的cmake)写到可执行文件中。chrpath工具可以查看这些路径。
>>> chrpath extract_gpu
extract_gpu: RPATH=/usr/local/cuda/lib64:/home/dechao_meng/data/github/temporal-segment-networks/3rd-party/opencv-3.4.4/build/lib
可以看到,OpenCV的动态库的绝对路径被写到了可执行文件中。因此即使可执行文件的位置发生移动,依然可以准确找到编译时的rpath。
接下来的问题:如果我把可执行文件复制到了别人的电脑上,或者我的动态库文件的目录发生了改变,怎样让可执行文件继续找到这个动态库呢?其实是在第五条:LD_LIBRARY_PATH。只要将存储动态库的目录加入到LD_LIBRARY_PATH中,可执行文件就能正确找到该目录。
这种做法十分常见,比如我们在安装CUDA时,最后一步是在.bashrc中配置
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
这样做之后,依赖cuda的可执行文件就能够正常运行了。
总结
写这篇文章是因为从我第一次使用cmake以来,经常因为动态链接的问题而耽误很长时间。清楚理解find_package的运行机制在Linux的C++开发中是非常重要的,而相关的资料网上又比较稀少。其实官网上解释的非常清楚,不过之前一直没有认真查。做事情还是应该一步一个脚印,将原理搞清楚再放心使用。
Reference
cmake添加查找目录_cmake find_package路径详解相关推荐
- cmake添加查找目录_CMake如何查找库路径(一)
CMake如何查找库路径(一) 如果你的代码使用了外部库(external libraries),并且你事先不知道这些库的头文件和库文件在当前平台的位置.那么适当的文件夹路径和库的搜索路径就应该被添加 ...
- cmake find_package路径详解
cmake find_package路径详解 转自:https://zhuanlan.zhihu.com/p/50829542 经常在Linux下面写C++程序,尤其是需要集成各种第三方库的工程,肯定 ...
- linux 查找目录或文件 (详解)
linux 查找目录或文件 (详解) 查找目录:find /(查找范围) -name '查找关键字' -type d 查找文件:find /(查找范围) -name 查找关键字 -print 如果需 ...
- cmake添加查找目录_CMakeLists.txt文件写法(7):添加查找头文件的路径
[1.List转换成为数组.(这里的List是实体是ArrayList) 调用ArrayList的toArray方法. toArray public T[] toArray(T[] a)返回一个按照正 ...
- linux文件目录:Linux中各目录(文件夹)作用详解(持续更新)
进入Linux系统,我们就是畅游在各种目录文件中,毕竟Linux是"文件系统",文件的存放就是在目录下面,那我们了解下"Linux中各目录(文件夹)作用详解"还 ...
- SpringBoot默认包扫描机制及@ComponentScan指定扫描路径详解
SpringBoot默认包扫描机制及@ComponentScan指定扫描路径详解 SpringBoot默认包扫描机制 标注了@Component和@Component的衍生注解如@Controller ...
- Nginx反向代理、动静分离、负载均衡及rewrite隐藏路径详解(Nginx Apache MySQL Redis)–第二部分...
Nginx反向代理.动静分离.负载均衡及rewrite隐藏路径详解 (Nginx Apache MySQL Redis) 楓城浪子原创,转载请标明出处! 更多技术博文请见个人博客:https://fe ...
- linux如何切换到光盘,怎么刻录cd光盘-Linux切换目录之cd命令详解
请关注本头条号,每天坚持更新原创干货技术文章. 如需学习视频,请在微信搜索公众号"智传网优"直接开始自助视频学习 1. 前言 在Linux cd(切换目录)命令是最重要和最广泛使用 ...
- linux 软链接 相对路径,Linux入门之ln命令创建软链接的绝对路径和相对路径详解(Ubuntu)...
ln命令创建软链接的绝对路径和相对路径详解 简介 ln命令 总结 简介 Linux链接,可以分为硬链接与软链接:本文主要介绍软链接.(默认情况下,ln命令产生硬链接) 软链接文件类似于Windows的 ...
最新文章
- kotlin条件表达式
- 理解Canvas的save()和restore()方法
- JQuery图表插件之Flot
- java线程泄露_面试官:小伙子先来说一下可能引起Java内存泄露的场景吧
- 网站前端设计,从960框架开始
- 普罗米修斯使用es数据库_用普罗米修斯和格拉法纳仪法来豪猪
- (转载)ubuntu开启SSH服务
- catkin_make和cmake
- 安装Ubuntu后必须要做的几件事(一)--基础应用篇
- [密码学]利用docker安装与使用sagemath
- mapinfo二次开发之:MapX和MapXtreme区别
- dismiss和remove_为什么不会在onDestroy或onPause中解雇Dialog,removeDialog或dialog.dismiss工作?...
- 概述、 BGP AS 、BGP 邻居、 BGP 更新源 、BGP TTL 、BGP路由表、 BGP 同步
- 编写一个静态方法lg(),接收一个整型参数N,返回不大于log2N(以2为底)的最大整数。不要使用Math库。
- Windows 系统维护
- 【IEEE_Verilog-4.4】Verilog中的充电强度charge strength和驱动强度drive strength
- Some Enforcer rules have failed. Look above for specific messages explaining why the rule failed.
- 从事网络安全,可以考取什么证书?
- 你有什么道理后悔没早点知道
- 有关面试八股文的一些难点
热门文章
- Reporting Services Internal Error(诡异的问题)-【转载】
- php建一个表按删除就删除,mysql表的清空、删除和修改操作详解
- Android ScrollView用法实例汇总
- 网页内容若使用gzip压缩--获得页面源码
- My first project
- HDU 5536 字典树
- 开发者自述:我是如何从 0 到 1 走进 Kaggle 的
- Office365下部署SharePoint站点集
- Linux Bash命令关于程序调试详解
- C++ 基础 - woaidongmao - C++博客 good 量产