見出し画像

Anacondaのベース環境以外で、C++に組み込んだPythonコードを実行させた

はじめに

アダコテックの伊藤です。こんにちは。

現在進めている案件で、pybind11を使ってpythonコードをC++から動かしたのですが、その際の問題点と対策についてまとめます。

google先生に質問してもドンピシャな回答がなかったので、同じに悩みに直面している方の助けになると幸いです。

なお、「C++からpythonコードを実行するのってどうやるの?」に関しては下記リンクを参照して下さい。https://qiita.com/benikabocha/items/5ec6b471de0d10aaf2df

前提条件

Anacondaはベース環境がPython3.8となっている。

ベース環境ではなく、別環境(Python3.7)にインストールされたpybind11を使って、C++に組み込んだPythonコードを実行させる。

仮想環境の構成はこんな感じ。

C:\Users\k-ito>conda env list
# conda environments:
#
base  *  C:\tools\Anaconda3
py37     C:\tools\Anaconda3\envs\py37

① 何も考えずに実行してみる。

まずは、何も考えずにC++プログラムを実行してみる。
と、下記のようなエラーが発生する。(ベース環境がpython3.8なんだから当たり前だよね?)

画像1

② Activateしてみた

下記コマンドを実行して、仮想環境を変更してみる。

conda activate py37

改めて、C++プログラムを実行すると今度は下記のようなエラーが発生する

Fatal Python error: initfsencoding: unable to load the file system codec
ModuleNotFoundError: No module named 'encodings'
Current thread 0x00001e88 (most recent call first):

③ Google先生に質問してみた

Goole先生に質問してみると、PATH環境変数とかPYTHONHOME環境変数の設定に問題があるんじゃないのかとの答えが見つかった

https://stackoverflow.com/questions/42512817/fatal-python-error-on-windows-10-modulenotfounderror-no-module-named-encodings

Activate実行後の環境変数を見るとPATH環境変数には下記PATHが追加されていたが、PYTHONHOMEは追加されていないようです。

C:\tools\Anaconda3\envs\py37;
C:\tools\Anaconda3\envs\py37\Library\mingw-w64\bin;
C:\tools\Anaconda3\envs\py37\Library\usr\bin;
C:\tools\Anaconda3\envs\py37\Library\bin;
C:\tools\Anaconda3\envs\py37\Scripts;
C:\tools\Anaconda3\envs\py37\bin;
C:\tools\Anaconda3\condabin;

④ PYTHONHOMEを環境変数に追加してみた。

下記コマンドでPYTHONHOME環境変数を(一時的に)追加してみる。

set PYTHONHOME=C:\tools\Anaconda3\envs\py37

C++プログラムを実行してみると、無事動きました!!

[2021-01-27 14:11:11.917] [system] [info] システム起動

が、新たに問題が発生!condaが動かない

conda deactivate

Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\matplotlib-3.1.1-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\sphinxcontrib_applehelp-1.0.1-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\sphinxcontrib_devhelp-1.0.1-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\sphinxcontrib_htmlhelp-1.0.2-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\sphinxcontrib_jsmath-1.0.1-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\sphinxcontrib_qthelp-1.0.2-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Error processing line 1 of C:\tools\Anaconda3\envs\py37\lib\site-packages\sphinxcontrib_serializinghtml-1.1.3-py3.7-nspkg.pth:
Traceback (most recent call last):
  File "C:\tools\Anaconda3\envs\py37\lib\site.py", line 168, in addpackage
    exec(line)
  File "<string>", line 1, in <module>
  File "C:\tools\Anaconda3\envs\py37\lib\importlib\__init__.py", line 51, in <module>
    _w_long = _bootstrap_external._w_long
AttributeError: module 'importlib._bootstrap_external' has no attribute '_w_long'
Remainder of file ignored
Traceback (most recent call last):
File "C:\tools\Anaconda3\Scripts\conda-script.py", line 11, in <module>
  from conda.cli import main
ModuleNotFoundError: No module named 'conda'

総合すると、

python37.dll(および他ファイルも)を参照するためにPATH環境変数に適切なPATHを追加する必要がある。

PYTHONHOME環境変数も適切に設定する必要があるが、これを設定するとcondaが動かなくなってしまう。

という事のようですが、PYTHONHOMEの方についての解決案はGoogle先生も教えてくれませんでした・・・。

結局、どうしたの?

PYTHONHOMEを定義して、condaが使えなくなるのは論外です。
なので、C++プログラム起動時にpythonまわりの環境変数を動的に定義するようにしました。(弊社エンジニアが実装したコードの抜粋です。)

void SetPythonEnvs()
{
   size_t size;
   std::vector<char> buf;
   // 本当は外部から指定するのがベスト 
   std::string python_home = "c:\\tools\\Anaconda3\\envs\\py37"; 
   _putenv_s("PYTHONHOME", python_home.c_str());
   // PATH環境変数の追加は省略
   getenv_s(&size, NULL, 0, "PATH");
   buf.resize(size);
   getenv_s(&size, buf.data(), size, "PATH");
   auto env_path = python_home + ";" + python_home + R"(\Library\bin;)" + std::string(buf.data());
   _putenv_s("PATH", env_path.c_str());
}

おわりに

冒頭にも書きましたが、google先生に質問してもドンピシャな回答がなかったので、同じに悩みに直面している方の助けになると幸いです。

メンバー募集中です
アダコテックは上記のような画像処理技術を使って、大手メーカーの検査ラインを自動化するソフトウェアを開発している会社です。
機械学習や画像処理の内部ロジックに興味がある方、ご連絡下さい!
我々と一緒にモノづくりに革新を起こしましょう!
https://adacotech.co.jp/recruit

この記事が気に入ったらサポートをしてみませんか?