linux下利用gcc編譯C和C++

gcc ------->默認編譯c文件(gcc  xxx  -lstdc++鏈接到c++庫編譯c++,g++默認編譯c++)


一.CC編譯程序過程分四個階段
◆ 預處理(Pre-Processing)
◆ 編譯(Compiling)
◆ 彙編(Assembling)
◆ 鏈接(Linking)


1.1 預處理(Pre-Processing)


gcc -E test.c -o test.i 或 gcc -E test.c
可以輸出test.i文件中存放着test.c經預處理之後的代碼。打開test.i文件,看一看,就明白了。後面那條指令,是直接在命令行窗口中輸出預處理後的代碼.


gcc的-E選項,可以讓編譯器在預處理後停止,並輸出預處理結果。預處理結果就是將#include等類似的文件中的內容插入到當前文件中。


 


1.2 編譯(Compiling)


預處理之後,可直接對生成的test.i文件編譯,生成彙編代碼:


gcc -S test.i -o test.s
gcc的-S選項,表示在程序編譯期間,在生成彙編代碼後,停止,-o輸出彙編代碼文件。


 


1.3 彙編(Assembling)


對於生成的彙編代碼文件test.s,gas彙編器負責將其編譯爲目標文件,如下:


gcc -c test.s -o test.o
1.4 鏈接(Linking)


gcc連接器是gas提供的,負責將程序的目標文件與所需的所有附加的目標文件連接起來,最終生成可執行文件。附加的目標文件包括靜態連接庫和動態連接庫。


對於上一小節中生成的test.o,將其與C標準輸入輸出庫進行連接,最終生成程序test


gcc test.o -o test
這個程序,一步到位的編譯指令是:


gcc test.c -o test
 


 二:庫文件鏈接


開發軟件時,完全不使用第三方函數庫的情況是比較少見的,通常來講都需要藉助許多函數庫的支持才能夠完成相應的功能。從程序員的角度看,函數庫實際上就是一些頭文件(.h)和庫文件(so、或lib、dll)的集合。。雖然Linux下的大多數函數都默認將頭文件放到/usr/include/目錄下,而庫文件則放到/usr/lib/目錄下;Windows所使用的庫文件主要放在Visual Stido的目錄下的include和lib,以及系統文件夾下。但也有的時候,我們要用的庫不再這些目錄下,所以GCC在編譯時必須用自己的辦法來查找所需要的頭文件和庫文件。(頭文件的路徑用-I,庫文件路徑用-L,比如說-I/usr/myinclude -L/usr/mylib)


-l參數就是用來指定程序要鏈接的庫,-l參數緊接着就是庫名,那麼庫名跟真正的庫文件名有什麼關係呢?就拿數學庫來說,他的庫名是m,他的庫文件名是libm.so,很容易看出,把庫文件名的頭lib和尾.so去掉就是庫名了(把函數庫命名爲“lib“是UNIX的慣例,“.so”是共享文件庫的標準擴展名)


 


2.1 編譯成可執行文件


首先我們要進行編譯test.c爲目標文件,這個時候需要執行


gcc –c –I /usr/dev/mysql/include test.c –o test.o
2.2 鏈接


最後我們把所有目標文件鏈接成可執行文件:


gcc –L /usr/dev/mysql/lib –lmysqlclient test.o –o test
Linux下的庫文件分爲兩大類分別是動態鏈接庫(通常以.so結尾)和靜態鏈接庫(通常以.a結尾),二者的區別僅在於程序執行時所需的代碼是在運行時動態加載的,還是在編譯時靜態加載的。


2.3 強制鏈接時使用靜態鏈接庫


默認情況下, GCC在鏈接時優先使用動態鏈接庫,只有當動態鏈接庫不存在時才考慮使用靜態鏈接庫,如果需要的話可以在編譯時加上-static選項,強制使用靜態鏈接庫。


在/usr/dev/mysql/lib目錄下有鏈接時所需要的庫文件libmysqlclient.so和libmysqlclient.a,爲了讓GCC在鏈接時只用到靜態鏈接庫,可以使用下面的命令:


gcc –L /usr/dev/mysql/lib –static –lmysqlclient test.o –o test
 


靜態庫鏈接時搜索路徑順序:


1. ld會去找GCC命令中的參數-L
2. 再找gcc的環境變量LIBRARY_PATH
3. 再找內定目錄 /lib /usr/lib /usr/local/lib 這是當初compile gcc時寫在程序內的


動態鏈接時、執行時搜索路徑順序:


1. 編譯目標代碼時指定的動態庫搜索路徑
2. 環境變量LD_LIBRARY_PATH指定的動態庫搜索路徑
3. 配置文件/etc/ld.so.conf中指定的動態庫搜索路徑
4. 默認的動態庫搜索路徑/lib
5. 默認的動態庫搜索路徑/usr/lib


有關環境變量:
LIBRARY_PATH環境變量:指定程序靜態鏈接庫文件搜索路徑
LD_LIBRARY_PATH環境變量:指定程序動態鏈接庫文件搜索路徑




總結:源文件首先會生成中間目標文件,再由中間目標文件生成執行文件。在編譯時,編譯器只檢測程序語法,和函數、變量是否被聲明。如果函數未被聲明,編譯器會給出一個警告,但可以生成Object File。而在鏈接程序時,鏈接器會在所有的Object File中找尋函數的實現,如果找不到,那到就會報鏈接錯誤碼

 


三:makefile工具


 make是一個命令工具,是一個解釋makefile中指令的命令工具,make會在當前目錄下找名字叫“Makefile”或“makefile”的文件。make會一層又一層地去找文件的依賴關係(如果該過程文件比生成的目標文件新,需重新編譯),直到最終編譯出第一個目標文件。


Makefile的規則


target ... : prerequisites ...
              command
          ...
          ...


 


 target這一個或多個的目標文件依賴於prerequisites中的文件,其生成規則定義在command中。說白一點就是說,prerequisites中如果有一個以上的文件比target文件要新的話,command所定義的命令就會被執行。這就是Makefile的規則。也就是Makefile中最核心的內容。


3.1 基礎makefile




複製代碼
    target : prerequisites1.o prerequisites2.o prerequisites3.o /
                cc -o target prerequisites1.o prerequisites2.o prerequisites3.o display.o 
    prerequisites1.o : prerequisites1.c prerequisites1.h
            cc -c main.c
    prerequisites2.o : prerequisites1.c prerequisites2.h
            cc -c prerequisites2.c
    prerequisites3.o : prerequisites3.c prerequisites3.h
            cc -c prerequisites3.c
    clean :
             rm target prerequisites1.o prerequisites2.o prerequisites3.o
複製代碼
反斜槓(/)是換行符的意思。在這個makefile中,目標文件(target)包含:中間目標文件(*.o),依賴文件(prerequisites)就是冒號後面的那些 .c 文件和 .h文件。每一個 .o 文件都有一組依賴文件,而這些 .o 文件又是執行文件 target 的依賴文件。依賴關係的實質上就是說明了目標文件是由哪些文件生成的。


在定義好依賴關係後,後續的那一行定義瞭如何生成目標文件的操作系統命令,一定要以一個Tab鍵作爲開頭。make並不管命令是怎麼工作的,他只管執行所定義的命令。make會比較targets文件和prerequisites文件的修改日期,如果prerequisites文件的日期要比targets文件的日期要新,或者target不存在的話,那麼,make就會執行後續定義的命令。


3.2 變量makefile


上例看到編譯目標文件時[.o]文件的字符串被重複了兩次,如果我們的工程需要加入一個新的[.o]文件,那麼我們需要在兩個地方加(應該是三個地方,還有一個地方在clean中)。我們聲明一個變量OBJ等於依賴的[.o]文件,然後在我們的makefile中以“$(objects)”的方式來使用這個變量


3.3 make自動推導


GNU的make很強大,它可以自動推導文件以及文件依賴關係後面的命令,於是我們就沒必要去在每一個[.o]文件後都寫上類似的命令。make看到一個[.o]文件,它就會自動的把[.c]文件加在依賴關係中,如果make找到一個prerequisite1.o,那麼prerequisite1.c,就會是prerequisite1.o的依賴文件。並且 cc -c prerequisite1.c 也會被推導出來。如下代碼:




複製代碼
OBJ = prerequisites1.o prerequisites2.o prerequisites3.o


target : $(OBJ)/
                cc -o target $(OBJ)
    prerequisites1.o : prerequisites1.h
    prerequisites2.o : prerequisites2.h
    prerequisites3.o : prerequisites3.h
    
    .PHONY : clean
    clean :
             rm target $(OBJ)
複製代碼
這種方法,也就是make的“隱晦規則”。上面文件內容中,“.PHONY”表示,clean是個僞目標文件。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章