How do I force make/gcc to show me the commands?

この見出し通りの検索が出来るようならもう答え見つけてんのと同じなのかなーとは思うけれども。

けどこれの答え探しって、検索しづらいのよねー…。

GNU のビルドツールというものはチマチマと小さな進化くらいはずっと続いていて、いつからか make の「各ステップで実行されている実際のコマンドライン」を隠蔽するのが主流になってしまった。実現してるのはこやつ。Makefile を手書きしてればこういうことは起こらないんだけどねぇ、automake やら色んな「インテリヂェンス」を使いこなしてるとこうなる。

普段はもちろんこれは嬉しい:

1 [hhsprings@localhost ffmpeg-3.2]$ make
2 CC	ffplay.o
3 ffplay.c:56:10: 致命的エラー: SDL.h: No such file or directory
4  #include <SDL.h>
5           ^~~~~~~
6 コンパイルを停止しました。
7 make: *** [common.mak:60: ffplay.o] エラー 1
8 [hhsprings@localhost ffmpeg-3.2]$ 

エラーを見逃すことはないだろうけれど、出力が静かなぶん、警告が埋もれにくくなる。隠蔽しないならこうなのだ:

本物の ffmpeg では Automake-Silent-Rules してるのでこうはならないが、そうしてないと仮定して。
1 [hhsprings@localhost ffmpeg-3.2]$ make
2 gcc -I. -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -std=c99 -fPIC -pthread -g3 -Wdeclaration-after-statement -Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes -Wempty-body -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign -Wno-unused-const-variable  -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=format-security -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=return-type -Werror=vla -Wformat -fdiagnostics-color=auto -Wno-maybe-uninitialized   -MMD -MF ffplay.d -MT ffplay.o -c -o ffplay.o ffplay.c
3 ffplay.c:56:10: 致命的エラー: SDL.h: No such file or directory
4  #include <SDL.h>
5           ^~~~~~~
6 コンパイルを停止しました。
7 make: *** [common.mak:60: ffplay.o] エラー 1
8 [hhsprings@localhost ffmpeg-3.2]$ 

そして「こうなって欲しい」(昔ながらの手書き Makefile と同じ動きをして欲しい)こと、あるでしょう? ってハナシ。コンパイルやらリンクやら何かプリプロセスやらポストプロセスやらで「問題があった場合」に、具体的な詳細を知る必要があることもあるわけだ。特にメジャーな linux みたいに超絶に問題が起こらない環境ならいいんだけど、MSVC みたいな(OSS にとっては)ドマイナーな環境だったりすれば、何も問題が起こらないことの方が稀なわけで、「誰がどのように問題を起こしているのか」を詳しく知る必要がある機会は、めっぽう多いわけだ。

最も意図に近い答えは思ったよりとんでもなく単純明快:

make VERBOSE=1 と同じという情報があったがワタシの環境ではダメだった。
1 [hhsprings@localhost ffmpeg-3.2]$ make V=1
2 gcc -I. -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -std=c99 -fPIC -pthread -g3 -Wdeclaration-after-statement -Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes -Wempty-body -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign -Wno-unused-const-variable  -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=format-security -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=return-type -Werror=vla -Wformat -fdiagnostics-color=auto -Wno-maybe-uninitialized   -MMD -MF ffplay.d -MT ffplay.o -c -o ffplay.o ffplay.c
3 ffplay.c:56:10: 致命的エラー: SDL.h: No such file or directory
4  #include <SDL.h>
5           ^~~~~~~
6 コンパイルを停止しました。
7 make: *** [common.mak:60: ffplay.o] エラー 1
8 [hhsprings@localhost ffmpeg-3.2]$ 

make そのものに慣れている人はわかると思うんだけれど、「V=1」は make そのものの魔法ではなく、これは automake やら色んなものが撒き散らしたマクロ相手の魔法、なのよね。だから知らなければそうそう簡単にはこの答えには辿りつけない。

make そのものにも魔法は仕込まれてた。--trace オプション。「Since GNU Make version 4.0」:

 1 [hhsprings@localhost ffmpeg-3.2]$ make --trace
 2 Makefile:205: ターゲット 'config.h' を .config のために更新します
 3 :
 4 common.mak:60: ターゲット 'ffplay.o' を ffplay.c のために更新します
 5 printf "CC\t%s\n" ffplay.o; gcc -I. -I./ -D_ISOC99_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_POSIX_C_SOURCE=200112 -D_XOPEN_SOURCE=600 -DPIC -std=c99 -fPIC -pthread -g3 -Wdeclaration-after-statement -Wall -Wdisabled-optimization -Wpointer-arith -Wredundant-decls -Wwrite-strings -Wtype-limits -Wundef -Wmissing-prototypes -Wno-pointer-to-int-cast -Wstrict-prototypes -Wempty-body -Wno-parentheses -Wno-switch -Wno-format-zero-length -Wno-pointer-sign -Wno-unused-const-variable  -fno-math-errno -fno-signed-zeros -fno-tree-vectorize -Werror=format-security -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=return-type -Werror=vla -Wformat -fdiagnostics-color=auto -Wno-maybe-uninitialized   -MMD -MF ffplay.d -MT ffplay.o -c -o ffplay.o ffplay.c
 6 CC	ffplay.o
 7 ffplay.c:56:10: 致命的エラー: SDL.h: No such file or directory
 8  #include <SDL.h>
 9           ^~~~~~~
10 コンパイルを停止しました。
11 make: *** [common.mak:60: ffplay.o] エラー 1
12 [hhsprings@localhost ffmpeg-3.2]$ 

やりたいこととは普通はちょっと違うのかなぁとは思うが、状況によってはこちらの方がいいかもしれない。

ちなみに「make -d」は全然意図と違うので普通は試みない方がいいよ。こんなん滅多に使わない。

思わぬ伏兵だなと思ったのは「make -n」(dry run)。これは「今実行しているもの」を見るものではなくて、「実行したフリをする」ことで、「実行したら何が起こるのか」を予め知るためのもの。だから「-n」は「install」とセットで使うことが多い。(make -n install)。ただ昔と違ってスクリプトが日に日に複雑になってきているので、見てもすぐには何をしたいのかわからないことが多かったりはするんだけれど。

StackOverflow ではほかにも、ナルホドと思うアプローチで解決してるのもあって面白かった。make SHELL='sh -x' は、あぁ言われてみれば。無論これは場合によっては必要以上に煩いよ。