GCCのsysrootオプションについて調べてみた

## sysrootって？
GCCに`--sysroot=<dir>`というオプションがあります。僕がどこでこのオプションを知ったのか最早思い出せないのですが、組込みLinuxでのクロスコンパイルについて調べているときに、どこかで見かけたのだと思います。なんとなく、漠然と組込みLinux開発で使ったり使わなかったりしていましたが、ここらで一つ真面目に調査をし、記録を残しておこうと思います。

ただし、僕は英語についてはサッパリなので、GCCのリファレンスから正確な意味を汲み取りことができません。ですので、この記事は実践上での結果をまとめたものになるのでご注意を。

## GCCのマニュアルから機能を推測する

[gcc.gnu.org Directory-Options](https://gcc.gnu.org/onlinedocs/gcc/Directory-Options.html)に`sysroot`についての説明があります。うーん、わかったような、わからんような。

## 実際に試してみる

文章だけだとピンとこないので、実際に試してみましょう。通称のGCCとARM-GCCの二つで試してみます。

**テスト環境**

```sh
    # OS
    % lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description:    Ubuntu 16.04.1 LTS
    Release:        16.04
    Codename:       xenial

    # ホストPC GCCのバージョン 
    % gcc --version
    gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609

    # クロス GCCのインストール
    % sudo apt-get install -y gcc-arm-linux-gnueabi

    # クロス GCCのバージョン
    % arm-linux-gnueabi-gcc --version
    arm-linux-gnueabi-gcc (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609
```

`--sysroot`には存在しないディレクトリを指定してもエラーにはならないので、とりあえず適当に`/dammy`としておきます。

```sh
    % gcc --sysroot=/dammy -o hello hello.c
    hello.c:1:19: fatal error: stdio.h: そのようなファイルやディレクトリはありません
    compilation terminated.
```

通常のGCC(以下GCC)では、`stdio.h`のインクルードに失敗し、エラーになりました。ふむ。確かに標準のインクルードパスが変化しているようです。

続いてARM-GCCで同様に試してみます。

```sh
    % arm-linux-gnueabi-gcc --sysroot=/dammy -o hello hello.c
```

あれ？コンパイルが通った！？さあ何やらわけがわからなくなってきました。こういう時は`-v`オプションでGCCの内部動作を調査してみましょう。

```sh
    % gcc -v --sysroot=/dammy -o hello hello.c
    Using built-in specs.
    COLLECT_GCC=gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/5/lto-wrapper
    Target: x86_64-linux-gnu
    ...
    ignoring nonexistent directory "/dammy/usr/local/include/x86_64-linux-gnu"
    ignoring nonexistent directory "/dammy/usr/local/include"
    ignoring nonexistent directory "/usr/lib/gcc/x86_64-linux-gnu/5/../../../../x86_64-linux-gnu/include"
    ignoring nonexistent directory "/dammy/usr/include/x86_64-linux-gnu"
    ignoring nonexistent directory "/dammy/usr/include"
    #include "..." search starts here:
    #include <...> search starts here:
     /usr/lib/gcc/x86_64-linux-gnu/5/include
     /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed
    End of search list.
    ...
    hello.c:1:19: fatal error: stdio.h: そのようなファイルやディレクトリはありません
    compilation terminated.
```

ずらずらとでてくるので、無関係そうな所は除外しています。`ignoring nonexistent directory "/dammy/xxx"`というあたりがそれっぽいですね。しかし、よく見ると`/dammy`配下ではないディレクトリもインクルードサーチパスに含まれているようです。どういうことでしょうか。とりあえず、ARM-GCCも`-v`で実行してみましょう。

```sh
    % arm-linux-gnueabi-gcc -v --sysroot=/dammy -o hello hello.c
    Using built-in specs.
    COLLECT_GCC=arm-linux-gnueabi-gcc
    COLLECT_LTO_WRAPPER=/usr/lib/gcc-cross/arm-linux-gnueabi/5/lto-wrapper
    Target: arm-linux-gnueabi

    ignoring nonexistent directory "/dammy/usr/local/include/arm-linux-gnueabi"
    ignoring nonexistent directory "/dammy/usr/include/arm-linux-gnueabi"
    ignoring nonexistent directory "/dammy/usr/include"
    #include "..." search starts here:
    #include <...> search starts here:
     /usr/lib/gcc-cross/arm-linux-gnueabi/5/include
     /usr/lib/gcc-cross/arm-linux-gnueabi/5/include-fixed
     /usr/lib/gcc-cross/arm-linux-gnueabi/5/../../../../arm-linux-gnueabi/include
    End of search list.
```

こちらもsysroot配下でないディレクトリがインクルードサーチパスに含まれていますね。
その中から探してみると`stdio.h`がありました。うーん・・・。

```sh
    % cd /usr/lib/gcc-cross/arm-linux-gnueabi/5/../../../../arm-linux-gnueabi/include
    % find . -name "stdio.h" | sed -e 's/^\.\///g'
    bits/stdio.h
    stdio.h
```

--------------------------------------------------

## 実行結果から振る舞いを推測する

`/usr/local/include/`, `/usr/include/`は`sysroot`オプションの置き換え対象になっているが、`/usr/lib`配下は対象ではないっぽいですね。
そして、何故かわかりませんがARM-GCCの方は、sysrootを指定しても上書きされない固定パスに標準ライブラリのヘッダが配置されているようです。

GCCの詳細については詳しくないので推測になりますが、これはARM-GCCだから、というよりは、ビルド時にたまたまこういう設定にしていたから、と考えておいた方がよさそうな気がします。
この記事では省略していますが、G++でsysrootを指定した場合は、GCCもARM-GCCも両方`iostream`のインクルードに失敗しました。

この結果で重要なポイントは、sysrootを指定しても上書きされないパスが存在する、という部分ではないでしょうか。

--------------------------------------------------

## で、何に使うの？
ターゲット側のルートファイルシステムを`sysroot`に指定する、というのが想定される用途・・・なのかな？
しかし、一般的な組込みLinux環境ではルートファイルシステムにヘッダファイルを配置するという運用はほぼありえないので、あまり有用な使い道が思い浮かばない・・・。デフォルトサーチパスよりも`-I`や、`-L`で指定したディレクトリが優先されるので、少なくとも自分で開発しているアプリケーションをビルドするときには必要性を感じない。

RaspberryPiみたいな、PCのLinuxに近いユーザーランド環境のクロスコンパイルをしたい時は、便利なのかもしれない。

Buildrootで自分でルートファイルシステムを構築したときは、ヘッダファイルってどうなるんだろう。ヘッダファイルありのルートファイルシステムと、シュリンクされたルートファイルシステムの2つができあがったりするんだろうか。であれば、そんな時も役に立つのかも。時間があるときに試してみよう。

--------------------------------------------------

## 総括
動きはなんとなくわかったが、具体的な用途がイメージできない！まあ今回の案件では使わなくていいということはわかった。