2014年09月11日

GNU CPP(GCC)の独自拡張#include_next指令

Warp の挙動を調べている時に、GCC のプリプロセッサの #include_next 指令の挙動にかなり悩んだので、備忘録も兼ねてドキュメントの日本語訳をアップロードします。

厳密な仕様が無く、あまり有名でもない(?)独自拡張なので(ARM CC や IBM XL C/C++ など、一応 GCC 以外のコンパイラのプリプロセッサにも取り入れられているようですが)、情報が少なく、実際にいろいろ動かして実験してみないと挙動がよくわからず、かなり混乱しました。以下の翻訳もあまり自信が無いので、何かお気づきの点があれば、コメント欄にてご指摘いただけると幸いです。(ただし、現在スパムコメントがあまりにも多いため、半角英数字のみのコメント、国外の IP アドレスからのコメント、改行が 10 個以上あるコメントは受け付けない設定になってます。ご注意ください。)

ちなみにこの記事は、問題を理解してもらうための布石で、実際に悩んだ問題は、また後日に解説します。



The C Preprocessor 2.7 Wrapper Headers (2014/9/11 閲覧)
https://gcc.gnu.org/onlinedocs/cpp/Wrapper-Headers.html

(以下の文章は、文章用のコピーレフトライセンスである GFDL で公開された文章の派生となるので、GFDL に従って自由に複製/改変/頒布等が可能です。)

時には、システムが提供するヘッダファイルを直接編集すること無しに、その内容を直す必要がある。例えば GCC の fixincludes 操作(訳注: GCC をビルドする際に、システムヘッダに不具合がある場合に実行される fixincludes スクリプトのことだと思われる)はそれを行う。一つの方法として、(修正対象のヘッダファイルと)同名の新しいヘッダを作成し、元のヘッダファイルの検索パスよりも前に検索パスを追加する方法がある。この方法は、あなたが古いヘッダファイルを完全に置き換えることを厭わない限り、正しく動作する。しかし、もし新しいヘッダファイルから古いヘッダファイルを参照したい場合はどうなるだろうか?
(Sometimes it is necessary to adjust the contents of a system-provided header file without editing it directly. GCC's fixincludes operation does this, for example. One way to do that would be to create a new header file with the same name and insert it in the search path before the original header. That works fine as long as you're willing to replace the old header entirely. But what if you want to refer to the old header from the new one?)

あなたは単純に古いヘッダファイルを #include することはできない。それをやってしまうと、(GCC のプリプロセッサは、検索パスリストの)先頭から(検索を)開始し、再びあなたが作った新しいヘッダを見つけてしまう。もしあなたのヘッダファイルが多重インクルード対策(参考 Once-Only Headers)をしていなければ、これが無限に繰り返され、致命的なエラーを発生させるだろう。
(You cannot simply include the old header with ‘#include’. That will start from the beginning, and find your new header again. If your header is not protected from multiple inclusion (see Once-Only Headers), it will recurse infinitely and cause a fatal error.)

あなたは以下のように古いヘッダファイルを絶対パス名でインクルードすることも可能だが。
(You could include the old header with an absolute pathname:)
     #include "/usr/include/old-header.h"
これは動作するものの、綺麗なやり方ではない。常にシステムヘッダーの場所は変わるだろうし、あなたはそれに合わせて(作成した)新しいヘッダを修正しなければならない。
This works, but is not clean; should the system headers ever move, you would have to edit the new headers to match.

標準 C の範囲でこの問題を解決する方法は無いが、あなたは #include_next という GNU 拡張を使うことができる。これは「この名前の、次のファイルをインクルードする」ことを意味する。この指令は、指定されたファイルの検索以外は #include のような動作をする。つまり、カレントファイル(#include_next 指令行が記述されたファイル)が見つかったディレクトリの次から、ヘッダファイルディレクトリのリストの検索を開始する。
(There is no way to solve this problem within the C standard, but you can use the GNU extension ‘#include_next’. It means, “Include the next file with this name”. This directive works like ‘#include’ except in searching for the specified file: it starts searching the list of header file directories after the directory in which the current file was found.)

あなたは(GCC に対して)-I /usr/local/include オプションを指定していて、検索対象のディレクトリリストに /usr/include も含まれると仮定しよう。また、両方のディレクトリに signal.h が存在すると仮定しよう。通常の #include <signal.h> は、このファイルを /usr/local/include 以下で見つける。もしそのファイル(最初に見つかった /usr/local/include/signal.h)が #include_next <signal.h> を含む場合、そのディレクトリ(/usr/local/include)の次から検索を開始し、そして /usr/include 以下にそのファイル(signal.h)を見つける。
(Suppose you specify -I /usr/local/include, and the list of directories to search also includes /usr/include; and suppose both directories contain signal.h. Ordinary #include <signal.h> finds the file under /usr/local/include. If that file contains #include_next <signal.h>, it starts searching after that directory, and finds the file in /usr/include.

#include_next は <file> と "file" のインクルードを区別しないし、あなたが(#include_next で)指定したファイルがカレントファイル(#include_next 指令行を含むファイル)と同名かどうかもチェックしない。それは単純にカレントファイルが見つかったディレクトリの次の検索パスのディレクトリから、ファイルの検索を開始するだけだ。
(‘#include_next’ does not distinguish between and "file" inclusion, nor does it check that the file you specify has the same name as the current file. It simply looks for the file named, starting with the directory in the search path after the one where the current file was found.)

#include_next の使用は大混乱をもたらし得る。我々は、他に代替手段が無い場合にのみ、その使用を推奨する。特に、ある特定のプログラムに付属するヘッダファイル群では使用するべきではない。それは、fixincludes のような(※)の行に従って(訳注: ここの意味がよくわからなかった)、グローバルな(システム全域に影響する、システムヘッダの)修正を行うためにのみ使用するべきだ。
(The use of ‘#include_next’ can lead to great confusion. We recommend it be used only when there is no other alternative. In particular, it should not be used in the headers belonging to a specific program; it should be used only to make global corrections along the lines of fixincludes.)
(※)コメントでのご指摘ありがとうございました!

トラックバックURL

コメント一覧

1. Posted by K   2014年10月16日 17:48
along the lines of は 「〜のように」という熟語ですね。
2. Posted by 若槻   2014年10月22日 09:29
ご指摘ありがとうございました!修正いたしました。

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード