macOS Catalina(10.15) の Xcode11 だと /usr/include が無い

# はじめに

実は、主に Mojave(10.14) で利用していた Xcode10 の頃から /usr/include は非推奨でした。
まず、Xcode10 を導入すると /usr/include が消えます。手動で復活させてもマイナー更新でいつの間にか消えたりしました。

- (参考) Xcode10 の /usr/include インストール方法 (mojave)
  - https://qiita.com/yoya/items/630c991a98e4554e6e87

# Xcode10 リリースノート

Xcode10 から /usr/include が無い件は、そのリリースノートに説明があります。

- https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes#3035624

```
 The command line tools will search the SDK for system headers by default.
 However, some software may fail to build correctly against the SDK and
require macOS headers to be installed in the base system under /usr/include.
 If you are the maintainer of such software, we encourage you to update
your project to work with the SDK or file a bug report for issues that are
preventing you from doing so. 
```

つまり、/usr/include でなく、SDK の中にあるヘッダを使えという事です。
ビルド出来ないソフトウェアは、バグレポートを出すなりメンテナなら自分で対応するなりして欲しいと。

ただ、Xcode10 の時点では /usr/include を復活させるパッケージを提供していました。

- https://developer.apple.com/documentation/xcode_release_notes/xcode_10_release_notes#3035624

```
 As a workaround, an extra package is provided which will
install the headers to the base system.
 In a future release, this package will no longer be provided.
```

これはワークアラウンドであって、今後のリリース(=Xcode11以降)では提供しないパッケージだと明言しています。

# SDK header path

```shell
% xcrun --show-sdk-path
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
```
この下に /usr/include が存在します。

```shell
% ls `xcrun --show-sdk-path`
Entitlements.plist	SDKSettings.json	System
Library			SDKSettings.plist	usr
% ls `xcrun --show-sdk-path`/usr
bin	include	lib	libexec	share
```

なお、実体は 〜/SDKs/MacOSX10.15.sdk/〜 で、〜/SDKs/MacOSX.sdk/ はそこへのシンボリックリンクです。xcrun が MacOSX.sdk を示してるので、何か特別な理由がなければ MacOSX10.15.sdk を直接参照しない方が良さそうな気がします。(あやふや

# 影響

Xcode コマンドラインツールのコンパイラである cc は当然この SDK の path を見ていますし、brew でインストールした gcc もこの path に対応しているようです。

```shell
% /usr/local/bin/gcc-9 -v
Using built-in specs.
COLLECT_GCC=/usr/local/bin/gcc-9
COLLECT_LTO_WRAPPER=/usr/local/Cellar/gcc/9.2.0_1/libexec/gcc/x86_64-apple-darwin19/9.2.0/lto-wrapper
Target: x86_64-apple-darwin19
Configured with: ../configure --build=x86_64-apple-darwin19 --prefix=/usr/local/Cellar/gcc/9.2.0_1 --libdir=/usr/local/Cellar/gcc/9.2.0_1/lib/gcc/9 --disable-nls --enable-checking=release --enable-languages=c,c++,objc,obj-c++,fortran --program-suffix=-9 --with-gmp=/usr/local/opt/gmp --with-mpfr=/usr/local/opt/mpfr --with-mpc=/usr/local/opt/libmpc --with-isl=/usr/local/opt/isl --with-system-zlib --with-pkgversion='Homebrew GCC 9.2.0_1' --with-bugurl=https://github.com/Homebrew/homebrew-core/issues --disable-multilib --with-native-system-header-dir=/usr/include --with-sysroot=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk
Thread model: posix
gcc version 9.2.0 (Homebrew GCC 9.2.0_1)
```

実際に困るケースとしては、ビルドシステムとしての autoconf や cmake のルール記述で /usr/include を決め打ちしている場合や、pkg-config 用の .pc ファイルで同様に決め打ちしている場合、正常にビルド出来なくなるでしょう。

## 実例 (ImageMagick)

現時点、brew でライブラリを揃えた環境に於いて、ImageMagick を configure, make しようとするとエラーが出て失敗します。

```shell
% make
<略>
  CC       MagickCore/libMagickCore_7_Q16HDRI_la-magick.lo
MagickCore/magick.c:100:12: fatal error: 'libxml/parser.h' file not found
#  include <libxml/parser.h>
           ^~~~~~~~~~~~~~~~~
1 error generated.
make[1]: *** [MagickCore/libMagickCore_7_Q16HDRI_la-magick.lo] Error 1
make: *** [all] Error 2
```

これは brew が示す SDK 側の libxml2 の情報が間違えているからだと思われます。

```shell
% find /usr/local -name "libxml*.pc"
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.8/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.9/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.10/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.11/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.14/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.13/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.12/libxml-2.0.pc
/usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.15/libxml-2.0.pc
/usr/local/Cellar/libxml2/2.9.9_2/lib/pkgconfig/libxml-2.0.pc
```

```shell
% cat /usr/local/Homebrew/Library/Homebrew/os/mac/pkgconfig/10.15/libxml-2.0.pc
prefix=/usr
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
modules=1

Name: libXML
Version: 2.9.4
Description: libXML library version2.
Requires:
Libs: -L${libdir} -lxml2
Libs.private: -lz -lpthread -licucore -lm
Cflags: -I${includedir}/libxml2
```

### 解決策1

/usr/bin/xml2-config は正しいパスを返すので、以下のように対処できます。

```shell
% env CFLAGS="$(xml2-config --cflags)" \
      XML_CFLAGS="$(xml2-config --cflags)" \
      XML_LIBS="$(xml2-config --libs)" \
  ./configure
% make
```

数年前まで ImageMagick も configure 時に xml2-config を使っていたのですが、いつの間にか pkg-config 使うようになってますね。まぁ pkg-config は色々なパッケージを解決できるので、これに寄せるのは美しいですし、今回のは brew 側の事故みたいなものです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">
https://github.com/ImageMagick/ImageMagick/commit/32f75d4dfc71aa7f04bef7191c03f2cbb7885de4#diff-e2d5a00791bce9a01f99bc6fd613a39dR31880
このコミットで、何故か受け付けておいたXML_CFLAGSを空にする手続きが書かれていました。

XML_CFLAGSを使わずにpkg-configがあれば使う様になってますね。これ移行masterまでずっとこうなってるのでconfigureに問題があると言えそうです。
</p>&mdash; bosturbo (@bosturbo) <a href="https://twitter.com/bosturbo/status/1181533443831652359">2019年10月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

### 解決作2

brew でインストールした libxml2 を使う場合はこうです。

```shell
% env PKG_CONFIG_PATH="/usr/local/opt/libxml2/lib/pkgconfig" \
  ./configure
% make
```

# 感謝

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">
MojaveでCommand Line Toolsを入れた状態で、
git clone https://github.com/ImageMagick/ImageMagick.git
cd ImageMagick
env CFLAGS="$(xml2-config --cflags)" XML_CFLAGS="$(xml2-config --cflags)" XML_LIBS="$(xml2-config --libs)" ./configure
make
したらbuild通りました。
</p>&mdash; bosturbo (@bosturbo) <a href="https://twitter.com/bosturbo/status/1181494743370387457">2019年10月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">
複数の開発版を共存させたいからですね。コンパイラは元々、それが可能なようになっている。ということは、/usr/includeを直接書くのは反則ってことかな。
</p>&mdash; Shinji Kono (@shinji_kono) <a href="https://twitter.com/shinji_kono/status/1181571962642010114">2019年10月8日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 追記 (2019/10/17)

--sysroot オプション、SDKROOT 環境変数と、それらに関連する解説がありましたので紹介します。

- macOS 10.15 CatalinaとXcode 11で/usr/includeが見つからない問題
  - https://qiita.com/imbsky/items/da709a514dded95b8575#_reference-9265170a4623682826ab

```shell
% export SDKROOT="$(xcrun --sdk macosx --show-sdk-path)"
```

なお、--sdk macosx を省略すると表示するパス名は違いますが、シンボリックリンクで同じ場所になります。

```shell
% xcrun --show-sdk-path
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk
% xcrun --sdk macosx --show-sdk-path
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk
% ls -l /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/
total 0
drwxr-xr-x  4 root  wheel  128 10  8 09:38 DriverKit19.0.sdk
drwxr-xr-x  8 root  wheel  256 10  8 09:39 MacOSX.sdk
lrwxr-xr-x  1 root  wheel   10  9 24 01:46 MacOSX10.15.sdk -> MacOSX.sdk
```

--sdk は文字通り、SDK の指定に使うようで、例えば driverkit だとこうなります。

```
% xcrun --sdk driverkit --show-sdk-path
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/DriverKit19.0.sdk
```