g++入門教程


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)印象中鏈接庫的順序是從右到左,因此基礎庫要寫到右側

參考文獻


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM