前言
本文的目的,在於列出一些 GCC 常用的情境,供有需要的讀者參考。由於 Clang 在參數上刻恴的向 GCC 靠攏,這些參數對於 Clang 通常也適用。
基本的使用方式
一開始先知道以下指令即可:
$ g++ -o program source.cpp
$ ./program
檢查 GCC 版本
使用 --version
參數可以顯示編譯器的版本號:
$ g++ --version
g++-8 (Homebrew GCC 8.1.0) 8.1.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
不同版本的編譯器提供的特性相異。在討論區討論時,有時候編譯器版本可以提示一些有用的訊息。
加入警告訊息
建議在編譯時一律加入 -Wall
和 -Wextra
來開啟一些常見的警告訊息:
$ g++ -Wall -Wextra -o hello hello.cpp
這兩個參數不會開啟所有的警告訊息,但對一般使用已經足夠了。
再加上 -Werror
參數可將警告訊息轉為錯誤訊息。但有時候警告訊息是無害的,不用刻意消除所有警告訊息,只要明確知道警告訊息的來源即可。
加入除錯訊息
在編譯時加上 -g
參數可以在執行檔內加入給 GDB 使用的資訊,有利於除錯。但該參數對實際上線的程式沒幫助。實際要對外發佈程式前,最好先關掉該參數後重新編譯一次程式。
加入剖析訊息
在編譯時加上 -pg
參數可在執行檔內加入給剖析器使用的資訊,有利於找出程式內的瓶頸步驟。但該參數本身會拖慢程式的運行。實際要發佈程式前,最好關掉該參數後重新編譯一次程式。
最佳化
和最佳化相關的參數很多,所以 GCC 提供一些套餐選項。常見的選項如下:
-O0
:關閉最佳化。預設選項-O1
:第一級最佳化-O2
:第二級最佳化。較保守的編譯會採用此級-O3
:第三級最佳化。偶爾會造成程式不穩定-Os
:對空間最佳化。需要考慮執行檔大小時使用
由於最佳化和語法無關,在學習語法的階段,不用耗費過多時間在這裡。
編譯多個檔案
有時候程式碼比較長,會按程式碼的功能拆開到不同檔案上。本節說明編譯多個檔案的方式。
使用單一指令
只用單一指令的方式如下:
$ g++ -o program a.cc b.cc c.cc
要編譯函式庫的話,這種方式就行不通了。還是要會分步編譯的流程。詳見下一小節。
拆解成多個步驟
先將原始碼逐一編譯成目的檔 (object file):
$ g++ -c a.o a.cc
$ g++ -c b.o b.cc
$ g++ -c c.o c.cc
然後再從目的檔編譯出執行檔:
$ g++ -o program a.o b.o c.o
編譯函式庫的步驟和本小節的方式類似。詳見後文。
指定 C++ 標準版本
在編譯時加上 -std=
參數可以指定 C++ 標準的版本。以下是可用的 ISO C++ 版本:
c++98
或c++03
:相當於 ANSI C++c++11
:現代 C++ 的起始版本c++14
c++17
c++20
(實驗性質)
虛擬指令如下:
$ g++ -std=c++17 program source.cc
除了 ISO C++ 外,還可以加上 GNU extension。以下是可用的版本:
gnu++98
或gnu++03
gnu++11
gnu++14
gnu++17
gnu++20
(實驗性質)
除非專案只用 GCC 編譯,不建議使用 GNU extension。我們的教學文章不會加上這些非標準特性。
加入外部函式庫
除了少數標準函式庫的函式庫外,編譯時要用 -l
參數來指明使用的函式庫。像是 -lm
是 C 數學函式庫,即為 -l
加上 m
組合而成。
如果函式庫所在的位置非系統預設位置,還要用額外的參數來指定函式庫位置。-I
用來指定標頭檔位置,-L
則用來指定二進位檔位置。
編譯函式庫
函式庫是 C++ 用來共享程式的方式。本節介紹編譯函式庫的方式。
編譯靜態函式庫 (Static Library)
先將原始碼編譯成目的檔:
$ g++ -c a.o a.cc
$ g++ -c b.o b.cc
$ g++ -c c.o c.cc
再用 ar(1)
將目的檔編成靜態函式庫:
$ ar rcs libmylib.a a.o b.o c.o
編譯動態函式庫 (Dynamic Library)
先將原始碼編譯成目的檔。注意這時要加上 -fPIC
參數:
$ g++ -fPIC -c a.o a.cc
$ g++ -fPIC -c b.o b.cc
$ g++ -fPIC -c c.o c.cc
再將目的檔編譯成動態函式庫。注意這時要加上 -shared
參數:
$ g++ -shared -o libmylib.so a.o b.o c.o
靜態函式庫和動態函式庫的目的檔不能通用。編譯時要先清掉舊的目的檔,更改參數後再重編程式碼。