Kivyを用いた数独ソルバーのGUIを配布してみよう．

本日は

[Kivyを用いた数独ソルバーのGUIのβ版ができました．](https://qiita.com/SatoshiTerasaki/items/e1bb2fe450636e93a0bf)
の続編です．Windows環境で.exe化させます．

ただ，いまのところは完全に隠しきれてません・・・．


いや，できました．

# PyInstallerにて

PyInstallerを用いてみましょう．インストールは下記の通り

```shell-session
> pip install pyinstaller
```
つぎのように `sudoku.py` と同階層に `sudoku.spec` をつくります：

- [【Python Kivy】pyinstallerでexeファイルを作成する方法](https://qiita.com/AkihikoKumasaka/items/cb6a499a47bc836d9556)

を参考にしました．

```py3
# -*- mode: python -*-
from kivy.deps import sdl2, glew

block_cipher = None


a = Analysis(['sudoku.py'],
             pathex=['D:\\work\\pythonCode\\kivy\\Sudoku\\beta'],
             binaries=[],
             datas=[],
             hiddenimports=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
          name='sudoku',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

coll = COLLECT(exe, Tree('.'),
               a.binaries,
               a.zipfiles,
               a.datas,
               *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
               strip=False,
               upx=True,
               name='sudoku')
```

Analysis内の引数の `pathx` は `sudoku.py` があるフォルダを指定します．

この後次のコマンドを実行します:

```shell-session
> pyinstaller sudoku.spec --onefile
```

`--onefile` で一つのexeにまとめてくれます．起動時にターミナルが出てほしくないときは `--noconsole` もつけておきましょう．これらはKivyのアプリケーションに限らず一般的に使えます．

生成物は `dist` フォルダ内にできます．

# できていないこと

sudoku.exeと同階層に `sudoku.kv` を置いておかないと起動時に落ちてしまう．
libz3.dllが必要なのはともかくとして．これを何とかしたい．

StackOverflowの記事が参考になりそう

- [Kivy: compiling to a single executable
](https://stackoverflow.com/questions/35952595/kivy-compiling-to-a-single-executable)

- [How to get an windows executable from my kivy app (Pyinstaller)?
](https://stackoverflow.com/questions/37696206/how-to-get-an-windows-executable-from-my-kivy-app-pyinstaller)

# できました・・・．

上記のStackOverflowを参考にしてたらいけました．
まず既存のsudoku.pyに次を追記します：

```py3:sudoku.py
def resourcePath():
    '''Returns path containing content - either locally or in pyinstaller tmp file'''
    if hasattr(sys, '_MEIPASS'):
        return os.path.join(sys._MEIPASS)

    return os.path.join(os.path.abspath("."))

def main():
    kivy.resources.resource_add_path(resourcePath())
    SudokuApp().run()


if __name__ == '__main__':
    main()
```

`kivy.resources.resource_add_path(resourcePath())` がキーポイントのようです．

spec file も次のようにします：

```py3
# -*- mode: python -*-
from kivy.deps import sdl2, glew

block_cipher = None


a = Analysis(['sudoku.py'],
             pathex=['D:\\work\\pythonCode\\kivy\\numberPlace\\beta'],
             binaries=[],
             datas=[],
             hookspath=[],
             runtime_hooks=[],
             excludes=[],
             win_no_prefer_redirects=False,
             win_private_assemblies=False,
             cipher=block_cipher,
             hiddenimports=[])

a.datas+=[('sudoku.kv','D:\\work\\pythonCode\\kivy\\numberPlace\\beta\\sudoku.kv',"DATA")]
pyz = PYZ(a.pure, a.zipped_data,
             cipher=block_cipher)
             
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
          name='sudoku',
          debug=False,
          strip=False,
          upx=True,
          runtime_tmpdir=None,
          console=True )

coll = COLLECT(exe, Tree('.'),
               a.binaries,
               a.zipfiles,
               a.datas,
               *[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],
               strip=False,
               upx=True,
               name='sudoku')
```

```py3
a.datas+=[('sudoku.kv','D:\\work\\pythonCode\\kivy\\numberPlace\\beta\\sudoku.kv',"DATA")]
```

を付け加えてPyInstallerに `sudoku.kv` の存在を教えられるようです．