在終端中輸入 gcc 文件名 -o 目標文件名
然後 ./目標文件名 就行了,沒有目標文件名,自動存為 a
執行 ./a 就行了。
在使用Gcc編譯器的時候,我們必須給出一系列必要的調用參數和文件名稱。GCC編譯器的調用參數大約有100多個,其中多數參數我們可能根本就用不到,這里只介紹其中最基本、最常用的參數。
GCC最基本的用法是∶gcc [options] [filenames]
其中options就是編譯器所需要的參數,filenames給出相關的文件名稱。
-c,只編譯,不連接成為可執行文件,編譯器只是由輸入的.c等源代碼文件生成.o為後綴的目標文件,通常用於編譯不包含主程序的子程序文件。
-o output_filename,確定輸出文件的名稱為output_filename,同時這個名稱不能和源文件同名。如果不給出這個選項,gcc就給出預設的可執行文件a.out。
-g,產生符號調試工具(GNU的gdb)所必要的符號資訊,要想對源代碼進行調試,我們就必須加入這個選項。
-O,對程序進行優化編譯、連接,採用這個選項,整個源代碼會在編譯、連接過程中進行優化處理,這樣產生的可執行文件的執行效率可以提高,但是,編譯、連接的速度就相應地要慢一些。
-O2,比-O更好的優化編譯、連接,當然整個編譯、連接過程會更慢。
-Idirname,將dirname所指出的目錄加入到程序頭文件目錄列表中,是跡行運在預編譯過程中使用的參數。C程序中的頭文件包含兩種情況∶
A)#include <myinc.h>
B)#include 「myinc.h」
其中,A類使用尖括弧(< >),B類使用雙引號(「 」)。對於A類,預處理程序cpp在系統預設包含文件目錄(如/usr/include)中搜尋相應的文件,而B類,預處理程序在目姿梁標文件的文件夾內搜索相應文件。
GCC執行過程示例
示例代碼 a.c:
#include <stdio.h>
int main()
{
printf("hello\n");
}
預編譯過程:
這個過程處理宏定義和include,並做語法檢查。
可以看到預編譯後,代碼從5行擴帶旦展到了910行。
gcc -E a.c -o a.i
cat a.c | wc -l
5
cat a.i | wc -l
910
編譯過程:
這個階段,生成匯編代碼。
gcc -S a.i -o a.s
cat a.s | wc -l
59
匯編過程:
這個階段,生成目標代碼。
此過程生成ELF格式的目標代碼。
gcc -c a.s -o a.o
file a.o
a.o: ELF 64-bit LSB relocatable, AMD x86-64, version 1 (SYSV), not stripped
鏈接過程:
鏈接過程。生成可執行代碼。鏈接分為兩種,一種是靜態鏈接,另外一種是動態鏈接。使用靜態鏈接的好處是,依賴的動態鏈接庫較少,對動態鏈接庫的版本不會很敏感,具有較好的兼容性;缺點是生成的程序比較大。使用動態鏈接的好處是,生成的程序比較小,佔用較少的內存。
gcc a.o -o a
程序運行:
./a
hello
編輯本段
GCC編譯簡單例子
編寫如下代碼:
#include <stdio.h>
int main()
{
printf("hello,world!\n");
}
執行情況如下:
gcc -E hello.c -o hello.i
gcc -S hello.i -o hello.s
gcc -c hello.s -o hello.o
gcc hello.c -o hello
./hello
hello,world!
㈡ Linux C/C++動態鏈接庫如何版本管理
Linux下的C/C++動態鏈接庫版本管理是開發者常常需要面對的問題,特別是在面對glibc版本不兼容、protocol buffer版本不兼容等場景時,初學者往往感到困惑。
動態鏈接庫的版本管理方式涉及多個層面,首要的是理解版本不兼容的概念,即程序在編譯時依賴特定版本的庫,而運行時環境提供的庫版本不一致,導致程序無法正常啟動或運行時出現錯誤。
動態鏈接庫能夠提高進程間二進制代碼復用,減少可執行文件的體積,但同時也帶來了符號沖突和版本管理的挑戰。在編寫動態庫時,開發者需考慮庫的兼容性問題,以免在更新版本後導致依賴程序運行失敗。
當動態庫更新版本後,如更改了函數名、增加或刪除了功能,與舊版本的程序將無法兼容。此時,若程序運行時找不到更新後的庫版本,就會引發找不到符號的錯誤。這一情況的示例說明了實際項目中版本管理的重要性。
庫兼容的含義在於程序編譯時所依賴的庫版本與運行時動態鏈接器找到的庫版本相匹配,從而確保程序能夠正常運行。庫版本的兼容性包含兩個層面:一是庫的主版本號一致,二是庫中的每個符號版本也需兼容。
在Linux中,動態庫版本通過版本號進行管理,通常由libname.so.x.y.z組成,其中x.y.z分別代表主版本、次版本和補丁版本。通過SONAME欄位,動態鏈接器可以識別庫的版本,並據此與程序進行匹配。
編譯時,開發者通過-l庫名參數指定依賴庫,此時鏈接器ld僅查找庫文件是否存在,而不考慮版本。而動態鏈接器在運行時則會檢查庫的SONAME欄位,以確定實際依賴的庫版本。如果沒有SONAME欄位,則程序依賴庫原始名稱。
考慮到編譯和運行時所需的庫文件名不同,一個動態鏈接庫在安裝後通常包括編譯時使用的libname.so、運行時使用的libname.so.x.y.z以及實際的庫文件libname.x.y.z。符號版本則允許在庫中為每個符號指定版本,這對於提高庫的兼容性和維護性至關重要。
綜上所述,理解動態鏈接庫版本管理是C/C++開發者不可或缺的知識點。通過合理設置庫的版本號、使用SONAME欄位、實現符號版本管理等手段,可以有效解決版本不兼容問題,確保程序的穩定運行。
㈢ Linux下C/C++動態庫在運行時是怎樣載入進來的
在linux上,你在ps中說的那種"將動態庫作為一個參數傳到程序里"的使用方式,是通過dlopen函數將.so載入到當前進程中,並且通過ld.so將.so"鏈接"進當前進程。這個"鏈接"過程包括:查找未定義符號在當前進程中的地址、分配數據/代碼/bss段內存(數據初始化全局變數、代碼段重定位)、執行constructor函數等。之後,可以使用dlsym在已知符號名的情況下通過符號名查找符號對應的地址。這個符號可以是一個全局變數、全局函數等。在你說的C++中,重載的函數也可以理解為全局函數,會有一個屬性為weak的符號。該符號的符號名如果不做修改,默認按照System V的C++ API命名規范命名(以保證linux下不同編譯器編譯出來的.so和.o可以通用)。但如果使用extern "C"修飾之後,變成C的函數名,則無名稱修飾,便於使用。