前言
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 ~/.bashrc或source ~/.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,避免之前存在的路徑失效,在前則先搜索,在后則后搜索
