gccの"-fmax-include-depth"オプションについて
はじめに
GCC 10.3から-fmax-include-depth
というオプションが追加されています。
(GCC 9.4のドキュメントには-fmax-include-depth
の記載は見つかりませんでした。)
-fmax-include-depth=depth
Set the maximum depth of the nested #include. The default is 200.
インクルードするファイルのネストの深さを設定できるようです。
Hello worldを例に見てみる。
例によって、以下のようにHello worldを用意します。
#include <stdio.h>
int main(void){
printf("hello\n");
return 0;
}
当然ですが、普通にコンパイル、実行はできます。
$ gcc-10 sample.c && ./a.out
hello
では、ここでインクルードしているstdio.h
から
どれだけ他のヘッダファイルがインクルードされているかを見てみます。
こういうときは-H
オプションが使えます。
-H
オプションを付けた結果は以下。
結構たくさんのヘッダファイルがインクルードされているのがわかります。
$ gcc-10 -H sample.c
. /usr/include/stdio.h
.. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h
... /usr/include/features.h
.... /usr/include/x86_64-linux-gnu/sys/cdefs.h
..... /usr/include/x86_64-linux-gnu/bits/wordsize.h
..... /usr/include/x86_64-linux-gnu/bits/long-double.h
.... /usr/include/x86_64-linux-gnu/gnu/stubs.h
..... /usr/include/x86_64-linux-gnu/gnu/stubs-64.h
.. /usr/lib/gcc/x86_64-linux-gnu/10/include/stddef.h
.. /usr/lib/gcc/x86_64-linux-gnu/10/include/stdarg.h
.. /usr/include/x86_64-linux-gnu/bits/types.h
... /usr/include/x86_64-linux-gnu/bits/wordsize.h
... /usr/include/x86_64-linux-gnu/bits/timesize.h
... /usr/include/x86_64-linux-gnu/bits/typesizes.h
... /usr/include/x86_64-linux-gnu/bits/time64.h
.. /usr/include/x86_64-linux-gnu/bits/types/__fpos_t.h
... /usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h
.. /usr/include/x86_64-linux-gnu/bits/types/__fpos64_t.h
.. /usr/include/x86_64-linux-gnu/bits/types/__FILE.h
.. /usr/include/x86_64-linux-gnu/bits/types/FILE.h
.. /usr/include/x86_64-linux-gnu/bits/types/struct_FILE.h
.. /usr/include/x86_64-linux-gnu/bits/stdio_lim.h
.. /usr/include/x86_64-linux-gnu/bits/sys_errlist.h
Multiple include guards may be useful for:
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h
/usr/include/x86_64-linux-gnu/bits/long-double.h
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h
/usr/include/x86_64-linux-gnu/bits/time64.h
/usr/include/x86_64-linux-gnu/bits/timesize.h
/usr/include/x86_64-linux-gnu/bits/typesizes.h
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h
/usr/include/x86_64-linux-gnu/gnu/stubs.h
/usr/lib/gcc/x86_64-linux-gnu/10/include/stddef.h
一番深い階層は5となるのでしょうか?
$ gcc-10 -H sample.c
. /usr/include/stdio.h ---> 1
.. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h ---> 2
... /usr/include/features.h ---> 3
.... /usr/include/x86_64-linux-gnu/sys/cdefs.h ---> 4
..... /usr/include/x86_64-linux-gnu/bits/wordsize.h ---> 5
..... /usr/include/x86_64-linux-gnu/bits/long-double.h ---> 5
....
試しに -fmax-include-depth=5
でコンパイルしてみます。
エラーが出てしまいました。
$ gcc-10 -H -fmax-include-depth=5 sample.c
. /usr/include/stdio.h
.. /usr/include/x86_64-linux-gnu/bits/libc-header-start.h
... /usr/include/features.h
.... /usr/include/x86_64-linux-gnu/sys/cdefs.h
In file included from /usr/include/features.h:461,
from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
from /usr/include/stdio.h:27,
from sample.c:1:
/usr/include/x86_64-linux-gnu/sys/cdefs.h:452:27: error: #include nested depth 5 exceeds maximum of 5 (use -fmax-include-depth=DEPTH to increase the maximum)
452 | #include <bits/wordsize.h>
| ^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:453:30: error: #include nested depth 5 exceeds maximum of 5 (use -fmax-include-depth=DEPTH to increase the maximum)
453 | #include <bits/long-double.h>
| ^
.... /usr/include/x86_64-linux-gnu/gnu/stubs.h
In file included from /usr/include/features.h:485,
from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
from /usr/include/stdio.h:27,
from sample.c:1:
/usr/include/x86_64-linux-gnu/gnu/stubs.h:10:27: error: #include nested depth 5 exceeds maximum of 5 (use -fmax-include-depth=DEPTH to increase the maximum)
10 | # include <gnu/stubs-64.h>
| ^
.. /usr/lib/gcc/x86_64-linux-gnu/10/include/stddef.h
.. /usr/lib/gcc/x86_64-linux-gnu/10/include/stdarg.h
.. /usr/include/x86_64-linux-gnu/bits/types.h
<省略>
階層の数え方(?)が違うのでしょうか、-fmax-include-depth=6
としたら
コンパイルできました。
$ gcc-10 -fmax-include-depth=6 sample.c
$ ./a.out
hello
もうちょっと単純な例で見てみる
以下のようなコードを用意してみました。
sample.cがsample.hをインクルードして、sample.h内でsample2.hをインクルードしているだけのものです。
#include "sample.h"
int main(void){
return 0;
}
#include "sample2.h"
int a;
int b;
これを-fmax-include-depth=2
でコンパイルしてみます。
$ gcc-10 -fmax-include-depth=2 sample.c
In file included from put.c:1:
sample.h:1:21: error: #include nested depth 2 exceeds maximum of 2 (use -fmax-include-depth=DEPTH to increase the maximum)
1 | #include "sample2.h"
| ^
だめでした。-fmax-include-depth=3
だと大丈夫です。
$ gcc-10 -fmax-include-depth=3 sample.c
$
何となく自分のイメージでは以下のように
ピンク色の数が階層の深さかなと思っていました。
ですが、動きを見てみると以下のようです。
(sample.cが1階層目ということ?)
デフォルトの200は?
あらためてドキュメントの記載を見ると、
以下のように記載されています。
Set the maximum depth of the nested #include. The default is 200.
なんで、デフォルトは200なのでしょうか。
ChangeLogを見ると以下の記載がありました。
2019-07-02 qing zhao
PR preprocessor/90581
* directives.c (do_include_common): Replace CPP_STACK_MAX with
CPP_OPTION (pfile, max_include_depth).
* include/cpplib.h (struct cpp_options): Add new field
max_include_depth.
* init.c (cpp_create_reader): Initiate new field max_include_depth.
* internal.h: Delete CPP_STACK_MAX.
gcc9.4のソースを見ると、以下のようにCPP_STACK_MAXが定義されていました。
/* Maximum nesting of cpp_buffers. We use a static limit, partly for
efficiency, and partly to limit runaway recursion. */
#define CPP_STACK_MAX 200
まとめ
普段何気なく#include <***.h>
とか使っていますが、
中身を追ってみると、面白そうです。
-H
オプションをヒントにコードを読んでみるのもよいかと。
clangのドキュメントはまだちゃんと読めていませんが、
-fmax-include-depth
相当のオプションはあるのでしょうか。
ドキュメントを読むといろいろなオプションが見つけられて楽しいですよ。
Discussion