diff --git a/01. 個人/02. 專注Study/C++/GCC.md b/01. 個人/02. 專注Study/C++/GCC.md index 5059a6d..e5e12ae 100644 --- a/01. 個人/02. 專注Study/C++/GCC.md +++ b/01. 個人/02. 專注Study/C++/GCC.md @@ -5,15 +5,85 @@ gcc可以判斷出目標程序所使用編程語言的類別,會把xxx.c文件 ## 常見文件副檔名 - 目標文件: - - xxx.o:操作系統:Linux, Mac - - xxx.obj, 操作系統:windows + - `xxx.o`:Linux, Mac + - `xxx.obj`:windows - 二進製文件: - - xxx(沒有後綴名), 操作系統:Linux, Mac, FreeBSD, - - xxx.exe, 操作系統:windows - - xxx.hex,操作系統:嵌入式系統 + - `xxx`(沒有副檔名):Linux, Mac, FreeBSD, + - `xxx.exe`:windows + - `xxx.hex`:嵌入式系統 - 共享庫文件,也叫動態庫文件: - - xxx.dll, 操作系統:windows - - xxx.so, 操作系統:Linux - - xxx.dylib, 操作系統:Mac\ + - `xxx.dll`:windows + - `xxx.so`:Linux + - `xxx.dylib`:Mac - 靜態庫文件 - - xxx.a + - `xxx.a` + +## C/C++語言的編譯過程 +1. 預處理 + 預處理命令聲明了編譯時需要的各種頭文件和宏,比如包含哪些頭文件、宏定義的擴展、在哪個代碼段做條件編譯等。涉及預處理的語法有:#define,#include,#ifdef...#endif +2. 編譯 + 首先檢查代碼的規範性和語法錯誤等,檢查完畢後把代碼翻譯成彙編語言,生成彙編語言文件 +3. 彙編 + 基於彙編語言文件生成二進制格式的目標文件 +4. 鏈接 + 將目標代碼與所依賴的庫文件進行關聯或者組裝,合成一個可執行文件 + +具體過程如圖: +![[Pasted image 20220926211701.png]] + +### 拿g++舉例 +1. 樣例代碼: +```cpp +#include + +int main() { +    std::cout << "Hello World!" << std::endl; +    return 0; +} +``` + +2. g++的編譯第一步是預處理:將`xx.cpp`源文件預處理成`xx.i`文件 +```cpp +g++ -E demo.cpp -o demo.i +``` + +3. 第二步是編譯:將`xx.i`文件編譯為`xx.s`的組合語言文件。此時只進行編譯生成組合語言程式碼,而不對代碼以彙編的方式調試 +```js +g++ -S demo.i -o demo.s +``` + +3. 第三步是彙編:將`xx.s`文件彙編成`xx.o`的二進制目標文件 +```cpp +g++ -c demo.s -o demo.o +``` + +4. 第四步是鏈接:將`xx.o`二進製文件進行鏈接,最終生成可執行程序 +```cpp +g++ demo.o -o demo.out +``` + +![[Pasted image 20220926212043.png]] + +## 靜態鏈接和動態鏈接的區別 +### 靜態庫 +與目標程序合併,成為目標程序的一部分。 +創建靜態庫的時候,需要使用`gcc/g++ -c`先將xxx.c源文件編譯為目標文件xxx.o,然後使用`ar`指令將xxx.o打包成xxxx.a靜態庫。 +目標程序與靜態庫鏈接時,目標程序代碼調用的任何外部函數的代碼都會從靜態庫中復製到最終的可執行文件中。 +GCC在鏈接時優先使用動態庫,只有當動態庫不存在時才開始使用靜態庫,如果要強制使用靜態庫,編譯時加上`-static`參數。 +使用`-Wl`、`-Bstatic`告訴鏈接器優先使用靜態庫。 + +### 動態庫 +不包含在目標程序中,但是與目標程序相關聯。 +創建動態庫的時候,可以傳`-shared`和`-fPIC`參數,`-fPIC`參數用於編譯階段,用來生成位置無關的代碼。使用`gcc -shared -fPIC`可以直接用xxx.c源文件生成xxx.so動態庫。 +目標程序與動態庫鏈接時,可執行文件僅包含它所需的一個小函數表,而不是來自庫文件的完整機器代碼。在可執行文件開始運行之前,動態庫的代碼被操作系統複製到內存中進行共享。 +動態庫之所以叫共享庫,可能是由於動態庫的代碼副本可以在多個程序之間共享。正因為這種鏈接方式,共享庫每次被更新時,都不需要重新編譯正在使用共享庫的目標程序。 +使用`-Wl`、`-Bdynamic`告訴鏈接器優先使用動態庫。 + +### 有關的環境變量 +`LIBRARY_PATH`:使用於編譯期間,目標程序鏈接時搜索動態庫的路徑。 +`LD_LIBRARY_PATH`:使用於目標程序生成後,目標程序運行時搜索動態庫的路徑 + +### 靜態庫鏈接時,搜索庫文件路徑的順序 +1. `ld`會去找GCC命令中的參數`-L` +2. gcc的環境變量`LIBRARY_PATH` +3. `/lib`,`/usr/lib`,`/usr/local/lib`等寫在程序內的路徑 \ No newline at end of file diff --git a/attachments/Pasted image 20220926211701.png b/attachments/Pasted image 20220926211701.png new file mode 100644 index 0000000..996c435 Binary files /dev/null and b/attachments/Pasted image 20220926211701.png differ diff --git a/attachments/Pasted image 20220926212043.png b/attachments/Pasted image 20220926212043.png new file mode 100644 index 0000000..5c39bd6 Binary files /dev/null and b/attachments/Pasted image 20220926212043.png differ