cmake find_package路径详解

cmake find_package路径详解

转自:https://zhuanlan.zhihu.com/p/50829542

经常在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})

工作流程如下:

  1. find_package在一些目录中查找OpenCV的配置文件。
  2. 找到后,find_package会将头文件目录设置到${OpenCV_INCLUDE_DIRS}中,将链接库设置到${OpenCV_LIBS}中。
  3. 设置可执行文件的链接库和头文件目录,编译文件。

到现在为止出现了第一个问题。那就是:
find_package会在哪些目录下面寻找OpenCV的配置文件?

find_package目录

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

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

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

<package>_DIR
CMAKE_PREFIX_PATH
CMAKE_FRAMEWORK_PATH
CMAKE_APPBUNDLE_PATH
PATH

其中,PATH中的路径如果以binsbin结尾,则自动回退到上一级目录。
找到根目录后,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.cmakeFind<package>.cmake文件。找到后即可执行该文件并生成相关链接信息。

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

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

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

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

配置好编译好了以后,我感兴趣的是另一个问题:
我现在编译出了可执行文件,并且这个可执行文件依赖于opencv里的动态库。这个动态库是在cmake时显式给出的。那么,

  1. 该执行文件在运行时是如何找到这个动态库的?
  2. 如果我把可执行文件移动了,如何让这个可执行文件依然能找到动态库?
  3. 如果我把该动态库位置移动了,如何让这个可执行文件依然能找到动态库?
  4. 如果我把可执行文件复制到别的电脑上使用,我该把其链接的动态库放到新电脑的什么位置?

可执行文件如何寻找动态库

在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

  1. https://cmake.org/cmake/help/v3.0/command/find_package.html
  2. https://unix.stackexchange.com/questions/22926/where-do-executables-look-for-shared-objects-at-runtime
  3. https://codeyarns.com/2017/11/02/how-to-change-rpath-or-runpath-of-executable/

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532603.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DVWA File Inclusion——Writeup

文件包含&#xff1a; 即File Inclusion&#xff0c;意思是文件包含&#xff08;漏洞&#xff09;&#xff0c;是指当服务器开启allow_url_include选项时&#xff0c;就可以通过php的某些特性函数&#xff08;include()&#xff0c;require()和include_once()&#xff0c;requi…

PyTorch JIT与TorchScript

PyTorch JIT与TorchScript 转自&#xff1a;https://zhuanlan.zhihu.com/p/370455320 如果搜索 PyTorch JIT&#xff0c;找到的将会是「TorchScript」的文档&#xff0c;那么什么是 JIT 呢&#xff1f;JIT 和 TorchScript 又有什么联系&#xff1f; 文章只会关注概念的部分&a…

DVWA Cross Site Request Forgery (CSRF) -------WP

CSRF: 介绍 CSRF跨站点请求伪造(Cross—Site Request Forgery)&#xff0c;跟XSS攻击一样&#xff0c;存在巨大的危害性&#xff0c;你可以这样来理解&#xff1a; 攻击者盗用了你的身份&#xff0c;以你的名义发送恶意请求&#xff0c;对服务器来说这个请求是完全合法的&…

PyTorch C++ API libtorch 简介

PyTorch C API libtorch 简介 翻译自 PyTorch 官方文档&#xff1a;https://pytorch.org/cppdocs/index.html#acknowledgements 整体划分 根据 PyTorch 官方文档 的介绍&#xff0c;PyTorch的C API可以粗略分为以下五个部分&#xff1a; ATen&#xff1a;基础的张量和数学计…

DVWA upload

LOW medium high impossible

安装 PyTorch C++ API libtorch 及一个最小例子

安装 PyTorch C API libtorch 及一个最小例子 翻译自&#xff1a;https://pytorch.org/cppdocs/installing.html 我们提供依赖 PyTorch 所需的所有头文件、库和 CMake 配置文件的二进制分发版。我们将此发行版称为 LibTorch&#xff0c;您可以在我们的网站上下载包含最新 Lib…

ImageNet 1K 类别名与索引的对应关系

ImageNet 1K 类别名与索引的对应关系 转自&#xff1a;http://befree2008.github.io/2018/10/05/20181005_ImageNet1000%E5%88%86%E7%B1%BB%E5%90%8D%E7%A7%B0%E5%92%8C%E7%BC%96%E5%8F%B7/ ImageNet 2012 1000个类名称和编号。ILSVRC2012_img_train.tar 这个文件解压出来都是…

sqlilab--writeup (5~6) 布尔盲注

1.# 和 – &#xff08;有个空格&#xff09;表示注释&#xff0c;可以使它们后面的语句不被执行。在url中&#xff0c;如果是get请求**(记住是get请求&#xff0c;也就是我们在浏览器中输入的url)** &#xff0c;解释执行的时候&#xff0c;url中#号是用来指导浏览器动作的&am…

PyTorch导出JIT模型并用C++ API libtorch调用

PyTorch导出JIT模型并用C API libtorch调用 本文将介绍如何将一个 PyTorch 模型导出为 JIT 模型并用 PyTorch 的 CAPI libtorch运行这个模型。 Step1&#xff1a;导出模型 首先我们进行第一步&#xff0c;用 Python API 来导出模型&#xff0c;由于本文的重点是在后面的部署…

sqli-lab--writeup(7~10)文件输出,时间布尔盲注

前置知识点&#xff1a; 1、outfile是将检索到的数据&#xff0c;保存到服务器的文件内&#xff1a; 格式&#xff1a;select * into outfile “文件地址” 示例&#xff1a; mysql> select * into outfile ‘f:/mysql/test/one’ from teacher_class; 2、文件是自动创建…

树莓派4B (aarch64) 安装PyTorch 1.8 的可行方案

树莓派4B (aarch64) 安装PyTorch 1.8 的可行方案 最终可行方案 试了一堆方案&#xff08;源码编译、Fast.ai的安装文件等&#xff09;之后&#xff0c;终于找到一个可行的方案。是在 PyTorch 官方讨论社区的一个帖子中找到的&#xff0c;在回复中一个大佬给出了自己在2021年1…

sqli-lab———writeup(11~17)

less11 用户名提交单引号显示sql语法错误&#xff0c;故存在sql注入 根据单引号报错&#xff0c;在用户名和密码任意行输入 万能密码&#xff1a;‘ or 11# 输入后username语句为&#xff1a;SELECT username, password FROM users WHERE username or 11; 双引号 password语…

深入理解Python中的全局解释锁GIL

深入理解Python中的全局解释锁GIL 转自&#xff1a;https://zhuanlan.zhihu.com/p/75780308 注&#xff1a;本文为蜗牛学院资深讲师卿淳俊老师原创&#xff0c;首发自公众号https://mp.weixin.qq.com/s/TBiqbSCsjIbNIk8ATky-tg&#xff0c;如需转载请私聊我处获得授权并注明出处…

sqli-lab————Writeup(18~20)各种头部注入

less18 基于错误的用户代理&#xff0c;头部POST注入 admin admin 登入成功&#xff08;进不去重置数据库&#xff09; 显示如下 有user agent参数&#xff0c;可能存在注入点 显示版本号&#xff1a; 爆库&#xff1a;User-Agent:and extractvalue(1,concat(0x7e,(select …

Python GIL

转自&#xff1a;https://blog.csdn.net/weixin_41594007/article/details/79485847 Python GIL 在进行GIL讲解之前&#xff0c;我们可以先回顾一下并行和并发的区别&#xff1a; 并行&#xff1a;多个CPU同时执行多个任务&#xff0c;就好像有两个程序&#xff0c;这两个程序…

sqli-lab——Writeup21~38(各种过滤绕过WAF和)

Less-21 Cookie Injection- Error Based- complex - string ( 基于错误的复杂的字符型Cookie注入) base64编码&#xff0c;单引号&#xff0c;报错型&#xff0c;cookie型注入。 本关和less-20相似&#xff0c;只是cookie的uname值经过base64编码了。 登录后页面&#xff1a;…

Libtorch报错:terminate called after throwing an instance of ‘c10::Error‘ what():isTensor()INTERNAL ASS

Libtorch报错&#xff1a;terminate called after throwing an instance of ‘c10::Error’ what(): isTensor() INTERNAL ASSERT FAILED 报错 问题出现在笔者想要将 yolov5 通过 PyTorch 的 C 接口 Libtorch 部署到树莓派上。 完整报错信息&#xff1a; terminate called …

sqli-lab——Writeup(38~over)堆叠等......

知识点&#xff1a; 1.堆叠注入原理&#xff08;stacked injection&#xff09; 在SQL中&#xff0c;分号&#xff08;;&#xff09;是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句&#xff0c;会不会一起执行&#xff1f;因此这个想法…

mysql常规使用(建立,增删改查,视图索引)

目录 1.数据库建立 2.增删改查 3.视图建立&#xff1a; 1.数据库建立 mysql> mysql> show databases; ----------------------------------- | Database | ----------------------------------- | information_schema | | ch…

php操作mysql数据库

phpmyadmin phpadmin是一个mysql图形化管理工具&#xff0c;是一款实用php开发的mysql苦户端软件&#xff0c;基于web跨平台的管理系统&#xff0c;支持简体中文&#xff0c;官网&#xff1a;www.phpmyadmin.net可以下载免费最新版。提供图形化操作界面&#xff0c;完成对mysq…