satumaimoの備忘録

個人的なメモ中心

【個人的メモ】gcc -Dでインクルードファイルを定義する場合は"<"と">"をエスケープする

GCCの初歩的な話題ですが、2時間近くハマったのでメモします。

-Dオプションとは

-D name

Predefine name as a macro, with definition 1.

-D name=definition

The contents of definition are tokenized and processed as if they appeared during translation phase three in a #define directive. In particular, the definition is truncated by embedded newline characters.

(gcc(1) — Linux manual pageから引用)

-Dは、#defineのようにマクロを定義できるオプションです。

-Dを用いたインクルードファイルの定義

あるソフトウェアに、以下のようなコードが含まれていました。

hoge.c

#include <stdio.h>
#include INCLUDE_FILE

int main(void)
{
  printf("%d\n", INCLUDED_CONSTANT);
  return 0;
}

hoge.h

#define INCLUDED_CONSTANT 10

ファイル構成は以下の通りとします。

Makefile
hoge.c
Inc/
└ hoge.h

このソフトウェアのMakefileには、以下のようなコマンドでhoge.cをコンパイルするよう記述されていました。

gcc -I./Inc -DINCLUDE_FILE=<hoge.h> hoge.c

しかし、make実行時に以下のエラーが発生しました。

-bash: hoge.h: そのようなファイルやディレクトリはありません

さらに、「hoge.cの中身が空になる」という現象も起きました。

エラー文に"-bash"とあるにも関わらず私はインクルードパスの指定に問題があるか、あるいはGCCのバグだと当初は考えていました。

しかし、実際は"<"と">"がリダイレクトの記号として扱われていたのが原因でした。

従って、以下のように-Dの引数をシングルクォーテーションで囲めば正常にコンパイルできます。

gcc -I./Inc -D'INCLUDE_FILE=<hoge.h>' hoge.c

なお、先述のmanページにはこのような記述もありました。

If you wish to define a function-like macro on the command line, write its argument list with surrounding parentheses before the equals sign (if any). Parentheses are meaningful to most shells, so you should quote the option. With sh and csh, -D'name(args...)=definition' works.

最初からmanページをしっかり読んでおけば良かったですね…。

結論

シェルでコマンドを実行するとき、(リダイレクトする場合を除いて)"<"と">"は必ずエスケープする。