日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

cmake find_package路径详解

發布時間:2025/3/8 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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})

工作流程如下:

  • find_package在一些目錄中查找OpenCV的配置文件。
  • 找到后,find_package會將頭文件目錄設置到${OpenCV_INCLUDE_DIRS}中,將鏈接庫設置到${OpenCV_LIBS}中。
  • 設置可執行文件的鏈接庫和頭文件目錄,編譯文件。
  • 到現在為止出現了第一個問題。那就是:
    find_package會在哪些目錄下面尋找OpenCV的配置文件?

    find_package目錄

    為什么我們要知道這個問題呢?因為很多庫,我們都是自己編譯安裝的。比如說,電腦中同時編譯了OpenCV2和OpenCV3,我該如何讓cmake知道到底找哪個呢?

    其實這個問題在CMake官方文檔中有非常詳細的解答。

    首先是查找路徑的根目錄。我把幾個重要的默認查找目錄總結如下:

    <package>_DIR CMAKE_PREFIX_PATH CMAKE_FRAMEWORK_PATH CMAKE_APPBUNDLE_PATH PATH

    其中,PATH中的路徑如果以bin或sbin結尾,則自動回退到上一級目錄。
    找到根目錄后,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>*/尋找模塊,這使得絕大部分我們直接通過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時顯式給出的。那么,

  • 該執行文件在運行時是如何找到這個動態庫的?
  • 如果我把可執行文件移動了,如何讓這個可執行文件依然能找到動態庫?
  • 如果我把該動態庫位置移動了,如何讓這個可執行文件依然能找到動態庫?
  • 如果我把可執行文件復制到別的電腦上使用,我該把其鏈接的動態庫放到新電腦的什么位置?
  • 可執行文件如何尋找動態庫

    在ld的官方文檔中,對這個問題有詳盡的描述。

    The linker uses the following search paths to locate required
    shared libraries:

  • Any directories specified by -rpath-link options.

  • 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.

  • 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”.

  • On SunOS, if the -rpath option was not used, search any
    directories specified using -L options.

  • For a native linker, the search the contents of the environment
    variable “LD_LIBRARY_PATH”.

  • 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.

  • The default directories, normally /lib and /usr/lib.

  • 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

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

    以上是生活随笔為你收集整理的cmake find_package路径详解的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。