🐨

#include_nextについて(gcc, clangのinclude pathについて)

2021/04/11に公開

はじめに

nuttxをclangでビルドしたときに以下のようなエラーが出ました。

In file included from stdio/lib_dtoa_engine.c:41:
In file included from /home/saitoyutaka/spresense/nuttx/include/math.h:52:
/home/saitoyutaka/spresense/nuttx/../sdk/include/arch/math.h:42:15: fatal error: 'math.h' file not found
#include_next <math.h>
              ^~~~~~~~
1 error generated.
ERROR: clang -v failed: 1

#include_nextがよくわからなかったので調べてみました。

include_next ドキュメント

gccのドキュメントはここ

include_nextはいつからあるか。

不明。
gccのコードを取ってきて、grepしたら以下のようなものが引っかかりました。
1998年くらいには #include_nextというものはあったのでしょうか。

gcc/ChangeLog-1998
1998-12-16  Zack Weinberg

	* cpplib.c (do_include): Treat #include_next in the
	primary source file as #include plus warning.  Treat
	#include_next in a file included by absolute path as an
	error.  fp == CPP_NULL_BUFFER is a fatal inconsistency.

include_nextを試しに使ってみる

以下のようにファイルを用意。

.
├── inc
│   └── h1.h
├── inc2
│   └── include
│       └── h1.h
└── src
    └── main.c

ファイルの中身はそれぞれ以下のようにする。

main.c
#include <stdio.h>
#include <h1.h>

int main(void){
    printf("hello %d\n", INC_NUM1);
    printf("hello %d\n", INC_NUM_TEST);
    return 0;
}
inc/h1.h
#define INC_NUM1 11
#define INC_NUM_TEST 11

#include_next <h1.h> // inc2/include/h1.h
inc2/include/h1.h
#define INC_NUM_TEST 12

以下のようにコンパイル。
INC_NUM_TESTの値が12(include/h1.h)となる。

$ gcc -isystem ../inc -isystem ../inc2/include main.c 
$ ./a.out 
hello 11
hello 12

clangではどうか。

$ clang -isystem ../inc -isystem ../inc2/include main.c 
$ ./a.out 
hello 11
hello 12

上記のように、#include_nextを使うと、
inc/h1.hの次にある検索パスのinc2/include/h1.hが読み込まれます。

sdk/include/arch/math.hに以下のようにコメントが書かれていますが、

#ifndef SDK_INCLUDE_ARCH_MATH_H
#define SDK_INCLUDE_ARCH_MATH_H

/* XXX: #include_next directive is only in GCC. */

#include_next <math.h>

最近(?)はclangでも#include_nextは使用できるようになっているようでした。

"はじめに"で書いたエラーはなんで出た?

次に、以下のようなコードを用意します。

sample.c
#include <math.h>
#include_next <math.h>

int main(void){
    return 100;
}

今度は、arm用にコンパイルをします。

$ arm-none-eabi-gcc -mabi=aapcs -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -c sample.c 
sample.c:2:2: warning: #include_next in primary source file
    2 | #include_next <math.h>
      |  ^~~~~~~~~~~~
$ file sample.o
sample.o: ELF 32-bit LSB relocatable, ARM, EABI5 version 1 (SYSV), not stripped

ワーニングはでるけど、コンパイルはできる。
つづいてclagで確認。

$ clang -target arm-none-eabi -march=armv7-m -mcpu=cortex-m4 -c sample.c
sample.c:1:10: fatal error: 'math.h' file not found
#include <math.h>
         ^~~~~~~~
1 error generated.

#includeのところでファイルがないよ、とエラーとなりました。
原因はコンパイル時のオプションのに-vをつけるとわかります。

gccの場合
#include <...> search starts here:以降の出力に注目。

$ arm-none-eabi-gcc -mabi=aapcs -mcpu=cortex-m4 -mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=hard -c -v sample.c 
Using built-in specs.
COLLECT_GCC=arm-none-eabi-gcc
Target: arm-none-eabi
<省略>
#include "..." search starts here:
#include <...> search starts here:
 /home/saitoyutaka/arm-gcc/gcc-arm-none-eabi-10-2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/include
 /home/saitoyutaka/arm-gcc/gcc-arm-none-eabi-10-2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/include-fixed
 /home/saitoyutaka/arm-gcc/gcc-arm-none-eabi-10-2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/include
End of search list.
GNU C17 (GNU Arm Embedded Toolchain 10-2020-q4-major) version 10.2.1 20201103 (release) (arm-none-eabi)
        compiled by GNU C version 4.8.4, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: e9addb35ad3a920a846c18a834db924d
sample.c:2:2: warning: #include_next in primary source file
    2 | #include_next <math.h>
      |  ^~~~~~~~~~~~
<省略>

clangの場合

$ clang -target arm-none-eabi -march=armv7-m -mcpu=cortex-m4 -c -v sample.c
clang version 11.0.0 (https://github.com/llvm/llvm-project.git 0160ad802e899c2922bc9b29564080c22eb0908c)
Target: arm-none-unknown-eabi
<省略>
#include "..." search starts here:
#include <...> search starts here:
 /home/saitoyutaka/clang/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04/lib/clang/11.0.0/include
End of search list.
sample.c:1:10: fatal error: 'math.h' file not found
#include <math.h>
         ^~~~~~~~
1 error generated.

clangの場合includeパスが
/home/saitoyutaka/clang/clang+llvm-11.0.0-x86_64-linux-gnu-ubuntu-20.04/lib/clang/11.0.0/includeのみです。
しかもパスの名前からするとarm用っぽくない。

不明点

arm-none-eabi-gcc の場合
/lib/gcc/arm-none-eabi/10.2.1/include
/lib/gcc/arm-none-eabi/10.2.1/include-fixed
/lib/gcc/arm-none-eabi/10.2.1/../../../../arm-none-eabi/include
のパスはデフォルトで入る?

まとめ

いろいろ、調べてみましたが原因は
インクルードパスの設定ができていないことが原因でいた。
#include_next directive is only in GCC.というコメントが
あったので、最初はclangでは(include_nextを使用しないで)どうやるのかな、
と考えていろいろ調べてしまっていました。(はー)

Discussion