mieki256's diary



2017/09/03() [n年前の日記]

#1 [python][windows][pi3d] Windows10 x64上に pi3d をインストールしてみたり

Windows上でも _pi3d はインストールできるらしいので試してみた。

_Introduction to pi3d - pi3d 2.20 documentation

環境は Windows10 x64 + Python 2.7.13 or Python 3.5.4。
> python --version
Python 2.7.13

> py -2 --version
Python 2.7.13

> py -3 --version
Python 3.5.4

動作に必要なモジュールをインストール。 :

pi3dをWindows上で動かすには以下のモジュールも必要になるらしい。
pygame
Pillow
numpy

現時点では pip でインストールできる。
pip install pygame
pip install Pillow
pip install numpy

最後に pi3d をインストール。
pip install pi3d

pip list
と打てばインストール済みモジュールの一覧が表示されるので、インストールできたか確認できるはず。

デモスクリプト群 pi3d_demos を入手。 :

_pi3d/pi3d_demos: Demos and support files for pi3d

git を使って持ってくる。
git clone https://github.com/pi3d/pi3d_demos.git

あるいは、zipをダウンロードして解凍してもいい。 _pi3d/pi3d_demos の、右上のほうの緑のボタン、「Clone or download」→「Download zip」をクリックすれば、zipファイルとしてダウンロードできる。

ANGLEの入手。 :

pi3dをWindows上で動かすためには、OpenGL ES をエミュレートするANGLEなるものが ―― 3〜4ファイルの .dllファイルが必要になるらしい。

入手方法はいくつかあるようで。

その1。 _paddywwoof/pi3d_windll からzipでダウンロードして解凍。中に入ってる dllファイルを使わせてもらう方法。

その2。Mozilla Firefox のインストールフォルダ、
C:\Program Files (x86)\Mozilla Firefox\
から、該当する .dll をコピーしてくる方法。

その3。Google Chrome のインストールフォルダ、
C:\Program Files (x86)\Google\Chrome\Application\バージョン番号\
からコピーしてくる方法。

動作に必要なファイルは3〜4ファイル。
libegl.dll
libglesv2.dll
d3dcompiler_47.dll   # 最後の数字は違ってる可能性有
mozglue.dll          # Mozilla Firefox のみ必要

これらのファイルを、動かしたいスクリプトと同じ階層に置く。例えば pi3d_demos を動かしたいなら、pi3d_demosフォルダの中にコピーする。

Pythonが32bit版なら、32bit版用のdllを、Pythonが64bit版なら、64bit版のdllを用意する。

ちなみに自分の環境では、 _paddywwoof/pi3d_windll の32bit版dll、あるいは Firefoxのソレが使えて、Google Chromeのソレは使えなかった。

デモスクリプトの実行。 :

pi3d_demos の Earth.py を動かしてみる。
cd pi3d_demos
python Earth.py
D:\home\prg\python\_test_sample\pi3d\pi3d_demos\pi3d_demos> python Earth.py
Traceback (most recent call last):
  File "Earth.py", line 11, in <module>
    import pi3d
  File "C:\Python\Python27\lib\site-packages\pi3d\__init__.py", line 10, in <module>
    from pi3d.constants import *
  File "C:\Python\Python27\lib\site-packages\pi3d\constants\__init__.py", line 167, in <module>
    PLATFORM, bcm, openegl, opengles = _detect_platform_and_load_libraries()
  File "C:\Python\Python27\lib\site-packages\pi3d\constants\__init__.py", line 160, in _detect_platform_and_load_libraries
    platform, bcm, openegl, opengles = loader()
  File "C:\Python\Python27\lib\site-packages\pi3d\constants\__init__.py", line 139, in _windows
    opengles = _load_library("libglesv2.dll", "Win")
  File "C:\Python\Python27\lib\site-packages\pi3d\constants\__init__.py", line 77, in _load_library
    Log.logger(__name__).error("Couldn't load library %s", name)
AttributeError: 'module' object has no attribute 'logger'
Python 2.7 上で試したらエラーが出て動かない…。libglesv2.dll を見つけ出すところで処理に失敗してる模様。

ところが。Python 3.5 ならどうか。
> py -3 Earth.py
こっちだと動いてしまった。地球と月がWindows上でもクルクル回ってる。

どうやら現時点では、Windows + Python + pi3d は、 Python 3.x でしか動かないようだなと。

どうしてエラーが出るのか謎。 :

Python 2.7で動かそうとした場合、 _pi3d/constants/__init__.py でエラーが出るわけだけど。ソースを眺めても、これでどうしてエラーが出るのか分からない。

pi3d_demosフォルダ内に _mydemo.py というファイルを作って動作確認してみた。

__mydemo.py
import sys
# sys.path.insert(1, '/home/pi/pi3d')

import ctypes

def _load_library(name, dll_type="C"):
    if name:
        try:
            if dll_type == "Win":
                return ctypes.WinDLL(name)
            else:
                return ctypes.CDLL(name)
        except:
            print("Couldn't load library %s" % name)

opengles = _load_library("libglesv2.dll", "Win")
openegl = _load_library("libegl.dll", "Win")
print(opengles)
print(openegl)

> python _mydemo.py
<WinDLL 'libglesv2.dll', handle 5ae30000 at 3467cd0>
<WinDLL 'libegl.dll', handle 5daa0000 at 3467db0>
ちゃんとdllを見つけることができてる。pi3d/constants/__init__.py をコピペして動かしてみたのに問題が出ていない。

なのに、pi3d/constants/__init__.py を呼び出すとエラーになってしまう。何故? どうして?

もし、Python 2.7同梱の ctypes のバグだったら、どっちもエラーが出るはずだよな…。なのに、片方はエラーで、片方は動く…。

Python 3.5 では動いてしまうのも謎。何故。

エラーが出る原因が分かった。 :

Python 2.7.13 のバグらしい。

_TypeError: LoadLibrary() argument 1 must be string, not unicode - Issue #147 - carlosperate/ardublockly
_Issue 29082: In 2.7.13, _ctypes.LoadLibrary no longer accepts Unicode objects - Python tracker
_ctypes - TypeError when importing ghostscript on Python - Stack Overflow

ctypes.WinDLL() に渡すべき文字列の種類が、Python 2.7.13 と Python 3.x では違ってしまっているらしい。Unicode文字列だか、バイト文字列だか…。

例えば、pi3d/constants/__init__.py の _load_library() を、以下のように書き換えるとエラーメッセージが変わってくる。
def _load_library(name, dll_type="C"):
  """Try to load a shared library, report an error on failure."""
  if name:
    try:
      if dll_type == "Win":
        return ctypes.WinDLL(name)
      else:
        return ctypes.CDLL(name)
    except:
      from pi3d.util import Log
      Log.logger(__name__).error("Couldn't load library %s", name)
def _load_library(name, dll_type="C"):
  """Try to load a shared library, report an error on failure."""
  if name:
    if dll_type == "Win":
      return ctypes.WinDLL(name)
    else:
      return ctypes.CDLL(name)

Python 2.7.13 で動かした場合。
> python Earth.py
Traceback (most recent call last):
  File "Earth.py", line 11, in <module>
    import pi3d
(中略)
  File "C:\Python\Python27\lib\site-packages\pi3d\constants\__init__.py", line 72, in _load_library
    return ctypes.WinDLL(name)
  File "C:\Python\Python27\lib\ctypes\__init__.py", line 362, in __init__
    self._handle = _dlopen(self._name, mode)
TypeError: LoadLibrary() argument 1 must be string, not unicode
「TypeError: LoadLibrary() argument 1 must be string, not unicode」と怒られてる。

Python 2.7.13 で動くように修正してみると…。
def _load_library(name, dll_type="C"):
  """Try to load a shared library, report an error on failure."""
  if name:
    name = name.encode('ascii', 'ignore')  # add
    if dll_type == "Win":
      return ctypes.WinDLL(name)
    else:
      return ctypes.CDLL(name)
1行追加しただけで、Python 2.7.13 でも動くようになった。

しかし、同じ修正をしたものを Python 3.5.4 で動かしてみると。
> py -3 Earth.py
Traceback (most recent call last):
  File "Earth.py", line 11, in <module>
    import pi3d
(中略)
  File "C:\Python\Python35\lib\site-packages\pi3d\constants\__init__.py", line 72, in _load_library
    return ctypes.WinDLL(name)
  File "C:\Python\Python35\lib\ctypes\__init__.py", line 351, in __init__
    self._handle = _dlopen(self._name, mode)
TypeError: LoadLibrary() argument 1 must be str, not bytes
今度は、「TypeError: LoadLibrary() argument 1 must be str, not bytes」と怒られた。

Python 2.7.13 と Python 3.5.4 で、エラーメッセージが違ってる…。LoadLibrary() に与えるべき文字列の種類が違うという。
TypeError: LoadLibrary() argument 1 must be string, not unicode

TypeError: LoadLibrary() argument 1 must be str, not bytes

解決策としては…。英語圏のやり取りを眺めると「Python 2.7.12 にダウングレードしろ」「もしくは Python 3.x を使え」ということになってるっぽいな…。

Python 2.7.13 は _結構色々修正されてる っぽいから、できれば 2.7.13 のほうがいいのではと思えてくるけど、しかし、こういう不具合があるのでは…。ていうか去年の年末に報告されてたのに、修正版はまだ出ないのか…。

以上です。

過去ログ表示

Prev - 2017/09 - Next
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project