GCC 編譯器介紹
GCC 是一種免費(fèi)的開(kāi)源編譯器,適用于多種編程語(yǔ)言,包括 C、C++、Objective-C、Fortran、Ada 等。開(kāi)源優(yōu)勢(shì)意味任何人都可以根據(jù)自己的需要自由修改和分發(fā) GCC 的源代碼,除開(kāi)源以外,GCC 還有以下幾個(gè)優(yōu)勢(shì):
跨平臺(tái)兼容性
GCC 可以在各種操作系統(tǒng)上運(yùn)行,包括 Linux、macOS 和 Windows。 這可以大幅度提高不同系統(tǒng)上的工作協(xié)同效率。模塊化架構(gòu)
GCC 被設(shè)計(jì)為一個(gè)模塊化系統(tǒng),不同的組件可以根據(jù)用戶的要求進(jìn)行組合或替換。 這種模塊化允許 GCC 支持多種語(yǔ)言和體系結(jié)構(gòu),還允許用戶根據(jù)自己的需要添加或刪除功能。優(yōu)化代碼生成效率
GCC 通過(guò)了循環(huán)展開(kāi)、指令調(diào)度和分支預(yù)測(cè)等多種技術(shù)實(shí)現(xiàn)代碼生成優(yōu)化,使其生成運(yùn)行速度更快且使用更少系統(tǒng)資源的優(yōu)化代碼。遵從行業(yè)標(biāo)準(zhǔn):
GCC 符合各種行業(yè)標(biāo)準(zhǔn),例如 C99 和 C++11 標(biāo)準(zhǔn),使其成為 C 和 C++ 開(kāi)發(fā)的可靠且廣泛接受的選擇。 GCC 還支持對(duì)這些標(biāo)準(zhǔn)的各種擴(kuò)展,允許開(kāi)發(fā)人員編寫(xiě)特定于他們要求的代碼。社區(qū)支持
GCC 擁有龐大而活躍的開(kāi)發(fā)人員和用戶社區(qū),他們?yōu)槠溟_(kāi)發(fā)和維護(hù)做出貢獻(xiàn)。 該社區(qū)為用戶提供支持和資源,使開(kāi)發(fā)人員更容易使用 GCC 并在需要時(shí)獲得幫助。
- Linux 開(kāi)發(fā)C/C++ 一定要熟悉 GCC
- VSCode 是通過(guò)調(diào)用 GCC 編譯器來(lái)實(shí)現(xiàn) C/C++ 的編譯工作的;
實(shí)際使用中:
使用 gcc 指令編譯 C 代碼
使用 g++指令編譯 C++ 代碼
編譯過(guò)程簡(jiǎn)析
- 預(yù)處理 - Pre-Processing // i文件
-E 選項(xiàng)指示編譯器僅對(duì)輸入文件進(jìn)行預(yù)處理
g++ -E main.cpp -o main.i // i文件
2。 編譯 - Compiling // s 文件
-S 編譯選項(xiàng)告訴 g++ 在為 C++ 代碼產(chǎn)生了匯編語(yǔ)言文件后停止編譯,g++ 產(chǎn)生的匯編語(yǔ)言文件的缺省擴(kuò)展名是 .s
g++ -S main.i -o main.s
3。 匯編 - Assembling // .o文件
-c 選項(xiàng)告訴 g++ 僅把源代碼編譯為機(jī)器語(yǔ)言的目標(biāo)代碼,缺省時(shí) g++ 建立的目標(biāo)代碼文件有一個(gè) .o 的擴(kuò)展名
g++ -c main.s -o main.o
4。 鏈接 - Linking // bin 文件
-o 編譯選項(xiàng)來(lái)為將產(chǎn)生的可執(zhí)行文件用指定的文件名
g++ main.o -o main
5。 以上可以綜合為
g++ main.cpp -o main
g++ 重要編譯參數(shù)
-g 編譯帶調(diào)試信息的可執(zhí)行文件
-g 選項(xiàng)告訴 GCC 產(chǎn)生能被 GNU 調(diào)試器 GDB 使用的調(diào)試信息,以調(diào)試程序。
產(chǎn)生帶調(diào)試信息的可執(zhí)行文件 main
g++ -g main.cpp
-O[n] 優(yōu)化源代碼
所謂優(yōu)化,例如省略掉代碼中從未使用過(guò)的變量、直接將常量表達(dá)式用結(jié)果值代替等等,這些操作會(huì)使編譯的速度降低,同時(shí)縮減目標(biāo)文件所包含的代碼量,提高最終生成的可執(zhí)行文件的運(yùn)行效率。
- -O 選項(xiàng)告訴 g++ 對(duì)源代碼進(jìn)行基本優(yōu)化。 這些優(yōu)化在大多數(shù)情況下都會(huì)使程序執(zhí)行的更快,同時(shí)減小代碼的長(zhǎng)度和執(zhí)行時(shí)間,其效果等價(jià)于-O1
- -O0 表示不做優(yōu)化
- -O1 為默認(rèn)優(yōu)化
- -O2 除了完成 -O1 的優(yōu)化之外,還進(jìn)行一些額外的調(diào)整工作,如指令調(diào)整等。
- -O3 則包括循環(huán)展開(kāi)和其他一些與處理特性相關(guān)的優(yōu)化工作。
使用 -O2優(yōu)化源代碼,并輸出可執(zhí)行文件
g++ -O2 main.cpp
-l 和 -L 指定庫(kù)文件 | 指定庫(kù)文件路徑
-l 參數(shù)(小寫(xiě))就是用來(lái)指定程序要鏈接的庫(kù),-l 參數(shù)緊接著就是庫(kù)名在 /lib 和 /usr/lib 和 /usr/local/lib 里的庫(kù)直接用 -l 參數(shù)就能鏈接,比如鏈接 glog 庫(kù)。
g++ -lglog main.cpp
如果庫(kù)文件沒(méi)放在上面三個(gè)目錄里,需要使用 -L 參數(shù)(大寫(xiě))指定庫(kù)文件所在目錄,-L 參數(shù)跟著的是庫(kù)文件所在的目錄名,鏈接 mytest 庫(kù),/home/bing/mytestlibfolder/libmytest.so。
g++ -L/home/bing/mytestlibfolder -lmytest main.cpp
-I 指定頭文件搜索目錄
/usr/include 目錄一般是不用指定的,gcc 知道去那里找,但是如果頭文件不在 /usr/icnclude
里我們就要用 -I 參數(shù)指定了,比如頭文件放在 /myinclude 目錄里,那編譯命令行就要加上 -I/myinclude 參數(shù)了,如果不加你會(huì)得到一個(gè)"xxxx.h: No such file or directory" 的錯(cuò)誤。 -I 參數(shù)可以用相對(duì)路徑,比如頭文件在當(dāng)前目錄,可以用-I。來(lái)指定。 上面我們提到的 –cflags 參數(shù)就是用來(lái)生成 -I 參數(shù)的。
g++ -I/myinclude main.cpp
-Wall 打印警告信息
打印出 gcc 提供的警告信息
g++ -Wall main.cpp
-w 關(guān)閉警告信息
g++ -w main.cpp
-std=c++11 設(shè)置編譯標(biāo)準(zhǔn)
使用 c++11 標(biāo)準(zhǔn)編譯 main.cpp
g++ -std=c++11 main.cpp
-o 指定輸出文件名
指定即將產(chǎn)生的文件名
g++ main.cpp -o niam
-D 定義宏
在使用 gcc/g++ 編譯的時(shí)候定義宏
常用場(chǎng)景: -DDEBUG 定義 DEBUG 宏,可能文件中有 DEBUG 宏部分的相關(guān)信息,用個(gè) DDEBUG來(lái) 選擇開(kāi)啟或關(guān)閉
#include <iostream>
int main()
{
#ifdef DEBUG
std::cout << "DEBUG" << std::endl;
#endif
// system("pause");
return 0;
}
g++ -DDEBUG main.cpp -o niam
注: 使用 man gcc 命令可以查看gcc英文使用手冊(cè)
用例
最初目錄結(jié)構(gòu)
.
├── include
│ └── StaticPolymorphism.h
├── main.cpp
└── src
└── StaticPolymorphism.cpp
2 directories,3 files
直接編譯
- 最簡(jiǎn)單的編譯,并運(yùn)行
# 將 main.cpp src/StaticPolymorphism.cpp 編譯為可執(zhí)行文件
g++ -Iinc main.cpp src/StaticPolymorphism.cpp
# 運(yùn)行 a.out
time ./a.out
- 增加參數(shù)編譯,并運(yùn)行
# 將 main.cpp src/StaticPolymorphism.cpp 編譯為可執(zhí)行文件 附帶一堆參數(shù)
g++ -g -std=c++11 -O2 -Wall -Iinc main.cpp src/StaticPolymorphism.cpp -o main
# 運(yùn)行 main
time ./main
鏈接靜態(tài)庫(kù)生成可執(zhí)行文件
# 進(jìn)入src目錄下
cd src
# 匯編,生成 StaticPolymorphism.o 文件
g++ StaticPolymorphism.cpp -c -I../inc
# 生成靜態(tài)庫(kù) libStaticPolymorphism.a
ar rs libStaticPolymorphism.a StaticPolymorphism.o
# 回到上級(jí)目錄
cd ..
# 鏈接,生成可執(zhí)行文件: main-with-static-link
g++ main.cpp -Iinc -Lsrc -lStaticPolymorphism -o main-with-static-link
詳細(xì)流程
- 使用 g++ -c 命令 cpp 源文件編譯成可重定位目標(biāo)文件(.o文件)
g++ StaticPolymorphism.cpp -c -I../inc
- 使用 ar rs 命令將可重定位目標(biāo)文件打包成靜態(tài)庫(kù)。
庫(kù)文件名都是以 lib 開(kāi)頭的,靜態(tài)庫(kù)以 .a 作為后綴,表示 Archive。 ar 命令將目標(biāo)文件打包成靜態(tài)庫(kù),選項(xiàng) r 表示將后面的文件列表添加到文件包,如果文件包不存在就創(chuàng)建它,如果文件包中已有同名文件就替換成新的。 選項(xiàng) s 是專(zhuān)用于生成靜態(tài)庫(kù)的,表示為靜態(tài)庫(kù)創(chuàng)建索引,這個(gè)索引被鏈接器使用。
ar rs libStaticPolymorphism.a StaticPolymorphism.o
- 把靜態(tài)庫(kù)和 main.cpp 編譯鏈接在一起。 例如
g++ main.cpp -Iinc -Lsrc -lStaticPolymorphism -o main-with-static-link
其中,-L 選項(xiàng)告訴編譯器去哪里找需要的庫(kù)文件,-lStaticPolymorphism 告訴編譯器要鏈接 libStaticPolymorphism 庫(kù), -I 選項(xiàng)告訴編譯器去哪里找頭文件。 注意,即使庫(kù)文件就在當(dāng)前目錄,編譯器默認(rèn)也不會(huì)去找的,所以 -L。 選項(xiàng)不能少。 編譯器默認(rèn)的查找目錄可以用-print-search-dirs 選項(xiàng)查看。
編譯器會(huì)在默認(rèn)搜索路徑以及 -L 選項(xiàng)指定的路徑中查找用 -l 選項(xiàng)指定的庫(kù),比如 -lStaticPolymorphism,編譯器會(huì)首先找有沒(méi)有動(dòng)態(tài)庫(kù) libStaticPolymorphism.so,如果有就鏈接它,如果沒(méi)有就找有沒(méi)有靜態(tài)庫(kù) libStaticPolymorphism.a,如果有就鏈接它。 所以編譯器是優(yōu)先考慮動(dòng)態(tài)庫(kù)的,如果希望編譯器本次編譯只鏈接靜態(tài)庫(kù),可以指定 -static 選項(xiàng)。
在鏈接靜態(tài)庫(kù)時(shí),鏈接器會(huì)把靜態(tài)庫(kù)中的目標(biāo)文件取出來(lái)和可執(zhí)行文件真正鏈接在一起。 鏈接器可以從靜態(tài)庫(kù)中只取出需要的目標(biāo)文件來(lái)做鏈接。 而且使用靜態(tài)庫(kù)只需寫(xiě)一個(gè)庫(kù)文件名,而不需要寫(xiě)一長(zhǎng)串目標(biāo)文件名。
最終目錄結(jié)構(gòu)
.
├── inc
│ └── StaticPolymorphism.h
├── main.cpp
├── main-with-static-link
├── README.md
└── src
├── libStaticPolymorphism.a
├── StaticPolymorphism.cpp
└── StaticPolymorphism.o
運(yùn)行可執(zhí)行文件
./main-with-static-link
鏈接動(dòng)態(tài)庫(kù)生成可執(zhí)行文件
# 進(jìn)入src目錄下
cd src
# 生成動(dòng)態(tài)庫(kù) libStaticPolymorphism.so
g++ StaticPolymorphism.cpp -I../inc -fPIC -shared -o libStaticPolymorphism.so
# 上面命令等價(jià)于以下兩條命令
g++ StaticPolymorphism.cpp -I../inc -c -fPIC
g++ -shared -o libStaticPolymorphism.so StaticPolymorphism.o
# 回到上級(jí)目錄
cd ..
# 鏈接,生成可執(zhí)行文件: main-with-dynamic-link
g++ main.cpp -Iinc -Lsrc -lStaticPolymorphism -o main-with-dynamic-link
詳細(xì)流程
- 使用 g++ -c -fPIC 命令 將 cpp 源文件編譯成可重定位目標(biāo)文件。 組成動(dòng)態(tài)庫(kù)的目標(biāo)文件和一般的目標(biāo)文件有所不同,在編譯時(shí)要加 -fPIC 選項(xiàng)
g++ StaticPolymorphism.cpp -I../inc -c -fPIC
- 使用 g++ -shared -o 命令將目標(biāo)文件編譯成動(dòng)態(tài)庫(kù)。
g++ -shared -o libStaticPolymorphism.so StaticPolymorphism.o
- 把 main.c 和動(dòng)態(tài)庫(kù)編譯鏈接在一起,例如:
g++ main.cpp -Iinc -Lsrc -lStaticPolymorphism -o main-with-dynamic-link
使用動(dòng)態(tài)庫(kù)編譯鏈接生成的可執(zhí)行文件只是包含動(dòng)態(tài)庫(kù)信息,并沒(méi)有真的做動(dòng)態(tài)鏈接。 在可執(zhí)行文件加載到內(nèi)存時(shí),根據(jù)程序包含的動(dòng)態(tài)庫(kù)信息做動(dòng)態(tài)鏈接。
運(yùn)行可執(zhí)行文件main可以會(huì)報(bào)錯(cuò):
./main-with-dynamic-link: error while loading shared libraries: libStaticPolymorphism.so: cannot open shared object file: No such file or directory
編譯的時(shí)候沒(méi)問(wèn)題,由于指定了 -Lsrc 選項(xiàng),編譯器可以在 src 目錄下找到 libstack.so,而運(yùn)行時(shí)卻說(shuō)找不到 libstack.so。 可以使用 ldd 命令查看可執(zhí)行文件依賴(lài)于哪些動(dòng)態(tài)庫(kù)。
ldd main-with-dynamic-link
linux-vdso.so.1 (0x00007fffe9fbb000)
libStaticPolymorphism.so => not found
libstdc++.so.6 => /lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f51da000000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f51d9c00000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f51da263000)
/lib64/ld-linux-x86-64.so。2 (0x00007f51da362000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f51da243000)
解決方法:
- 把 libStaticPolymorphism.so 所在目錄的絕對(duì)路徑 (比如/home/klein/compiler-case/compilation-dynamic-link/src) 添加到 /etc/ld.so.conf 中(該文件中每個(gè)路徑占一行); 然后運(yùn)行l(wèi)dconfig命令。 ldconfig 命令會(huì)處理 /etc/ld.so.conf 中配置的目錄和一些系統(tǒng)默認(rèn)目錄,如/lib,/usr/lib等,處理之后生成 /etc/ld.so.cache 緩存文件,動(dòng)態(tài)鏈接器就從這個(gè)緩存中搜索動(dòng)態(tài)庫(kù)。
- 把 libStaticPolymorphism.so 拷到 /usr/lib 或 /lib 目錄,這樣可以確保動(dòng)態(tài)鏈接器能找到這個(gè)動(dòng)態(tài)庫(kù)。
- 使用 LD_LIBRARY_PATH 環(huán)境變量預(yù)先加載 libStaticPolymorphism.so 所在目錄。
最終目錄結(jié)構(gòu)
.
├── inc
│ └── StaticPolymorphism.h
├── main.cpp
├── main-with-dynamic-link
├── README.md
└── src
├── libStaticPolymorphism.so
├── StaticPolymorphism.cpp
└── StaticPolymorphism.o
2 directories,7 files
運(yùn)行可執(zhí)行文件
LD_LIBRARY_PATH=src ./main-with-dynamic-link