GNU g++經常使用編譯選項用法

GNU g++經常使用編譯選項用法

本文來自ChinaUnix博客,若是查看原文請點:http://blog.chinaunix.net/u/30686/showart_1210761.htmlhtml

 

GCC Option Refresher前端

本節回顧GCC的C編譯器的基本使用方法。java

g++編譯器的選項能夠是單字符,好比-o,也能夠多字符,好比-ansi。因此你不能夠把多個單字符選項合寫到一塊兒,這和許多其餘GNU和UNIX下的程序不一樣。例如,多字符選項-pg不表示2個單字符選項-p -g。選項-pg表示在最終的2進制文件裏生成額外的代碼,用來輸出GNU code profiler的信息gprof;而選項-p -g則表示在目標2進制文件裏生成額外的代碼,用來產生prof code profiler須要的信息(-p),並在目標里加入調試信息(-g)。c++

既然g++把多字符的選項進行了區分,你就能夠隨意安排各個選項的順序了。好比:安全

g++ -pg -fno-strength-reduce -g myprog.c -o myprogapp

編輯器

g++ myprog.c -o myprog -g -fno-strength-reduce -pgide

是同樣的。函數

通常狀況下,這些選項的順序是無所謂的。可是在有些狀況下,順序會變得重要,好比你屢次使用同一類的選項。舉個例子,-I選項指定了搜索include文件的目錄,若是你用-I指定了多個目錄,gcc會按照你指定目錄的順序搜索須要的文件。性能

用g++編譯單個源文件myprog.cc很簡單,只要把文件名當參數傳給g++就好了。

$ g++ myprog.cc

$ ls -l

-rwxr-xr-x 1 wvh users 13644 Oct 5 16:17 a.out

-rw-r--r-- 1 wvh users 220 Oct 5 16:17 myprog.cc

默認狀況下,UNIX和LINUX操做系統生成的目標文件是當前目錄下的a.out,只要輸入./a.out就能夠執行。在Cygwin系統下,你獲得的是a.exe,經過輸入./a或者./a.exe均可以執行。

要定義g++的輸出文件名,使用-o選項以下所示:

$ g++ myprog.cc -o runme

$ ls -l

-rw-r--r-- 1 wvh users 220 Oct 5 16:17 myprog.cc

-rwxr-xr-x 1 wvh users 13644 Oct 5 16:28 runme

若是編譯多個源文件,只要在命令行裏列出它們就好了,以下所示,最終產生的輸出文件是showdate:

$ g++ showdate.cc helper.cc –o showdate

若是你想先編譯這些源文件,最後再把它們連接成一個2進制文件,能夠用-c選項,那麼g++就只產生object文件,以下所示:

$ g++ -c showdate.cc

$ g++ -c helper.cc

$ g++ showdate.o helper.o –o showdate

$ ls -l

total 124

-rw-r--r-- 1 wvh users 210 Oct 5 12:42 helper.cc

-rw-r--r-- 1 wvh users 45 Oct 5 12:29 helper.h

-rw-r--r-- 1 wvh users 1104 Oct 5 13:50 helper.o

-rwxr-xr-x 1 wvh users 13891 Oct 5 13:51 showdate

-rw-r--r-- 1 wvh users 208 Oct 5 12:44 showdate.cc

-rw-r--r-- 1 wvh users 1008 Oct 5 13:50 showdate.o

注意

全部的GCC編譯器都是經過文件的後綴名來判斷文件類型的,而後選擇應該進行的操做(好比,後綴名爲.o的文件只須要進行連接),文件類型到操做的映射記錄在GCC的specs文件裏。在GCC版本4之前,specs文件是標準文本文件,能夠用任何文本編輯器修改;可是GCC版本4之後specs文件是內建文件,必需要進行解壓才能修改。

很顯然,當你的項目文件稍微多點,使用命令行來編譯就不可接受了,特別是還要加上搜索目錄、優化選項和其餘g++選項。解決的方案就是make,不過本文並不討論它。

C++源文件擴展名

前面說過全部GCC編譯器都經過文件後綴名來決定採用的操做。下表列出了g++認識的文件類型和相應的操做。

Suffix Operation

.C C++ source code to preprocess.

.cc C++ source code to preprocess. This is the standard extension for C++ source files.

.cpp C++ source code to preprocess.

.cxx C++ source code to preprocess

.ii C++ source code not to preprocess.

若是一個文件的後綴名未知,那麼就當成object文件進行連接。這並非說你只能使用上表列出的文件名後綴來區分源代碼文件和其餘文件,你能夠用-x lang選項指定一個或多個輸入文件的代碼類型,不使用標準的文件名後綴規則。lang參數指定代碼的類型;對於C++,輸入文件能夠是c++(標準的C++源文件)或c++-cpp-output(已經被預處理過的C++源文件,不需再進行預處理)。

注意

當GCC編譯器遇到上表列出的文件後綴,它會當成C++文件。可是,有些GCC編譯器(好比gcc)不能處理C++程序裏很複雜的依賴關係,好比複雜的類庫,因而編譯失敗。因此你應該用g++(或c++)來編譯C++程序。

GCC的C++編譯器的命令行選項

許多命令行選項對於GCC編譯器家族都是通用的,下表只列出g++專有的命令行參數。

Option

Description

-fabi-version=n

指定編譯代碼須要符合的C++ ABI(application binary interface)版本。對於GCC版本3.4及更高,默認的ABI版本是2。

-fcheck-new

保證new操做返回的指針爲非空。

-fconserve-space

把全局變量的初始化操做延遲到運行的時候,common segment裏的全局變量不初始化,這樣減小可執行文件的大小。

-fdollars-in-identifiers

容許標識符裏出現$符號(默認)。

-fms-extensions

使g++忽略Microsoft Foundation Classes (MFC)中非標準用法的警告信息。

-fno-access-control

禁止訪問檢查

-fno-const-strings

強制g++把字符串常量的類型定義成char *,而無論ISO C++標準是否要求是const char *。

-fno-elide-constructors

強制g++老是調用copy構造函數,即便在用臨時對象初始化另外一個同類型對象的時候。

-fno-enforce-eh-specs

禁止在運行時檢查異常處理違例。

-ffor-scope

對於for語句初始化部分申明的變量,限制其做用域是for循環之內。你也能夠用-fno-for-scope選項強制其做用域爲下一個‘}’以前,雖然這和ISO標準衝突,可是舊版本g++和許多其餘傳統的C++編譯器都是這樣作的。

-fms-extensions

禁止對Microsoft Foundation Classes代碼的沒必要要的警告。

-fno-gnu-keywords

禁止把typeof做爲一個關鍵字,這樣就能夠用它做爲標識符使用,你仍可使用__typeof__關鍵字來代替它。該選項被包含在了-ansi選項裏面。

-fno-implement-inlines

Saves space by not creating out-of-line copies of inline functions controlled by #pragma statements. Using this option will generate linker errors if the such functions are not inlined everywhere they are called

-fno-implicit-inline-templates

不建立隱含的模板實例以節省空間。(詳見-fno-implicit-templates)

-fno-implicit-templates

只建立外聯(非內聯)模板的顯式實例以節省空間。

-fno-nonansi-builtins

禁止使用非ANSI/ISO標準的內置屬性,包括ffs、alloca、_exit、index、bzero、conjf及其餘相關的函數。

-fno-operator-names

禁止使用and、bitand、bitor、compl、not、or和xor關鍵字做爲對應操做符的同義詞。

-fno-optional-diags

禁止非標準的內部語法診斷,好比類中特殊的名字應該在什麼時候使用各類不一樣的形式。

-fno-rtti

禁止給類的虛函數產生運行時類型信息(RTTI)

-fno-threadsafe-statics

使g++不產生用於線程安全檢查的代碼,這樣能減小代碼量,若是不須要線程安全的話。

-fno-weak

使g++不使用弱符合支持,即便連接器支持它。這個選擇用於g++測試的時候,其餘時候請不要使用。

-fpermissive

把代碼的語法錯誤做爲警告,並繼續編譯進程。

-frepo

容許模板實例化在鏈接時自動進行。該選項包含了-fno-implicit-templates選項。

-fstats

編譯完成後顯示前端的統計信息。該選項通常只有g++開發人員使用。

-ftemplate-depth-n

保證模板實例化的遞歸深度不超過整數n。

-fuse-cxa-atexit

註冊靜態對象的析構函數時,使用__cxa_atexit而不是atexit。

-fvisibility=value

(GCC 4.02或之後)使g++不導出ELF(Executable and Linking Format,Linux和Solaris等系統上默認的2進制文件格式)中用hidden標識的object模塊內或庫內的符號。該選項能減小目標文件大小,加快符號表的查找,從而改善運行性能。可是,該選項也會由於不一樣的visibility等級而致使模塊間拋出異常發生問題,詳見後面的「「Visibility Attributes and Pragmas for GCC C++ Libraries」一節。若是沒有使用該選項,那麼默認的visibility值是default,即導出全部目標文件和庫裏的符號。

-nostdinc++

禁止在C++的標準目錄裏搜索頭文件。

g++編譯器的其餘一些C++選項處理優化、警告和代碼生成的任務,咱們在其餘章節裏討論。下表總結了專對C++的警告選項。

Option

Description

-Wabi

當編譯器生成的代碼和標準C++ ABI不兼容的時候發出警告。對於GCC版本3.4和更高,默認的ABI版本是2。

-Wctor-dtor-privacy

當一個類的全部構造函數和析構函數都是私有時發出警告。

-Weffc++

當出現不符合《Effective C++》(Scott Meyers,Addison-Wesley,2005,ISBN: 0-321-33487-6)風格的代碼時給出警告

-Wno-deprecated

使用已過期C++屬性和用法時不給出警告。

-Wno-non-template-friend

當非模板的友元函數定義在模板裏時不給出警告。In the C++ language template specification, a friend must declare or define a nontemplate function if the name of the friend is an unqualified identifier.

-Wno-pmf-conversions

當把一個指向類成員函數的指針隱式轉化成通常指針的時候不給出警告。

-Wnon-virtual-dtor

當一個類須要虛析構函數而又沒有申明虛析構函數的時候給出警告。該選項被包含在-Wall選項裏。

-Wold-style-cast

當在C++源代碼裏使用了傳統C語言風格的類型轉換方式時,給出警告。

-Woverloaded-virtual

當子類的函數申明覆蓋基類虛函數的時候給出警告。

-Wreorder

當類成員變量的初始化順序和申明順序不一致的時候給出警告。g++編譯器會自動記錄全部變量的正確初始化順序。該選項被包含在-Wall選項裏。

-Wsign-promo

當一個重載操做把一個有符號數值轉換成無符號數值的時候給出警告。在版本3.4及之前,g++對無符號類型進行了保護,可是這和C++標準不一致。

-Wstrict-null-sentinel

當用一個無類型的NULL做爲哨兵的時候發出警告。哨兵是指一個無效的輸入值,一般表明輸入的結束。此問題的緣由是無類型的NULL在不一樣的編譯器實現裏有不一樣的大小,因此必須先轉化成固定的類型。

ABI Differences in g++ Versions

C++ ABI是一套API標準,定義了C++庫提供的數據類型、類、方法、頭文件等的接口和規範。對庫和目標文件來講,物理組織、參數傳遞方式和命名方式是很重要的,因此須要一個統一的接口,使編譯出來的C++程序與提供的庫的接口一致。這種一致性對語言特有的一些屬性更加劇要,好比拋出異常和捕捉異常的時候。

從版本3開始的GNU C++編譯器,都遵循一個工業標準的C++ ABI規範,定義在http://www.codesourcery.com/cxx-abi/abi.html。雖然這個規範是爲64位Itanium定製的,可是它適用於任何平臺,而且已經做爲GNU/Linux和BSD系統的C++ ABI的實現。

版本3.4之前的g++使用ABI版本1,以後使用ABI版本2。不一樣ABI版本之間的程序和庫不能混用。若是你不肯定本身g++的ABI版本,能夠用g++ --version命令檢查g++的版本,或用一個僞編譯命令顯示ABI標識符,命令行以下:

g++ -E -dM -

若是顯示102,那麼就是版本1;若是顯示1002,就是版本2。若是你必須用到之前版本ABI的庫,那麼給g++加上選項-fabi-version=n,其中n就是你要兼容的ABI版本。這樣作只能算做權宜之計,把全部舊的代碼和庫更新到當前版本纔是最佳解決方案。

GNU C++ Implementation Details and Extensions

本文雖然不討論怎樣寫好C++程序,可是當你用GCC的C++編譯器編譯你的C++程序的時候,你能夠從GCC的擴展中獲得許多好處,包括編譯器自身的優點和g++使用的標準C++庫libstdc++的優點。本節提煉出最爲重要的一些擴展特性,並討論它們在C++規範和編譯器行爲方面的一些差別。

Attribute Definitions Specific to g++

做爲對visibility屬性(詳見於「Visibility Attributes and Pragmas for GCC C++ Libraries」)的補充,g++提供了2個額外的屬性,即init_priority(priority)和java_interface屬性。

The init_priority Attribute

該屬性容許用戶控制某個名字空間裏的對象的初始化順序。一般,對象的初始化順序是它們在某個代碼單元裏的定義順序。init_priority只有一個整型參數,值爲101到65535,越小表示優先級越大。好比,在下面的僞碼裏,類MyClass將比類YourClass先初始化:

class MyClass

{

};

class YourClass

{

__attribute__ ((visibility("default"))) void MyMethod();

};

要改變它們的初始化順序,你能夠把代碼改爲下面這樣:

class MyClass

{

__attribute__ ((init_priority(65535)));

};

class YourClass

{

__attribute__ ((init_priority(101)));

};

你只須要注意所使用的優先級數值的順序,具體使用了哪一個數值則無所謂(即只要MyClass的優先級數值比YourClass大就好了,是否是65535和101則無所謂)。

The java_interface Attribute

該屬性通知g++某個類是一個Java接口類,並只能在標識了extern 「Java」的模塊內使用。調用這個類的函數使用的是GCC Java編譯器的接口表機制(interface table mechanism),而不是一般的C++虛函數表機制(virtual function table mechanism)。

提示

記住,Java的運行時環境須要更多的初始化工做。當你混合使用C++和Java代碼時,最好用Java寫主程序,這樣能保證調用Java函數前初始化工做已經作足了。

C++ Template Instantiation in g++

模板是C++最有用和最有趣的特性之一,能減小重複代碼,提升複用率,簡化調試和代碼維護工做。模板也有利於編譯時的類型檢查,好比,使用了模板就不用再傳遞void指針,由於你能夠把模板參數實例化成任何須要的類型。

g++經過增長3個功能擴展了標準的ISO模板定義:

l 支持使用extern關鍵詞對實例化類型進行前置申明;

l The ability to instantiate the support data required by the compiler for a named template class without actually instantiating it by using the inline keyword

l The ability to only instantiate the static data members of a class without instantiating support data or member functions by using the static keyword

基本上,GCC的g++編譯器支持Borland和Cfront(AT&T)兩種模板特性。要支持Borland的模板實例化和使用特性,g++使用-frepo選項容許預處理器在處理每一個翻譯單元(源代碼文件)時進行模板實例化,並把信息存在.rpo文件裏。這些文件被後面的編譯過程使用,並由連接器最後合併成單個編譯單元。要支持Cfront特性,g++內置了一個模板實例化庫並在連接的時候合併到代碼裏。Cfront要求使用模板的代碼要麼進行顯式實例化,要麼包含定義模板的申明文件。你能夠把顯式實例化放在代碼的任何地方,或一個包含的頭文件裏。對於後者,你可能要去掉-fno-implicit-templates選項,這樣你只獲得了顯式實例化的那些實例。

Function Name Identifiers in C++ and C

GCC編譯器預約義了2個標識符存儲當前函數的標識。__FUNCTION__標識符只存儲函數名字,__PRETTY_FUNCTION__則存儲函數的全稱。在C程序裏,這2種名字是同樣的,可是在C++程序裏它們有區別。下面的程序展現了這種區別:

#include

using namespace std;

class c {

public:

void method_a(void)

{

cout

cout

 

}

};

int main(void)

{

c C;

C.method_a();

return 0;

}

運行的輸出是:

$ ./a.out

Function method_a in FUNCTION_example.cc

Pretty Function void c::method_a() in FUNCTION_example.cc

在C++裏,__FUNCTION__和__PRETTY_FUNCTION__是變量,而不是宏定義,因此#ifdef __FUNCTION__是沒有意義的。

注意

若是你的GCC是3.2版本或更高,那麼__FUNCTION__和__PRETTY_FUNCTION__的行爲就和C99定義的__func__變量是同樣的。早於3.2版本的GCC編譯器把__FUNCTION__和__PRETTY_FUNCTION__定義成字符串,因此它們能夠和其餘字符串進行串接操做。

Minimum and Maximum Value Operators

g++編譯器加入了?操做符,分別表示2個數值中較小的和較大的那個。好比,下面的代碼把10賦給min變量:

min = 10

而下面的代碼把15賦給max:

max = 10 >? 15;

提示

既然這些操做符是語言提供的,那麼它們也能對任何類或enum類型進行重載。

Using Java Exception Handling in C++ Applications

Java和C++的異常處理模型是不一樣的,雖然g++能猜想C++代碼什麼時候使用了Java異常,你最好仍是明確標識出這種狀況,避免連接錯誤。要告訴g++一塊代碼可能使用Java異常,把下面的代碼放在該翻譯單元中任何catch和throw代碼以前:

#pragma GCC java_exceptions

你不能在一個翻譯單元裏同時使用Java和C++異常。

Visibility Attributes and Pragmas for GCC C++ Libraries

寫C++庫的時候一個廣泛的問題就是可見的ELF符號太多了,其實許多符號都不能被外部使用,也不用對外公開。GCC版本4.02及更高提供了-fvisibility=value選項和相關的內置屬性,使你能夠控制這種行爲,使用的方式和微軟C++編譯器提供的__declspec(dllexport)方式類似。新的-fhidden選項有2個可選值:default,導出目標文件的全部符號(這也是默認的行爲);hidden,不導出當前目標模塊的符號。還能夠在函數或類前加以下代碼來進行設置:__attribute__ ((visibility("default")))和__attribute__ ((visibility("hidden")))。

默認狀況下,ELF導出所有符號。要隱藏特定目標文件的符號,須要在編譯該文件的時候加上-fvisibility=hidden選項。這將致使makefile的複雜性大大增長,由於你要麼須要手動設置每一個文件的編譯選項,要麼改變全局編譯選項致使任何符號都不能導出。這在類庫正常拋出異常或者調試某些變量的時候實在是個災難。

讓指定的符號可見的好方式是聯合使用代碼屬性設置和編譯選項-fvisibility=hidden。若是要導出某個符號,先在它們的定義前加上__attribute__((visibility("default"))),好比下面這樣:

class MyClass

{

int i;

__attribute__ ((visibility("default"))) void MyMethod();

};

而後給makefile增長-fvisibility=hidden的編譯選項,這樣全部其餘的符號就被隱藏了。另外一個稍微好點的方法是定義一個宏,並放到全部你不想導出的符號定義前面,而後使用默認的導出全部符號,以下所示:

#define LOCAL __attribute__ ((visibility("hidden")))

class MyClass

{

int i;

LOCAL void MyMethod();

};

編譯時不使用-fvisibility=value選項,這樣除了MyMethod被隱藏,其餘符號都被導出。

還有一種控制可見屬性的pragma語法如今還能使用,不過未來可能要去掉,以下面這樣:

extern void foo(int);

#pragma GCC visibility push(hidden)

extern void bar(int);

#pragma GCC visibility pop符號foo會被導出,可是bar則不會。這種方式雖然很簡單方便,可是建議你仍是使用visibility和__attribute__。

 

======================== End

相關文章
相關標籤/搜索