(解決済み) Xcode14 & Mac M1環境下でgrpcioが突然インストールできなくなったので対処した話

Google Cloud Platform(GCP)サービスをPythonなどから触るとき、grpcioライブラリがついて回ります。grpcioはc++で組まれている関係で、CPUアーキテクチャなどの環境によってビルドできたりビルドできなかったりが起こりやすいです。ある日、grpcioライブラリがインストールできない状態になり、調査の上解決したので忘備録を共有します。

<!-- more -->

**2022.11.3 追記: Xcode 14.1(14B47b)で本問題が解消されていることを確認しました！Xcode 14系はXcode 14.1以上を使えば良さそうです。**

## TL;DR

1. Xcode 14.0.xではgrpcioのビルドができないため、Xcode 13系を`/Applications/Xcode.app`に置いた上でビルドしましょう。

2. python 3.9.14や3.10.6を使えるのであればアップデートしましょう。

アップデートできない場合は以下のステップを踏みます。

- - - 

grpcioのインストールに失敗したとき、ビルドログを見て以下の対処をします。

1. `error: expected unqualified-id`が頻出している → Xcode 14.0.xを使っているときに発生します。Xcode 13以下を`/Applications/Xcode.app`に用意しましょう
1. `fatal error: 'openssl/ssl.h' file not found`が頻出している → OpenSSLのライブラリファイルに参照できないときに発生します。以下の様にOpenSSLのライブラリパスを通しておき、`export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1`と`export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1`を設定してシステム側のOpenSSLとzlibを参照させるようにします。

```
export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl@3/include"
export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@3/lib/pkgconfig:${PKG_CONFIG_PATH}"
export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1
export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1
```

※ Homebrew以外でOpenSSLを入れている場合は、上記LDFLAGS, CPPFLAGS, PKG_CONFIG_PATHは適宜読み替えてください。

- - -

## 経緯
ピリカでは、GCPベースで各種サービスを提供しています。特にバックエンド部分については、Cloud TaskやCloud Loggingなどのサービスを使う関係上、プロセス間通信でgrpcioが使われています。

ある日、M1 Mac環境下でpipenvで依存ライブラリを更新しようとしたところ、突然grpcioのインストールに失敗した旨が4000行近くのエラーログとともに表示されました。

そこで、grpcioをインストールできるようにすべく調査しました。

## 開発環境
- MacBook Pro (M1, 2020)
- macOS Monterey 12.6
- pyenv 2.3.4
- pipenv 2022.9.24
- Xcode: 14.0.1が`/Application/Xcode.app`、13.4.1が`/Application/Xcode_13.app`に存在
- パッケージマネージャ: Homebrew 3.6.4
- これまでインストールできていたgrpcio: 1.49.1以前のすべて

## 調査
### 1. error: expected unqualified-id について調査
これまでgrpcioの最新バージョンである1.49.1でも1.47.0でも、M1 Mac環境下でインストールできていました。そのため、grpcio依存の問題ではなく、開発環境の問題なのかと思いました。エラーログを見てみると、以下の様になっていました。

```
[pipenv.exceptions.InstallError]:       third_party/abseil-cpp/absl/time/time.h:460:14: error: expected unqualified-id
```

この中で、`error: expected unqualified-id`がビルド時のエラー内容だと思いました。そこで、`error: expected unqualified-id grpcio`で同様の事例がないか調べてみたところ、以下のIssueが見つかりました。

- https://github.com/grpc/grpc/issues/30723

ここではPythonを3.10.6や3.9.14にアップデートするか、grpcioを1.46.3に固定するとインストールできる旨が記載されていました。

しかしながら、2022年10月4日現在、pyenvにて3.9.13が未サポートなことと、grpcioのバージョンを固定するとGCPの各ライブラリのバージョンを上げられなくなります。そこで、エラーログを見返しました。

```
[pipenv.exceptions.InstallError]:       /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdlib.h:301:30: third_party/abseil-cpp/absl/strings/internal/cordz_info.h:28:
...
```

すると、`/Applications/Xcode.app/...`と記載があり、そこでヘッダーファイルなどを参照していました。そこで振り返ると、数日前にXcode 14.0.1を`/Applications/Xcode.app`に入れて、なおかつXcode 13.4.1を`/Applications/Xcode_13.app`に移していました。このため、Xcode 13.4.1を`/Applications/Xcode.app`に戻したところ、当該エラー文自体は表示されなくなりました。ただ、引き続きgrpcioのビルド自体は失敗していたので、さらにエラーログを見ました。

### 2.fatal error: 'openssl/ssl.h' file not found について調査
1. が解決したあとのエラーログでは以下の表示がありました。

```
[pipenv.exceptions.InstallError]:       ./src/core/tsi/ssl/key_logging/ssl_key_logging.h:23:10: fatal error: 'openssl/ssl.h' file not found

```

こちらは比較的わかりやすいエラーで、openssl関連のヘッダファイルが見つからないという内容です。なので、OpenSSLのライブラリへのパスを通し、かつそちらを使う設定でgrpcioをビルドすると良さそうです。

- https://github.com/grpc/grpc/issues/25082

によると、

- `GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1`と`GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1`を指定し、MacOS上にインストールしているOpenSSLとzlibを参照する設定にする
  - これにともない、Homebrewなどで、OpenSSLおよびzlibのインストールが必要
- LDFLAGS, CFLAGS(あるいはCPPFLAGSでも可)でOpenSSLのライブラリパスとインクルードパスを指定する

の2点(OpenSSLとzlibのインストールも含めると3点)が有効でした。

そこで、以下の設定を`~/.zshrc`に書き込み、再度ビルドしたところインストールに成功しました！

```
export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib"
export CFLAGS="-I/opt/homebrew/opt/openssl@3/include"
export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1
export GRPC_PYTHON_BUILD_SYSTEM_ZLIB=1
```

※ パッケージ管理でHomebrew以外をお使いの方は、CLFLAGSおよびCFLAGSについて適宜パスを読み替えてください

以上、ご覧いただきありがとうございました！