g++命令選項多如繁星,本文參考網上博客總結一篇簡單易用的入門教程。
1. g++簡介
g++是GNU開發的C++編譯器,是GCC(GNU Compiler Collection)GNU編譯器套件的組成部分。另外,gcc是GNU的C編譯器。
g++編譯器是GCC的一部分,GCC編譯工作一般分為四個步驟:
(1)預處理(Preprocessing)。由預處理器cpp完成,將.cpp源文件預處理為.i文件。
g++ -E test.cpp -o test.i //生成預處理后的.i文件
(2)編譯(Compilation)。由編譯器cc1plus完成,將.i文件編譯為.s的匯編文件。使用-S選項,只進行編譯而不進行匯編,生成匯編代碼。
g++ -S test.i -o test.s //生成匯編.s文件
(3)匯編(Assembly)。由匯編器as完成,將.s文件匯編成.o的二進制目標文件
g++ -c test.s -o test.o //生成二進制.o文件
(4)鏈接(Linking)。由鏈接器ld,將.o文件連接生成可執行程序。
g++ test.o -o test.out //生成二進制.out可執行文件
2. 命令格式
gcc [-c|-S|-E] [-std=standard]
[-g] [-pg] [-Olevel]
[-Wwarn...] [-pedantic]
[-Idir...] [-Ldir...]
[-Dmacro[=defn]...] [-Umacro]
[-foption...] [-mmachine-option...]
[-o outfile] [@file] infile...
3. 命令選項
關於g++的命令選項,可以參考GCC官方手冊,或者使用man g++單獨查看g++使用手冊。
下面列出常用的命令選項。
(1)總體選項
-E (僅作預處理,不進行編譯、匯編和鏈接)
只激活預處理,這個不生成文件,你需要把它重定向到一個輸出文件里面。例子用法:
gcc -E hello.c > pianoapan.txt
gcc -E hello.c | more
慢慢看吧,一句`hello word`也要預處理成800行的代碼。
-S (僅編譯到匯編語言,不進行匯編和鏈接)
只激活預處理和編譯,就是指把文件編譯成為匯編代碼。例子用法:
gcc -S hello.c
將生成.s的匯編代碼,可以用文本編輯器查看。
-c (編譯、匯編到目標代碼,不進行鏈接)
只激活預處理,編譯,和匯編,也就是他只把程序做成obj文件。例子用法:
gcc -c hello.c
將生成.o的目標文件(object file)。
-o (輸出到指定的文件)
指定目標名稱,缺省的時候,gcc/g++編譯出來的文件是a.out。例子如下:
g++ -o hello.out hello.cpp
g++ -o hello.asm -S hello.cpp
(2)目錄選項
-I[dir] (把dir加入到搜索頭文件的路徑列表中)
g++優先在當前目錄查找頭文件,如果沒有找到,會到系統默認的頭文件目錄找。
如果使用-I指定了目錄,g++會到-I指定的目錄查找,查找不到,然后再到系統默認的頭文件目錄查找
例子如下:
g++ test.c -I../inc -o test
-L[dir] (把dir加入到搜索庫文件的路徑列表中)
編譯的時候,指定搜索庫的路徑。比如你自己的庫,可以用它指定目錄,不然編譯器將只在標准庫的
目錄找。這個dir就是目錄的名稱。例子如下:
g++ -I../inc -L/home/mylib test.c -o test -lmythread
-l[library] (進行鏈接時搜索名為library的庫)
指定編譯的時使用的庫,例子用法
g++ hello.c -o hello -lpthread
使用pthread庫編譯連接,生成程序。
-include [file] (一般用不到,頭文件都是在代碼中 #include)
相當於在代碼中使用#include,用於包含某個代碼。
簡單來說,就是編譯某個文件,需要另一個文件的時候,就可以用它設定。例子用法:
g++ hello.c -include /root/pianopan.h
-Wl,-rpath=[dir] (把dir加入到程序運行時搜索庫文件的路徑列表中)
程序運行時查找自己的動態庫的時候,可以用它指定運行時的動態庫搜索路徑。用法如下:
g++ -o hello hello.cpp -L./lib -lmylib -Wl,-rpath=./lib
(3)預處理選項
-Dmacro
相當於C語言中的#define macro
-Dmacro=defn
定義宏,相當於C語言中的#define macro defn
-Umacro
取消宏定義,相當於C語言中的#undef macro
-undef
取消任何非標准宏的定義,C++標准預定義的宏仍然有效
(4)鏈接方式選項
-static
此選項將禁止使用動態庫。優點:程序運行不依賴於其他庫。缺點:可執行文件比較大。
-shared
此選項將盡量使用動態庫,為默認選項。優點:生成文件比較小。缺點:運行時需要系統提供動態庫。
-Wl,-Bstatic
告訴鏈接器ld只鏈接靜態庫,如果只存在動態鏈接庫,則鏈接器報錯。
-Wl,-Bdynamic
告訴鏈接器ld優先使用動態鏈接庫,如果只存在靜態鏈接庫,則使用靜態鏈接庫。
(5)錯誤與告警選項
-Wall(打開一些很有用的警告選項)
一般使用該選項,允許發出GCC能夠提供的所有有用的警告。也可以用-W{warning}來標記指定的警告
-W (打印一些額外的警告信息)
-Werror (把警告當作錯誤,出現任何警告就放棄編譯)
要求g++將所有的警告當成錯誤進行處理,在警告發生時中止編譯過程。
-Werror={warning}
將指定警告設置為錯誤。例如-Werror=return-type,如果函數需要返回值卻沒有return語句,則編譯報錯
-Wshadow
當一個局部變量遮蓋住了另一個局部變量,或者全局變量時,給出警告(很有用,建議打開)
-w
關閉所有警告(建議不要使用此項)
這一類選項其實還有很多,如-Wpointer-arith、-Wcast-qual、-Waggregate-return、-Winline等,在此不一一介紹,需要用到可以查手冊。
(6)調試選項
-g
指示編譯器,在編譯時,產生調試信息。
-ggdb
此選項將盡可能的生成gdb可以使用的調試信息。
-glevel
請求生成調試信息,同時用level指出需要多少信息,默認的level值是2。
(7)優化選項
-O0 (禁止編譯器進行優化。默認為此項)
-O1 (嘗試優化編譯時間和可執行文件大小)
-O2 (更多的優化,會嘗試幾乎全部的優化功能,但不會進行“空間換時間”的優化方法)
-O3 (在 -O2 的基礎上再打開一些優化選項:-finline-functions, -funswitch-loops 和 -fgcse-after-reload )
-Os (對生成文件大小進行優化。它會打開 -O2 開的全部選項,除了會那些增加文件大小的。)
編譯器優化建議使用-O2。
(8)標准
-ansi
支持符合ANSI標准的C程序(關閉GNU C中某些不兼容ANSI C的特性)
-std=c99
指明使用標准 ISO C99 作為標准來編譯程序
-std=c++11
指明使用標准 C++11 作為標准來編譯程序
(9)其他選項
-fpic
編譯器生成位置無關目標碼(PIC,position-independent code),用於動態鏈接庫,即Linux下的.so文件。
通過全局偏移表(GOT,Global Offset Table)訪問所有常量地址。
程序啟動時通過動態加載程序解析GOT條目。
如果鏈接的so文件的GOT大小超過計算機特定的最大大小,則會從鏈接器收到錯誤消息,指示-fpic不起作用。這種情況下,請使用-fPIC重新編譯
-fPIC
同-fpic功能一致,生成位置無關目標碼,用於生成動態鏈接庫,建議使用該選項,而非-fpic
-v
顯示詳細的編譯、匯編、連接命令
-imacros file
將file文件的宏,擴展到gcc/g++的輸入文件,宏定義本身並不出現在輸入文件中
-nostdinc
不在系統缺省的頭文件目錄里面找頭文件,一般和-I聯合使用,明確限定頭文件的位置。
-nostdin C++
不在g++指定的標准路經中搜索,但仍在其他路徑中搜索,此選項在創建libg++庫使用。
-C
在預處理的時候,不刪除注釋信息,一般和-E使用,有時候分析程序,用這個很方便的。
-m
生成與具體CPU相關的程序。
-m32
生成32bits程序
-m64
生成64bits程序
-M
生成文件依賴的信息,包含目標文件所依賴的所有源文件。你可以用gcc -M hello.c來測試一下,很簡單。
-MM
和上面的那個一樣,但是它將忽略由#include造成的依賴關系。
-MD
和-M相同,但是輸出將導入到.d的文件里面。
-MMD
和-MM相同,但是輸出將導入到.d的文件里面。
-x language filename
設定文件所使用的語言,使后綴名無效,對以后的多個有效.
也就是根據約定C語言的后綴名稱是.c的,而C++的后綴名是.C或者.cpp。
如果你很個性,決定你的C代碼文件的后綴名是.pig,那你就要用這個參數
這個參數對他后面的文件名都起作用,除非到了下一個參數的使用。可以使用的參數有下面的這些:
c,objective-c,c-header,c++,cpp-output,assembler,assembler-with-cpp。
看到英文,應該可以理解的。例子用法:
gcc -x c hello.pig
-x none filename
關掉上一個選項,也就是讓gcc根據文件名后綴,自動識別文件類型,例子用法:
gcc -x c hello.pig -x none hello2.c
4. 鏈接注意事項
4.1 指定靜態與動態的鏈接方式
g++鏈接庫時,默認優先鏈接動態鏈接庫。靜態庫與動態庫混合鏈接時,有如下兩種方法:
(1)靜態鏈接庫使用絕對路徑,動態鏈接庫使用-l。以boost庫為例,如果我們要使用靜態庫則可書寫如下:
g++ main.cpp -pthread /usr/lib64/libboost_thread.a /usr/lib64/libboost_system.a
(2)使用-Wl,-Bstatic告訴鏈接器ld鏈接靜態庫,不存在靜態庫,則ld報錯。使用-Wl,-Bdynamic告訴鏈接器優先使用動態鏈接庫,如果只存在靜態庫,則鏈接靜態庫,不報錯。示例如下:
g++ main.cpp -Wl,-Bstatic -lboost_system -lboost_thread -Wl,-Bdynamic
注意
(1)命令末尾-Wl,-Bdynamic,作用是告訴鏈接器,后續系統庫的鏈接默認使用動態鏈接,否則會出現找不到系統庫的錯誤,諸如:
/usr/bin/ld: cannot find -lgcc_s
collect2: ld returned 1 exit status
(2)鏈接時,庫要放在目標文件的后面,否則會報"undefined reference to: xxx"錯誤。具體參見gcc手冊的如下描述:
the linker searches and processes libraries and object files in the order they are
specified. Thus, `foo.o -lz bar.o' searches library `z' after file foo.o but before
bar.o. If bar.o refers to functions in `z', those functions may not be loaded.
(3)印象中鏈接庫的順序是從右到左,因此基礎庫要寫到右側
參考文獻
- 1.g++入門教程
- 2.gcc編譯選項
- 3.gcc 運行指定動態庫的三種方法
