本文介紹在linux中標頭檔案的搜尋路徑,也就是說你通過include指定的標頭檔案,linux下的gcc編譯器它是怎麼找到它的呢。在此之前,先了解乙個基本概念。
標頭檔案是一種文字檔案,使用文字編輯器將**編寫好之後,以副檔名.h儲存就行了。標頭檔案中一般放一些重複使用的**,例如函式宣告、變數宣告、常數定義、巨集的定義等等。當使用#include語句將標頭檔案引用時,相當於將標頭檔案中所有內容,複製到#include處。#include有兩種寫法形式,分別是:
#include <> : 直接到系統指定的某些目錄中去找某些標頭檔案。
#include 「」 : 先到原始檔所在資料夾去找,然後再到系統指定的某些目錄中去找某些標頭檔案。
#include檔案可能會帶來乙個問題就是重複應用,如a.h引用的乙個函式是某種實現,而b.h引用的這個函式卻是另外一種實現,這樣在編譯的時候將會出現錯誤。所以,為了避免因為重複引用而導致的編譯錯誤,標頭檔案常具有:
#ifndef label
#define label
//**部分
#endif
的格式。其中label為乙個唯一的標號,命名規則跟變數的命名規則一樣。常根據它所在的頭檔名來命名,例如,如果標頭檔案的檔名叫做hardware.h,那麼可以這樣使用:
#ifndef __hardware_h__
#define __hardware_h__
//**部分
#endif
這樣寫的意思就是,如果沒有定義__hardware_h__,則定義__hardware_h__,並編譯下面的**部分,直到遇到#endif。這樣當重複引用時,由於__hardware_h__已經被定義,則下面的**部分就不會被編譯了,這樣就避免了重複定義。
一句話,標頭檔案事實上只是把一些常用的命令整合在裡面,你要用到哪方面的命令就載入哪個標頭檔案就可以了。
gcc尋找標頭檔案的路徑(按照1->2->3的順序)
1. 在gcc編譯原始檔的時候,通過引數-i指定標頭檔案的搜尋路徑,如果指定路徑有多個路徑時,則按照指定路徑的順序搜尋標頭檔案。命令形式如:「gcc -i /path/where/theheadfile/in sourcefile.c「,這裡原始檔的路徑可以是絕對路徑,也可以是相對路徑。eg:
設當前路徑為/root/test,include_test.c如果要包含標頭檔案「include/include_test.h「,有兩種方法:
1) include_test.c中#include 「include/include_test.h」或者#include "/root/test/include/include_test.h",然後gcc include_test.c即可
2) include_test.c中#include 或者#include ,然後gcc –i include include_test.c也可
2. 通過查詢gcc的環境變數c_include_path/cplus_include_path/objc_include_path來搜尋標頭檔案位置。
3. 再找內定目錄搜尋,分別是
/usr/include
/usr/local/include
/usr/lib/gcc-lib/i386-linux/2.95.2/include
最後一行是gcc程式的庫檔案位址,各個使用者的系統上可能不一樣。
gcc在預設情況下,都會指定到/usr/include資料夾尋找標頭檔案。
gcc還有乙個引數:-nostdinc,它使編譯器不再系統預設的頭檔案目錄裡面找標頭檔案,一般和-i聯合使用,明確限定標頭檔案的位置。在編譯驅動模組時,由於非凡的需求必須強制gcc不搜尋系統預設路徑,也就是不搜尋/usr/include要用引數-nostdinc,還要自己用-i引數來指定核心標頭檔案路徑,這個時候必須在makefile中指定。
4. 當#include使用相對路徑的時候,gcc最終會根據上面這些路徑,來最終構建出頭檔案的位置。如#include 就是包含檔案/usr/include/sys/types.h
1)elf可執行檔案中動態段中dt_rpath所指定的路徑。即在編譯目標**時, 對gcc加入鏈結引數「-wl,-rpath」指定動態庫搜尋路徑,eg:gcc -wl,-rpath,/home/arc/test,-rpath,/lib/,-rpath,/usr/lib/,-rpath,/usr/local/lib test.c
2)環境變數ld_library_path 指定的動態庫搜尋路徑
3)/etc/ld.so.cache中所快取的動態庫路徑,這個可以通過先修改配置檔案/etc/ld.so.conf中指定的動態庫搜尋路徑,然後執行ldconfig命令來改變。
4)預設的動態庫搜尋路徑/lib
5)預設的動態庫搜尋路徑/usr/lib
另外:在嵌入式linux系統的實際應用中,1和2被經常使用,也有一些相對簡單的的嵌入式系統會採用4或5的路徑來規範動態庫,3在嵌入式系統中使用的比較少, 因為有很多系統根本就不支援ld.so.cache。
那麼,動態鏈結器ld.so在這五種路徑中,是按照什麼樣的順序來搜尋需要的動態共享庫呢?答案這裡先告知就是按照上面的順序來得,即優先順序是:1-->2-->3-->4-->5。我們可以寫簡單的程式來證明這個結論。
首先,寫成5個函式,這5個函式名稱都叫pt,但是裡面的內容不一樣:
pt1.c
#include
void pt(){
printf("1 path on the gcc give \n");
pt2.c
#include
void pt(){
printf("2 path on the ld_library_path \n");
pt3.c
#include
void pt(){
printf("3 path on the /etc/ld.so.conf \n");
pt4.c
#include
void pt(){
printf("4 path on the /lib \n");
pt5.c
#include
void pt(){
printf("5 path on the /usr/lib \n");
然後,分別編譯這5個函式,然後將它們分別移到上面5種情況對應的5個不同目錄下:
gcc -fpic -c pt1.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/1/
gcc -fpic -c pt2.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/2/
gcc -fpic -c pt3.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /tmp/st/3/
gcc -fpic -c pt4.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /lib/
gcc -fpic -c pt5.c -o pt.o
gcc -shared pt.o -o libpt.so
mv libpt.so /usr/lib/
再次,編寫乙個main函式m,讓它來呼叫函式pt:
m.c
#include
int main(){
printf("start....\n");
pt();
printf("......end\n");
return 0;
最後,準備環境,讓ld都知道這5個路徑:
(a) 往/etc/ld.so.conf總增加一行,內容:/tmp/st/3,然後執行 ldconfig 命令
(b) export ld_library_path=/tmp/st/2
另外3中路徑,ld都可以得到,請接著看下面。
之後測試:
gcc m.c -o m1 -l/tmp/st/1 -lpt -wl,-rpath,/tmp/st/1
./m1
start....
1 path on the gcc give
......end
這裡在可執行檔案中動態段中dt_rpath所指定的路徑,因此需要在編譯m.c的時候就指定路徑,由於其他路徑都也告訴了ld,很明顯,此種方法優先順序最高了。
gcc m.c -o m -l/tmp/st/1 -lpt
./mstart....
2 path on the ld_library_path
......end
這裡很顯然呼叫了ld_library_path指定了路徑中的共享庫,因此此種情況優先順序第二。
mv /tmp/st/2/libpt.so /tmp/st/2/libpt2.so
/mstart....
3 path on the /etc/ld.so.conf
......end
這裡是呼叫了/etc/ld.so.cache中所快取的動態庫路徑中的共享庫,因此此種情況優先順序第三。
mv /tmp/st/3/libpt.so /tmp/st/3/libpt3.so
./mstart....
4 path on the /lib
......end
這裡是呼叫/lib中的共享庫,優先順序第四。
rm /lib/libpt.so
./mstart....
5 path on the /usr/lib
......end
這裡是呼叫/lib中的共享庫,優先順序第五。
故證明這五種路徑指定方法的優先順序是1-->2-->3-->4-->5!
Linux C 常用標頭檔案
sys types.h 資料型別定義 sys socket.h 提供socket函式及資料結構 netinet in.h 定義資料結構sockaddr in netdb.h 提供設定及獲取網域名稱的函式 sys ioctl.h 提供對i o控制的函式 sys poll.h 提供socket等待測試機...
Linux C常用的標頭檔案
原文出處 忘了 下的,只是在自己的文件找到 一些標頭檔案的作用 ansi c 提供斷言,assert 表示式 gcc。gtk,gnome 的基礎庫,提供很多有用的函式,如有資料結構操作函式。使?胓lib 只需要包含 gcc。資料夾操作函式。struct dirent,struct dir,opend...
Linux C語言標頭檔案搜尋路徑
本文介紹在linux中標頭檔案的搜尋路徑,也就是說你通過include指定的標頭檔案,linux下的gcc編譯器它是怎麼找到它的呢。在此之前,先了解乙個基本概念。標頭檔案是一種文字檔案,使用文字編輯器將 編寫好之後,以副檔名.h儲存就行了。標頭檔案中一般放一些重複使用的 例如函式宣告 變數宣告 常數...