pyinstallerの*.specファイル作成法。

作成されたpython scriptをpyinstallerを用いてMacOSのアプリを作れます。

最初僕はpy2appを使用しましたが結果ファイルサイズが以下のように違いました。
- Py2appの結果：35MB
- Pyinstallerの結果：25MB
Pyinstallerを使わないわけがないでしょう。
インストールはPIPで可能になりまして。（昨年はできませんでした）

>pip install pyinstaller 

それで完了

pyinstallerの駆動は*.specファイルを通じてするのがお勧めです。

specファイルの基本構造は下のようです。

```
# -*- mode: python -*-
# filename = Main.spec

a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
             icon='mainIcon.ico')
```
この場合はmain.pyを読んでMain.appを作ります。iconはmainIcon.icoをかぶります。

Main.pyは　”/Users/.../ProgramNameDir”に存在し、その下の "./lib"のlibファイルを参考しています。なので　*.specファイルが"./lib"を認識できるように少し修正します。

```
# -*- mode: python -*-
# filename = Main.spec

### 個人の./libsを認識するためのコード ###
import sys 
myLibPath = './libs'
sys.path.append(myLibPath)
############################

a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
             icon='mainIcon.ico')
```

もう一つの問題があります。Main.pyでは　/Users/.../ProgramNameDir/img内のイメージ・ファイルをつかいます。これはsys.path.appendで追加しても最終のアプリでは読めません。イメージ・ファイルをハンドリング仕組みが違うからです。

pyinstallerで作られたアプリが駆動する際、必要なファイル（イメージ・ファイルなど）は臨時フォルダ(temp folder)内「＿MEIPASS」という場所でコピーします。だから*.pyコード内に「＿MEIPASS」を認識させる必要があります。

Main.pyでこの関数を追加します。

```
def resource_path(relative):
  if hasattr(sys, "_MEIPASS"):
      return os.path.join(sys._MEIPASS, relative)
  return os.path.join(relative)
```

そしてコード内のイメージ参照こどを変換します。
例え：
```"./img/Title.png" --> resource_path("./img/Title.png")```

*.specファイルにはTree()を追加します。

```
# -*- mode: python -*-
#filename = Main.spec
import sys 
myLibPath = './libs'
sys.path.append(myLibPath)
a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('img',prefix='img'), #<--追加するイメージがあるフォルダ名
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
             icon='mainIcon.ico')
```

僕はMacBook proを使っています。即ちRetina Displayを使っています。pyinstallerで作られたアプリをそのまま作るとRetina Displayの上にはメッセージ・ボックスとかダイアログが滲んで見えるので醜いです。
それを解決するためBUNDLEにinfo_plistを追加します。


```
# -*- mode: python -*-
#filename = Main.spec
import sys 
myLibPath = './libs'
sys.path.append(myLibPath)
a = Analysis(['Main.py'],
             pathex=['/Users/.../ProgramNameDir'],
             hiddenimports=[],
             hookspath=None,
             runtime_hooks=None)
pyz = PYZ(a.pure)
exe = EXE(pyz,
Tree('img',prefix='img'), 
          a.scripts,
          a.binaries,
          a.zipfiles,
          a.datas,
          name='Main',
          debug=False,
          strip=None,
          upx=True,
          console=False , icon='mainIcon.ico')
app = BUNDLE(exe,
             name='Main.app',
　　　　　　  info_plist={ 'NSHighResolutionCapable': 'True'}, #<-- Option for High Resolution
             icon='mainIcon.ico')
```

これで大体におわりです。
```pyinstaller Main.spec```
でアプリができます。

py2exeとかpy2appの場合は事例がずいぶんあるけどpyinstallerの場合はあんまりないので整理のため記録しました。