GCC -E選項:生成預處理檔案

2020-07-16 10:04:43
C語言程式碼在交給編譯器之前,會先由前處理器進行一些文字替換方面的操作,例如宏展開、檔案包含、刪除部分程式碼等。

在正常的情況下,GCC 不會保留預處理階段的輸出檔案,也即.i檔案。然而,可以利用-E選項保留前處理器的輸出檔案,以用於診斷程式碼。-E選項指示 GCC 在預處理完畢之後即可停止。

預設情況下,前處理器的輸出會被匯入到標準輸出流(也就是顯示器),可以利用-o選項把它匯入到某個輸出檔案:

$ gcc -E circle.c -o circle.i

表示把預處理的結果匯出到 circle.i 檔案。

因為標頭檔案可能相當大,如果原始檔包括了多個標頭檔案,那麼它的前處理器輸出可能會龐雜難讀。使用-C選項會很有幫助,這個選項可以阻止前處理器刪除原始檔和標頭檔案中的注釋:

$ gcc -E -C circle.c -o circle.c

注意,這裡是大寫的 -C,不是小寫的 -c。小寫的 -c 表示只編譯不連結。

下面是 GCC 前處理器階段常用的選項:

-Dname[=definition]

在處理原始檔之前,先定義宏 name。宏 name 必須是在原始檔和標頭檔案中都沒有被定義過的。將該選項搭配原始碼中的#ifdef name命令使用,可以實現條件式編譯。如果沒有指定一個替換的值,該宏被定義為值 1。

-Uname

如果在命令列或 GCC 預設設定中定義過宏 name,則“取消”name 的定義。-D-U選項會依據在命令列中出現的先後順序進行處理。

-Idirectory[:directory[...]]

當通過 #include 命令把所需的標頭檔案包括進原始碼中時,除系統標準 include 目錄之外,指定其他的目錄對這些標頭檔案進行搜尋。

-iquote directory[:directory[...]]

這是在最近 GCC 版本中新增的選項,它為在 #include 命令中採用引號而非尖括號指定的標頭檔案指定搜尋目錄。

-isystem directory[:directory[...]]

該選項在標準系統 include 目錄以外為系統標頭檔案指定搜尋目錄,且它指定的目錄優先於標準系統 include 目錄被搜尋。在目錄說明開頭位置的等號,被視作系統根目錄的預留位置,可以使用--sysroot-isysroot選項來修改它。

-isysroot directory

該選項指定搜尋標頭檔案時的系統根目錄。例如,如果編譯器通常在 /usr/include 目錄及其子目錄下搜尋系統標頭檔案,則該選項將引導到 directory/usr/include 及其子目錄下進行搜尋。

--sysroot選項,採用一個連字元替代 i,它為連結庫搜尋而不是標頭檔案搜尋指定系統根目錄以外的目錄。如果 isysroot 不可用,則 sysroot 既為標頭檔案又為連結庫搜尋指定目錄。

-I-

在較新版本的 GCC 中,該選項被-iquote替代。在舊版本中,該選項用於將命令列的所有-Idirectory選項分割為兩組。所有在-I-左邊加上-I選項的目錄,被視為等同於採用-iquote選項;這指的是,它們只對 #include 命令中採用引號的標頭檔案名進行搜尋。

所有在-I-右邊加上-I選項的目錄,將對所有 #include 命令中的標頭檔案名進行搜尋,無論檔名是在引號還是尖括號中。

而且,如果命令列中出現了-I-,那麼包括原始檔本身的目錄不再自動作為搜尋標頭檔案的目錄。

對於include目錄而言,通常的搜尋順序是:
  1. 包含指定原始檔的目錄(對於在 #include 命令中以引號包括的檔名)。
  2. 採用-iquote選項指定的目錄,依照出現在命令列中的順序進行搜尋。只對 #include 命令中採用引號的標頭檔案名進行搜尋。
  3. 採用-I選型指定的目錄,依照出現在命令列中的順序進行搜尋。
  4. 採用環境變數 CPATH 指定的目錄。
  5. 採用-isystem選項指定的目錄,依照出現在命令列中的順序進行搜尋。
  6. 採用環境變數 C_INCLUDE_PATH 指定的目錄。
  7. 系統預設的 include 目錄。