Linux 編譯運行查找頭文件和庫的順序


前言

linux中在使用gcc進行編譯時,可能會出現找不到相應庫或頭文件的情況,往往讓人十分頭疼。因此,此文描述了庫和頭文件的查找順序和一些注意事項,希望能幫助大家在出錯時能夠快速定位和解決。

頭文件

gcc在編譯時按照如下順序尋找所需要的頭文件:

1.先搜索當前目錄( 這里注意,只有用#include "headfile.h"時才會搜索當前目錄
2.接着搜索-I指定的目錄
3.然后找gcc的環境變量 C_INCLUDE_PATH,CPLUS_INCLUDE_PATH,OBJC_INCLUDE_PATH
4.再找內定目錄: /usr/include, /usr/local/include
5.最后找gcc的一系列自帶目錄,如:

CPLUS_INCLUDE_PATH=/usr/lib/gcc/x86_64-redhat-linux/4.8.5/include

庫文件

gcc在編譯時按照如下順序尋找所需要的庫文件:

1.gcc會去找-L指定的目錄
2.再找gcc的環境變量LIBRARY_PATH
3.再找內定目錄

  • /lib和/lib64
  • /usr/lib 和/usr/lib64
  • /usr/local/lib和/usr/local/lib64

這是當初compile gcc時寫在程序內的

這里有兩個問題:

1.默認情況下,gcc編譯時只會查找相應的頭文件,而不會連接具體的lib。也就是說只要include設置完全,就可以編譯通過。它沒有進一步檢查include中的類和函數有沒有實現,而是在運行時才開始查找。所以就會經常發生編譯可以通過,但運行時卻無法運行,因為在運行時它找不到相關類或者函數的實現。

這時,使用-Wl,--no-undefined參數,如果使用了include文件,連接器卻找不到相應的實現,就會產生錯誤提示。

2.編譯時默認不查找當前目錄,需要使用-L ./指定,例如

運行時動態庫的搜索路徑

動態庫的搜索路徑搜索的先后順序是:

1.編譯目標代碼時指定的動態庫搜索路徑;這是通過gcc的參數-Wl,-rpath=指定。當指定多個動態庫搜索路徑時,路徑之間用冒號分隔
2.環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑
3.配置文件/etc/ld.so.conf中指定的動態庫搜索路徑
4.默認的動態庫搜索路徑/lib, /usr/lib

注意:

1.動態庫搜尋路徑並不包括當前目錄,所以當即使可執行文件和其所需的so文件在同一文件夾,也會出現找不到問題

2.一般不推薦直接修改環境變量,而是修改/etc/ld.so.conf,將相應的路徑添加上,然后ldconfig一下就好

3.ldconfig做的這些東西都與運行程序時有關,跟編譯時一點關系都沒有,編譯的時候還是該加-L就得加,不要混淆了

4.往/lib/usr/lib里面lib,是不用修改/etc/ld.so.conf的,但是完了之后要調一下ldconfig(很重要),不然這個lib會找不到。而往其他目錄加lib,需要修改/etc/ld.so.conf,並且要ldconfig一下。

5.如果確實需要改環境變量,則有以下幾種情況:

  • 臨時修改(關閉shell后失效):若是權限不夠(無法更改/etc/ld.so.conf)或只是想臨時改一下環境變量用於測試,則可以使用export,就是export一個全局變量LD_LIBRARY_PATH,然后運行程序的時候就會去這個目錄中找lib。如:命令行執行:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/user/abc/lib

一般來講這只是一種臨時的解決方案,在沒有權限或臨時需要的時候使用。

  • 修改作用於當前用戶:在.bashrc中設置或者在./bash_profile設置,這對當前用戶生效。記得source ~/.bashrcsource ~/.bash_profile

  • 修改作用於所有用戶:在/etc/profile中設置或在/etc/profile.d/中創建一個自定義的shell(**.sh)腳本,一般推薦使用后者。原因如下:

It's NOT a good idea to change this file unless you know what you are doing. It's much better to create a custom.sh shell script in /etc/profile.d/ to make custom changes to your environment, as this will prevent the need for merging in future updates.

翻譯即:除非您知道自己在做什么,否則更改此文件不是一個好主意。 最好在/etc/profile.d/中創建一個自定義的shell(**.sh)腳本,以對您的環境進行自定義更改,因為這樣可以避免在將來的更新中合並。

  • 最后是關於環境變量的寫法:

如:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/user/abc/lib
或者這樣寫:export LD_LIBRARY_PATH="${LD_LIBRARY_PATH}:/home/user/abc/lib"

要用:隔開,注意要加上$LD_LIBRARY_PATH,避免之前存在的路徑失效,在前則先搜索,在后則后搜索

參考

1.關於開發中常見的編譯器技巧
2.LD_LIBRARY_PATH環境變量設置及Linux動態庫查找方法


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM