All Articles

C 言語のヘッダファイルの在り処と、「<なんとか>.h」がないというエラーへの対応について

例えば Ruby や Python などで MySQL のクライアントライブラリを入れようとしたりすると、C 言語のヘッダファイル (<なんとか>.h) がないというエラーになったりすることがあります。

そういった際はなんとなくググって解決できることも多いですが、根本的には必要なファイルを探す方法を身につけることが望ましいです。

そこでこの記事には、

  • C 言語のヘッダファイルがどこにあるのか
  • 「<なんとか>.h」をインストールする方法

について、自分に分かる範囲で書いていきます。

検証環境

まずは、検証環境について載せておきます。 (Ubuntu 20.04 です)

$ uname -a
Linux oshima-desktop 5.13.0-52-generic #59~20.04.1-Ubuntu SMP Thu Jun 16 21:21:28 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
$ gcc --version
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

そもそも C 言語のヘッダファイルはどこにあるのか

さて、それではまず前提として、C 言語のヘッダファイルがどこにあるのかから見ていきます。

Google などで調べてみてもいいですが、「C 言語のコンパイル時にも参照されているはず」というアイデアで見てみようと思います。

まずは C 言語のサンプルコードを作成します。

#include <stdio.h>

int main()
{
  printf("Hello world!\n");
  exit(0);
}

gcc でコンパイルします。

このとき、-v オプションで実行の詳細を表示してみます。

$ gcc -o hello hello.c -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper
OFFLOAD_TARGET_NAMES=nvptx-none:hsa
OFFLOAD_TARGET_DEFAULT=1
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu 9.4.0-1ubuntu1~20.04.1' --with-bugurl=file:///usr/share/doc/gcc-9/README.Bugs --enable-languages=c,ada,c++,go,brig,d,fortran,objc,obj-c++,gm2 --prefix=/usr --with-gcc-major-version-only --program-suffix=-9 --program-prefix=x86_64-linux-gnu- --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --with-default-libstdcxx-abi=new --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --enable-default-pie --with-system-zlib --with-target-system-zlib=auto --enable-objc-gc=auto --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-offload-targets=nvptx-none=/build/gcc-9-Av3uEd/gcc-9-9.4.0/debian/tmp-nvptx/usr,hsa --without-cuda-driver --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1) 
COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/cceK2Ql4.s
GNU C17 (Ubuntu 9.4.0-1ubuntu1~20.04.1) version 9.4.0 (x86_64-linux-gnu)
	compiled by GNU C version 9.4.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/include-fixed"
ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/9/../../../../x86_64-linux-gnu/include"
#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/9/include
 /usr/local/include
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.
GNU C17 (Ubuntu 9.4.0-1ubuntu1~20.04.1) version 9.4.0 (x86_64-linux-gnu)
	compiled by GNU C version 9.4.0, GMP version 6.2.0, MPFR version 4.0.2, MPC version 1.1.0, isl version isl-0.22.1-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: c0c95c0b4209efec1c1892d5ff24030b
hello.c: In function ‘main’:
hello.c:6:3: warning: implicit declaration of function ‘exit’ [-Wimplicit-function-declaration]
    6 |   exit(0);
      |   ^~~~
hello.c:6:3: warning: incompatible implicit declaration of built-in function ‘exit’
hello.c:2:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘exit’
    1 | #include <stdio.h>
  +++ |+#include <stdlib.h>
    2 | 
COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64'
 as -v --64 -o /tmp/ccolkcv4.o /tmp/cceK2Ql4.s
GNU アセンブラ バージョン 2.34 (x86_64-linux-gnu)、BFD バージョン (GNU Binutils for Ubuntu) 2.34 を使用
COMPILER_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/
LIBRARY_PATH=/usr/lib/gcc/x86_64-linux-gnu/9/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib/:/lib/x86_64-linux-gnu/:/lib/../lib/:/usr/lib/x86_64-linux-gnu/:/usr/lib/../lib/:/usr/lib/gcc/x86_64-linux-gnu/9/../../../:/lib/:/usr/lib/
COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64'
 /usr/lib/gcc/x86_64-linux-gnu/9/collect2 -plugin /usr/lib/gcc/x86_64-linux-gnu/9/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/9/lto-wrapper -plugin-opt=-fresolution=/tmp/cczXFzh6.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o hello /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/9/crtbeginS.o -L/usr/lib/gcc/x86_64-linux-gnu/9 -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/9/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/9/../../.. /tmp/ccolkcv4.o -lgcc --push-state --as-needed -lgcc_s --pop-state -lc -lgcc --push-state --as-needed -lgcc_s --pop-state /usr/lib/gcc/x86_64-linux-gnu/9/crtendS.o /usr/lib/gcc/x86_64-linux-gnu/9/../../../x86_64-linux-gnu/crtn.o
COLLECT_GCC_OPTIONS='-o' 'hello' '-v' '-mtune=generic' '-march=x86-64'

この中を見てみると、

 /usr/lib/gcc/x86_64-linux-gnu/9/cc1 -quiet -v -imultiarch x86_64-linux-gnu hello.c -quiet -dumpbase hello.c -mtune=generic -march=x86-64 -auxbase hello -version -fasynchronous-unwind-tables -fstack-protector-strong -Wformat -Wformat-security -fstack-clash-protection -fcf-protection -o /tmp/cceK2Ql4.s

という箇所で実際のコンパイラ (cc1) が実行されているようです。

※ gcc は広義では「コンパイラ」ですが、実際には内部で狭義のコンパイラ (cc1) やアセンブラ (as)、リンカなど (collect2) を呼び出しており、「コンパイラドライバ」と呼ばれることもあるそうです。

さて、cc1 の実行以降の出力を見てみると…

#include "..." search starts here:
#include <...> search starts here:
 /usr/lib/gcc/x86_64-linux-gnu/9/include
 /usr/local/include
 /usr/include/x86_64-linux-gnu
 /usr/include
End of search list.

ということで、#include の検索をしている箇所が見つかりました。

ここに表示されているパスから、ヘッダファイルを探しているようですね。

ls などで見てみると、たしかにヘッダファイルが見つかります。

必要なヘッダファイルをインストールするには

ここから、不足しているヘッダファイルを探してインストールする方法を書いていきます。

例えば Ruby や Python などで MySQL のクライアントライブラリを使いたい場合に、C 言語のヘッダファイルがないというエラーになったりすることがあります。

そんな例であれば、

$ sudo apt install libmariadb-dev

のようにして、libmariadb-dev などをインストールして解決することになります。

これは、求められているヘッダファイルが libmariadb-dev に含まれているためです。

libmariadb-dev に含まれているファイルは、以下のように見ることができます。

$ dpkg -L libmariadb-dev 
/.
/usr
/usr/bin
/usr/bin/mariadb_config
/usr/include
/usr/include/mariadb
    :
/usr/include/mariadb/mysql.h
    :

ということで、libmariadb-dev をインストールすると、やはり /usr/include 以下にヘッダファイルが配置されるようですね。

本来はこれとは逆で、あるヘッダファイルを含むパッケージを知りたいはずです。

apt-file コマンドを使うことで、指定したヘッダファイルを含むパッケージを検索できます。

$ apt-file search mysql.h
    :
libgdal-doc: /usr/share/doc/libgdal-doc/gdal/drv_mysql.html
libgearman-doc: /usr/share/doc/libgearman-doc/html/gearmand/queues/mysql.html
libmariadb-dev: /usr/include/mariadb/mysql.h
libmariadb-dev: /usr/include/mariadb/server/mysql.h
libmariadb-dev: /usr/include/mariadb/server/private/probes_mysql.h
libmysqlclient-dev: /usr/include/mysql/mysql.h
libodb-api-dev: /usr/include/x86_64-linux-gnu/mysql.h
    :

mysql.h と検索してみましたが、libmariadb-dev 以外にも大量のパッケージが見つかりました。

おわりに

以上、C 言語のヘッダファイルの在り処と、「<なんとか>.h」がないというエラーへの対応について見てきました。

このあたりは個人的になんとなくやっていた部分があるので、もっと知識をつけていこうと思います。

関連書籍

リンカ・ローダ実践開発テクニック