GCC-6.1.0 での g++ によるシステムヘッダ検索パス

GCC-6.1.0 での g++ によるシステムヘッダ検索パス

久々に GCCを更新して最新の 6.1.0にしましたが g++でコンパイルできないトラブルがありました
GCC-6.1.0 での環境設定上の注意点をメモします

環境は次のとおりです

検証環境
CPU AMD A10-7800 (3.5GHz 4コア)
マザーボード F2A88XM-D3H(GIGABYTE製 AMD A88X Micro-ATX)
メモリ 16GB (DDR3-1333)
HDD HITACHI HDP725025GLA380 (SATA 250GB)
イーサネット Realtek GbE RTL8111F?
グラフィック RadeonR7 (内蔵GPU)
サウンド Realtek ALC887 codec (オンボード)
Linux 3.10.1
GCC 6.1.0
glibc 2.23
binutils 2.26.1

発生した問題と原因

Linux を 64bit化したときのメモ を参考にしながら binutils glibc GCC を最新化しました
で 下記テストプログラムをコンパイルすると…

$ cat tes.cpp
#include <iostream>

int main() {
 std::cout << "Hello World\n";
 return ( 0 );
}

$ g++ -o tes tes.cpp
In file included from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/ext/string_conversions.h:41: ,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/bits/basic_string.h:5402,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/string:52,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/bits/locale_classes.h:40,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/bits/ios_base.h:41,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/ios:42,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/ostream:38,
                 from /usr/gcc/6.1.0/x86_64/include/c++/6.1.0/iostream:39,
                 from tes.cpp:1:
/usr/gcc/6.1.0/x86_64/include/c++/6.1.0/cstdlib:75:25: 致命的エラー: stdlib.h: そのようなファイルやディレクトリはありません
 #include_next <stdlib.h>

コンパイルを停止しました。
$
 

単純な C++プログラムがコンパイルできないという現象でした
#include_next <stdlib.h> で stdlib.h が見つからないというのが直接の原因です

<cstdlib> (C言語で言う stdlib.h のようなもの) 内での <stdlib.h> の呼び出しが
#include から #include_next に変わったのが 最近の GCC での変更点ですが そもそも #include_next とは何でしょうか

#include_next とは システムオリジナルのヘッダ.h を 同名のヘッダでオーバーライドできる仕組みです
オリジナルの glibcのヘッダでは 問題が出るため GCCでは上書き用のヘッダを用意することでビルド環境の整合性を保っています
図にすると下記イメージです
(ユーザプログラム) #include <stdlib.h> → (GCC stdlib.h) #include_next <stdlib.h> → (glibc オリジナル stdlib.h)
stdlib.h の例では ユーザプログラム側で #include <stdlib.h> すると
glibcの stdlib.h が呼ばれる前に GCCの stdlib.h が呼ばれる仕組みとなっています
GCCの stdlib.h では必要な変更点が記載されており 変更不要な定義は glibcの stdlib.h を呼び出す動作となります

このような オーバーライドの仕組みを担保するために
#include_next で確実にオリジナルのヘッダディレクトリが探索される必要がありますが
g++ではこの辺りの挙動が変わったようです