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.pswp.cn/news/532603.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/532603.shtml
英文地址,請注明出處:http://en.pswp.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…