オプション沼(1) gcc 困ったとき?の -v オプション、眺めてみるの回

Joseph Halfmoon

普段よりコンパイラやらバイナリツールやらにはお世話になっております。コマンドラインオプションなるものあり。常々「テキトー」「惰性」です。ビルドツールにお任せで何も考えてないことさえあります。そういうことではイカンのではないかと今頃になって思い至りました。まあ、実際にやってみる、それが一番簡単。

※「オプション沼」投稿順 index はこちら

今回、実感してみまするのは、gcc の -v オプションです。-V(バージョン表示)ではありませぬぞ。小文字の方の -v です。通常使いませんな。しかし、たまに使うときはいつも苦し紛れ、インクルードパスがどっち向いているのかわからない、とか困ったときに頼るオプションであります。

※以下実験はWindows11上のWSL2で動作しているUbuntu 20.04LTSで行ってます。

-v オプション

一応、gccのオンラインドキュメントへのリンクを貼り付けさせていただきます。

GCC online documentation

その中で、-v オプションについて記載のあるのは以下のページです。

3.2 Options Controlling the Kind of Output

そこを見ても記述は素気ないっす。「コンパイラ・ドライバ」である gcc が「下請け」の奴らを呼び出す様子を詳細に出力してくれるもの。「下請け」の呼び出しの様子を冒頭のアイキャッチ画像に図にしてみましたぜ。

たまに使用させていただくと、何やら山のように出力される情報に心の扉が閉まる気がしてなりません。

まず、わすれちゃいけない大事なポイントはこの出力は標準エラー出力に向いていることであります。私は、出力をファイルに落とそうとして ‘>’ と書いて失敗しました。わすれずに ‘2>’ としないと。

今回のサンプル・プロジェクト

実際に処理するソース・ファイルが無ければ実験できないので、以下の別シリーズ記事のソースを流用いたしました。

ソフトな忘却力(27) MPFR、the Multiple Precision Floating-Point Reliable Library

MPFR「多倍長浮動小数点演算」ライブラリを使って2の平方根を少し多めの桁数で計算してみるもの。上記では以下のようなコマンドラインでコンパイルしてました。

$ gcc root2.c $(pkg-config --cflags --libs mpfr)

pkg-configコマンドがmpfrに対応していたので上記のようにオプションの生成は「お任せ」にしてます。実際にpkg-configを単独で走らせると以下のようでした。mpfrライブラリだけでなく、gmpライブラリ(こちらは浮動小数だけでない多倍長演算用)もリンクするように指示しているのね。

pkg-config

実際のコマンドラインは以下相当です。こっちゃの方がシンプルだわいな。

$ gcc root2.c -lmpfr -lgmp
-vオプションつけてコンパイルしてみる

ずらずらと大量に出力されてくる冒頭部分が以下に。gcc_configure

上記のピンク色に染めたgcc version 9.4.0というところ以降がホントの処理部分かと思います。それ以前は設定というか、gccそのものの素性というべきかもしれません。特に黄色で色をつけた Configured with 以降の表示、あまり多すぎて目が回りそうです。この部分を調べてみると gcc のオジェクトファイル内に「文字列」として含まれております。gccそのものをビルドするまえに、configure したときのオプションの一覧がそのまま取り込まれているのかなあ?知らんけど。

今回は先に進んで、大筋のみ確認したいと思います。やたらオプションなどの列挙が多く読みずらい出力ですが、結局読み取れるのはgccは以下の3つの「下請け」さんにお願いしている、という事実です。

    1. cc1
    2. as
    3. collect2

最初のcc1は、プリプロセッサ兼Cコンパイラ本体みたいっす。遥かな古代、最初にc言語習ったころには、プリプロセッサはcppというお名前で、その後コンパイラパス1のcc1、パス2のcc2などという段取りだったですが、今のgccではcc1がひとりですべてをやっておると。

その次のasは、言わずとしれたアセンブラ、gnuのアセンブラなので gas と唱えるものであります。ただ、最近は gas というと googleのアプリケーション・スクリプトの記事ばかりヒットするので肩身が狭いです。

最後のcollect2はリンカに相当するのですが、ホンモノのリンカ ld は別にあり、collect2は ld の上に一枚かぶさっている1次下請け、ldは2次下請けということみたいっす。

さて、cc1の起動部分を眺めてみます。gcc_comp2

ピンク色をみると、cc1で起動されたものの実体はGNU C17であると知れます。このGNU C17自体、GMPとかMPFRとか今回使用しているライブラリを使ってコンパイルされていることもしれます。

ちょっと見ずらいですが、黄色で塗った -o /tmp/ccrHjwRS.sという部分で、出力ファイルが .s (アセンブラ・ソース、ただし、テンポラリディレクトリ中のなんだかわからないお名前)であることもしれます。

その下をみると、インクルードパスの有無を調べたりしてますな。ということはこのあたりでヘッダファイルを読み取ってソースコードをプリプロセスしておるのでありましょう。

さてその次、再びGNU C17のグリーティング・メッセージが出力されておりますな。想像するに、このあたりでプリプロセスしたソースを実際にコンパイルしておるのでありましょう。gcc_comp3

実際のコンパイルのステージは数十ステージ?におよぶ長いもの。私は興味はありますが、今は触りますまい。興味のある方は以下へ。

GNU Compiler Collection (GCC) Internals

さてその次は、asの起動です。以下の最初の行をみると、テンポラリの仮の名前の .s アセンブラソースから、同じく仮の名前の .o オブジェクトへとアセンブルせよとあります。gcc_comp4

最後はリンカを最終的に呼び出すための collect2 です。ライブラリファイルも列挙されていますが、実行時のランタイムライブラリらしきものなどもリンク指定されているのが見てとれます。gcc_comp5

-vオプション、ほんわか慣れた? お次は何?

オプション沼(2) gcc、いつもの-gオプション。objdumpにも-gあったのね。へ進む