Windows の pip で Pygrib をインストールする

Windows,お役立ち情報,プログラムPip,pygrib,Python,Windows10

気象庁が出している数値予報データなどの GPV (Grid Point Value) を扱う Python ライブラリに Pygrib というものがあります。この記事では Windows 10 で pip を使って Pygrib を入れようとしたらビルドエラーが出てうまくいかなかったため、頑張って何とかした話です。

概要と環境

Pygrib を pip でインストールする手順を簡単にまとめると次のとおりです。

  • grib_api を Visual Studio 経由でビルドする
  • ビルドしたライブラリなどのパスを設定して pip でインストールする

全体的にはブログ記事「pygrib が Microsoft Visual Studio でビルド出来るようになる話」を参考にしました。

実行環境は以下の通りでした。

  • Windows 10 (バージョン 21H2)
  • Python 3.9.13

ただ、pip だとうまくビルドできなかったのですが、Anaconda 環境では普通に conda install できました<ref>conda install -c conda-forge pygrib</ref>。したがって以下の記述は「pygrib を利用したいけど、Windows でしかも Anaconda は使いたくない」という人向けのメモになります。

pip で入らない

まずは pip を使ってインストールを試みましたが、ビルドエラーで怒られました。

PS C:\Users\sample> python.exe -m pip install pygrib
Collecting pygrib
  Using cached pygrib-2.1.4.tar.gz (21.8 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: pyproj in c:\users\sample\appdata\local\programs\python\python39\lib\site-packages (from pygrib) (3.4.0)
Requirement already satisfied: numpy in c:\users\sample\appdata\local\programs\python\python39\lib\site-packages (from pygrib) (1.22.4)
Requirement already satisfied: certifi in c:\users\sample\appdata\local\programs\python\python39\lib\site-packages (from pyproj->pygrib) (2022.5.18.1)
Building wheels for collected packages: pygrib
  Building wheel for pygrib (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building wheel for pygrib (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [14 lines of output]
      eccodes not found, build may fail...
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build\lib.win-amd64-cpython-39
      creating build\lib.win-amd64-cpython-39\pygrib
      copying src\pygrib\__init__.py -> build\lib.win-amd64-cpython-39\pygrib
      running build_ext
      cythoning src/pygrib/_pygrib.pyx to src/pygrib\_pygrib.c
      C:\Users\sample\AppData\Local\Temp\pip-build-env-gaold049\overlay\Lib\site-packages\Cython\Compiler\Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: C:\Users\sample\AppData\Local\Temp\pip-install-qsivpw8o\pygrib_3b7fe8055b8a46b298e0ead62563ca4a\src\pygrib\_pygrib.pyx
        tree = Parsing.p_module(s, pxd, full_module_name)
      building 'pygrib._pygrib' extension
      error: Microsoft Visual C++ 14.0 or greater is required. Get it with "Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for pygrib
Failed to build pygrib
ERROR: Could not build wheels for pygrib, which is required to install pyproject.toml-based projects

エラー文 “error: Microsoft Visual C++ 14.0 or greater is required. Get it with “Microsoft C++ Build Tools": https://visualstudio.microsoft.com/visual-cpp-build-tools/" より Microsoft Visual C++ のバージョン 14.0 以降のものがないということがわかったので、指示に従って Microsoft C++ Build Tools からインストーラをダウンロードし、Visual C++ をインストールします。

Visual C++ をインストールしたあとで、再び pip install をすると違うエラーで怒られました。

PS C:\Users\sample> python.exe -m pip install pygrib
Collecting pygrib
  Using cached pygrib-2.1.4.tar.gz (21.8 MB)
  Installing build dependencies ... done
  Getting requirements to build wheel ... done
  Preparing metadata (pyproject.toml) ... done
Requirement already satisfied: pyproj in c:\users\sample\appdata\local\programs\python\python39\lib\site-packages (from pygrib) (3.4.0)
Requirement already satisfied: numpy in c:\users\sample\appdata\local\programs\python\python39\lib\site-packages (from pygrib) (1.22.4)
Requirement already satisfied: certifi in c:\users\sample\appdata\local\programs\python\python39\lib\site-packages (from pyproj->pygrib) (2022.5.18.1)
Building wheels for collected packages: pygrib
  Building wheel for pygrib (pyproject.toml) ... error
  error: subprocess-exited-with-error

  × Building wheel for pygrib (pyproject.toml) did not run successfully.
  │ exit code: 1
  ╰─> [22 lines of output]
      eccodes not found, build may fail...
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build\lib.win-amd64-cpython-39
      creating build\lib.win-amd64-cpython-39\pygrib
      copying src\pygrib\__init__.py -> build\lib.win-amd64-cpython-39\pygrib
      running build_ext
      cythoning src/pygrib/_pygrib.pyx to src/pygrib\_pygrib.c
      C:\Users\sample\AppData\Local\Temp\pip-build-env-a12alw0y\overlay\Lib\site-packages\Cython\Compiler\Main.py:369: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: C:\Users\sample\AppData\Local\Temp\pip-install-71nznokm\pygrib_743dda9af7fb4c6ba78e7cb596d5d4cf\src\pygrib\_pygrib.pyx
        tree = Parsing.p_module(s, pxd, full_module_name)
      building 'pygrib._pygrib' extension
      creating build\temp.win-amd64-cpython-39
      creating build\temp.win-amd64-cpython-39\Release
      creating build\temp.win-amd64-cpython-39\Release\src
      creating build\temp.win-amd64-cpython-39\Release\src\pygrib
      "C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.33.31629\bin\HostX86\x64\cl.exe" /c /nologo /O2 /W3 /GL /DNDEBUG /MD -IC:\Users\sample\AppData\Local\Programs\Python\Python39\include -IC:\Users\sample\AppData\Local\Programs\Python\Python39\Include -IC:\Users\sample\AppData\Local\Temp\pip-build-env-a12alw0y\overlay\Lib\site-packages\numpy\core\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Tools\MSVC\14.33.31629\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\VS\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.19041.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\um" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\shared" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\winrt" "-IC:\Program Files (x86)\Windows Kits\10\\include\10.0.19041.0\\cppwinrt" /Tcsrc/pygrib\_pygrib.c /Fobuild\temp.win-amd64-cpython-39\Release\src/pygrib\_pygrib.obj
      _pygrib.c
      C:\Users\sample\AppData\Local\Temp\pip-build-env-a12alw0y\overlay\Lib\site-packages\numpy\core\include\numpy\npy_1_7_deprecated_api.h(14) : Warning Msg: Using deprecated NumPy API, disable it with #define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION
      src/pygrib\_pygrib.c(756): fatal error C1083: include ファイルを開けません。'grib_api.h':No such file or directory
      error: command 'C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Tools\\MSVC\\14.33.31629\\bin\\HostX86\\x64\\cl.exe' failed with exit code 2
      [end of output]

  note: This error originates from a subprocess, and is likely not a problem with pip.
  ERROR: Failed building wheel for pygrib
Failed to build pygrib
ERROR: Could not build wheels for pygrib, which is required to install pyproject.toml-based projects

エラー文 “fatal error C1083: include ファイルを開けません。’grib_api.h’:No such file or directory" より “grib_api.h" がないのが原因だとわかりました。

grib_api のために ecCodes をビルドする

grib_api.hecCodes に含まれているので、まず ecCodes のソースを公式サイトからダウンロードします。ここでは記事執筆時点での最新版である version 2.27.0 のソースコードをダウンロードしました。

ソースコードは tar.gz で固められているので、解凍します。私は WSL の Linux 経由で解凍してしまいました。Windows ネイティブの機能だけで解凍しようとすると、場合によってはちょっと大変かもしれません。解凍すれば eccodes-2.27.0-Source というフォルダが出てきます。

できたフォルダの中、eccodes-2.27.0-Source/windows/msvc/grip_api.sln を開きます。これは Visual Studio 用のプロジェクトファイルなので、適切に関連付けされていれば Visual Studio が起動するはずです。

ソリューションの再ターゲット (Toolset 変換)

eccodes のソースに同梱されている Visual Studio 用のプロジェクトファイルは古いバージョンの Visual Studio によってできているらしいので、最新版に合わせたプロジェクトに更新(再ターゲット、Toolset の変換)します。私の場合は、最初の起動時に以下のようなダイアログがでて再ターゲットを促されました。OK を選択して再ターゲット (Toolset の変換) を行います。

ソリューションの再ターゲットのプロンプト

もしこの画面が出なかった場合は右端のソリューションエクスプローラーにあるソリューション名を右クリックして出てくるメニューから「ソリューションの再ターゲット」を選択して更新します。

右クリックメニューからソリューションの再ターゲット

eccodes_version.h を作成する

手動で eccodes-2.27.0-Source/src/eccodes_versions.h を作成します。まず同じフォルダにある eccodes-2.27.0-Source/src/eccodes_versions.h.inコピーして、eccodes_versions.h を作成し、中の情報を書き換えます。

基本的に @ で囲まれているところを書き換えます。下記に示す例は、元々の eccodes_versions.h.in の内容をコメントアウトしつつ、変更すべき内容を並べて書いています。

/*
 * (C) Copyright 2005- ECMWF.
 *
 * This software is licensed under the terms of the Apache Licence Version 2.0
 * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
 *
 * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
 * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
 */

#ifndef eccodes_version_H
#define eccodes_version_H

// #define ECCODES_VERSION_STR      "@eccodes_VERSION_STR@" // 書き換え前
#define ECCODES_VERSION_STR      "2.27.0" // 書き換え後

// #define ECCODES_MAJOR_VERSION    @eccodes_VERSION_MAJOR@ // 書き換え前
#define ECCODES_MAJOR_VERSION    2 // 書き換え後
// #define ECCODES_MINOR_VERSION    @eccodes_VERSION_MINOR@ // 書き換え前
#define ECCODES_MINOR_VERSION    27 // 書き換え後
// #define ECCODES_REVISION_VERSION @eccodes_VERSION_PATCH@ // 書き換え前
#define ECCODES_REVISION_VERSION 0 // 書き換え後
#define ECCODES_VERSION (ECCODES_MAJOR_VERSION*10000+ECCODES_MINOR_VERSION*100+ECCODES_REVISION_VERSION)

#endif /* eccodes_version_H */

バージョン情報を書き換える感じです。この例の場合、書き換えるのは以下のような感じです。

  • @eccodes_VERSION_STR@ → 2.27.0 (ダブルクォーテーションで囲まれているのに注意!)
  • @eccodes_VERSION_MAJOR@ → 2
  • @eccodes_VERSION_MINOR@ → 27
  • @eccodes_VERSION_PATCH@ → 0

設定すべき数値はソースコードのバージョンによって異なります。最初の eccodes_VERSION_STR は文字列なので、ダブルクォーテーションで囲み、そのあとドット区切りで示されているバージョンの数値をそれぞれ設定します。

ビルドする

grib_api をビルドします。ビルドは Visual Studio 画面中のコマンドプロンプト (PowerShell) で以下のコマンドを実行しました。

MSBuild.exe -p:Configuration=Release -p:platform=x64 grib_api.sln

私の環境では 2 分程度かかりました。Warning (警告) はたくさん出ますが、エラーはなく終了します。

環境変数を設定して Pygrib をインストール

grib_api をビルドしたことで Pygrib をインストールするのに必要なライブラリができたので、インストールします。ちなみに grib_api をビルドしたのと同じ Visual Studio 内のコマンドプロンプトで pip install しようとしたら、私の環境ではうまくいかなくてハマった(原因の想像は後述)ので、新しく PowerShell を起動した方がいいかもしれません。

環境変数を設定する

pip コマンドでインストールを始める前に環境変数を設定します。LIB と INCLUDE を変更します。

$oldlib = [System.Environment]::GetEnvironmentVariable("LIB")
$oldlib = "C:\Path\to\src\eccodes-2.27.0-Source\windows\msvc\grib_api_lib\x64\Release;" + $oldlib
[System.Environment]::SetEnvironmentVariable("LIB", $oldlib)

$oldinc = [System.Environment]::GetEnvironmentVariable("INCLUDE")
$oldinc = "C:\Path\to\src\eccodes-2.27.0-Source\src;" + $oldinc 
[System.Environment]::SetEnvironmentVariable("INCLUDE", $oldinc)

それぞれ元々設定されている環境変数を消さないようにするため、わざわざ変数に入れてから設定しています。

pip install を試みる(失敗)

環境変数を設定後、pip でインストールを試みます。

Python.exe -m pip install pygrib

しかし失敗します(エラー例は失敗する環境をもう一度再現できたら掲載します)。ライブラリのビルド環境(64 bit)と Python の実行環境(32 bit)が合わないというエラーが出ました。これはシステムで持っている Python 環境とは別に Visual Studio で持っている Python 環境があって、起動している Python が異なるのかもしれません。

pip install を試みる(成功)

改めて PowerShell を起動し、pip install するとうまくいきます。

Python.exe -m pip install pygrib

めでたしめでたし……ではありませんでした。もう少し続きます。

Pygrib 実行時に必要な環境変数の設定

めでたくインストールできたので早速 import して実行を試みると次のように怒られます。

ECCODES ERROR   :  Unable to find definition files directory
ECCODES ERROR   :  Unable to find boot.def. Context path=(null)

Possible causes:
- The software is not correctly installed
- The environment variable ECCODES_DEFINITION_PATH is defined but incorrect

ecCodes assertion failed: `0' in C:\Path\to\eccodes-2.27.0-Source\src\grib_context.c:226

ECCODES_DEFINITION_PATH が指定されていないとエラーを吐いています。そのため、最初に ecCodes をビルドしたときに使用したフォルダの definitions フォルダを環境変数に設定してやります。

[System.Environment]::SetEnvironmentVariable("ECCODES_DEFINITION_PATH", "C:\path\to\eccodes-2.27.0-Source\definitions")

これで無事動かせるようになりました。本当のめでたしめでたし。

しかし毎回立ち上げるたびに設定せねばならないので、システムの環境変数として設定しておいたほうがいいかもしれません。

参考資料