|
2025-12-13
2025-12-14
概要 †PyInstaller や Nuitka、cxFreeze などPythonアプリをデスクトップアプリ化する手段はいくつがあるが、課題も多い。
そこで今回は、Inno Setup を使用してPythonアプリを配布する為の手順について記載する。 目次 †Inno Setupとは †Inno Setupは Windowsアプリ用のインストーラーを簡単に作成できるオープンソースのフリーソフトウェア。
公式: https://jrsoftware.org/isinfo.php Inno Setupを採用する事によるメリット/デメリット †メリット †
デメリット †
インストール先のフォルダ構成 †以下のようなフォルダ構成でインストールされるようにインストーラーを作成する。 アプリケーションフォルダ/ ├─ python/ ... Python本体 及び ライブラリ │ ├─ : │ └─ : ├─ main.py ├─ run_app.bat └─ その他リソース 開発用のリポジトリ構成 †リポジトリ/ ├─ app/ ... Pythonアプリケーション │ ├─ main.py │ ├─ requirements.txt │ ├─ : │ └─ run_app.bat ... アプリケーション起動用バッチ ├─ installer/ │ ├─ installer.iss ... Inno Setup定義 │ ├─ python-3.13.11-embed-amd64.zip ... Embeddable Python (公式から取得) │ ├─ get-pip.py ... pipの手動インストール用スクリプト │ └─ wheels ... build_wheels.bat で作成 ├─ tools/ │ └─ build_wheels.bat ... wheel をダウンロード/ビルドする為のバッチ └─ .github/ └─ workflows/ └─ build-installer.yml ... Github Action用のワークフロー 準備 †Inno Setup のインストール †https://jrsoftware.org/isdl.php からダウンロードしてインストール Embeddable Python の取得 †今回は完全オフラインに対応する為にインストーラー内にPython実行環境を内包する為、Embeddable Python(※) を事前にダウンロードしておく。 https://www.python.org/downloads/windows/ get-pip.py の取得 †pipを有効にする為に「pipを手動でインストールするためのスクリプト」を事前にダウンロードしておく(公式提供) https://bootstrap.pypa.io/get-pip.py wheelの準備 †今回は完全オフラインで実行できるインストーラを作成する為、事前にPythonライブラリをダウンロードしておき、インストーラに内包する形を取る。 python -m pip download --only-binary=:all: --platform win_amd64 --python-version 313 --implementation cp --abi cp313 -r requirements.txt -d wheels ※成功すると wheels 配下に各ライブラリの whl が作成される。( whl はそのライブラリの実行に必要なファイルを内包した zip ファイル ) ただし、wheel がないライブラリがあった場合、アプリケーションは動作しなくなる可能性がある為、ここでは wheel が無い場合にビルドして作成する為にバッチ化しておく。 tools/build_wheels.bat @echo off
cd /d "%~dp0"
setlocal enabledelayedexpansion
REM =====================================================
REM 設定
REM =====================================================
set PYTHON=python
set REQS=..\app\requirements.txt
set OUTDIR=..\installer\wheels
set PY_VER=313
set ABI=cp313
set PLATFORM=win_amd64
set IMPL=cp
REM =====================================================
REM 初期化
REM =====================================================
if not exist "%REQS%" (
echo [ERROR] requirements.txt not found
exit /b 1
)
if exist "%OUTDIR%" (
echo [INFO] Cleaning existing wheels directory
rmdir /s /q "%OUTDIR%"
)
mkdir "%OUTDIR%"
REM =====================================================
REM pip / setuptools / wheel のダウンロード
REM =====================================================
%PYTHON% -m pip download ^
pip setuptools wheel ^
-d "%OUTDIR%"
REM =====================================================
REM その他 wheelのダウンロード
REM =====================================================
%PYTHON% -m pip download ^
--only-binary=:all: ^
--platform %PLATFORM% ^
--python-version %PY_VER% ^
--implementation %IMPL% ^
--abi %ABI% ^
-r "%REQS%" ^
-d "%OUTDIR%"
REM =====================================================
REM wheelがダウンロードできなかったライブラリを確認する
REM =====================================================
set MISSING=
for /f "usebackq delims==" %%A in ("%REQS%") do (
set PKG=%%A
set FOUND=0
for %%W in ("%OUTDIR%\%%A-*.whl") do (
set FOUND=1
)
if "!FOUND!"=="0" (
echo [WARN] Wheel missing: %%A
set MISSING=!MISSING! %%A
)
)
REM =====================================================
REM wheelのビルド(wheelがなかったものだけ)
REM ※C++ビルド環境が必要
REM =====================================================
if not "%MISSING%"=="" (
for %%P in (%MISSING%) do (
echo [BUILD] %%P
%PYTHON% -m pip wheel ^
--no-deps ^
%%P ^
-w "%OUTDIR%"
if errorlevel 1 (
echo [ERROR] Failed to build wheel for %%P
exit /b 1
)
)
) else (
echo [INFO] All wheels were available prebuilt
)
REM =====================================================
REM 最終確認
REM =====================================================
if exist "%OUTDIR%\*.tar.gz" (
echo [ERROR] sdist found in wheels directory
dir "%OUTDIR%\*.tar.gz"
exit /b 1
)
if exist "%OUTDIR%\*.zip" (
echo [ERROR] unexpected zip found in wheels directory
dir "%OUTDIR%\*.zip"
exit /b 1
)
echo [SUCCESS] All dependencies are wheels only
REM =====================================================
REM 完了
REM =====================================================
endlocal
exit /b 0
wheelのダウンロードを実行(wheels配下にライブラリのwhlファイルがダウンロード または 作成される) tools\build_wheels.bat アプリケーション起動用バッチの作成 †run_app.bat @echo off setlocal cd /d "%~dp0" REM アプリ専用 Python set PYTHON=%CD%\python\pythonw.exe if not exist "%PYTHON%" ( echo Local Python not found. pause exit /b 1 ) "%PYTHON%" main.py Inno Setup ファイル作成 †Inno Setup の定義は iss というファイルにテキスト形式で記述する。 参考: https://jrsoftware.org/ishelp/index.php?topic=setupsection
installer.iss †; ==================================================
; オフラインで実行可能なインストーラー
; ==================================================
[Setup]
AppName=MyPythonApp
AppVersion=1.0.0
AppPublisher=MyCompany
DefaultDirName={localappdata}\MyPythonApp
DefaultGroupName=MyPythonApp
OutputBaseFilename=MyPythonAppInstaller
OutputDir=Output
Compression=lzma
SolidCompression=yes
PrivilegesRequired=lowest
ArchitecturesAllowed=x64
ArchitecturesInstallIn64BitMode=x64
; ==================================================
; ファイルコピー
; ==================================================
[Files]
; Embeddable Python のコピー
Source: "python-3.13.11-embed-amd64.zip"; DestDir: "{app}";
; get-pipのコピー
Source: "get-pip.py"; DestDir: "{app}"
; wheel のコピー
Source: "wheels\*"; DestDir: "{app}\wheels"; Flags: recursesubdirs createallsubdirs
; アプリケーションのコピー
Source: "..\app\*"; DestDir: "{app}"; Flags: recursesubdirs createallsubdirs; Excludes: "__pycache__,*.pyc,.git\*,.venv\*"
; ==================================================
; ショートカット作成
; ==================================================
[Icons]
Name: "{group}\MyPythonApp"; Filename: "{cmd}"; Parameters: "/c start /min run_app.bat"; WorkingDir: "{app}"; IconFilename: "{app}\myapp.ico"
Name: "{userdesktop}\MyPythonApp"; Filename: "{cmd}"; Parameters: "/c start /min run_app.bat"; WorkingDir: "{app}"; IconFilename: "{app}\myapp.ico"
; ==================================================
; インストール
; ==================================================
[Run]
; 1) Python ZIP を展開
Filename: "powershell.exe"; \
Parameters: "-NoProfile -ExecutionPolicy Bypass -Command ""Expand-Archive -Force '{app}\python-3.13.11-embed-amd64.zip' '{app}\python'"""; \
StatusMsg: "Extracting Python runtime..."; \
Flags: waituntilterminated runhidden
; 2) python313._pth を修正(site 有効化)
Filename: "{cmd}"; \
Parameters: "/c echo import site>> ""{app}\python\python313._pth"""; \
StatusMsg: "Configuring Python..."; \
Flags: waituntilterminated runhidden
; 3) pip インストール(オフライン)
Filename: "{app}\python\python.exe"; \
Parameters: """{app}\get-pip.py"" --no-index --find-links ""{app}\wheels"""; \
StatusMsg: "Installing pip..."; \
Flags: waituntilterminated
; 4) wheel から依存関係をインストール(オフライン)
Filename: "{app}\python\python.exe"; \
Parameters: "-m pip install --no-index --find-links ""{app}\wheels"" -r ""{app}\requirements.txt"""; \
StatusMsg: "Installing dependencies (offline)..."; \
Flags: waituntilterminated
; 5) インストール済みのwheelsを削除
Filename: "{cmd}"; \
Parameters: "/c rmdir /s /q ""{app}\wheels"""; \
StatusMsg: "delete wheels..."; \
Flags: runhidden
; 6) インストール済みの embed python を削除
Filename: "{cmd}"; \
Parameters: "/c del /f /q ""{app}\python-3.13.11-embed-amd64.zip"""; \
StatusMsg: "delete embed python zip..."; \
Flags: runhidden
; 7) アプリを起動
Filename: "{cmd}"; \
Parameters: "/c start /min cmd /c ""{app}\run_app.bat"""; \
StatusMsg: "run my app..."; \
Description: "Run MyApp"; \
Flags: postinstall
; ==================================================
; アンインストール時の処理
; ==================================================
[UninstallRun]
Filename: "{cmd}"; \
Parameters: "/c rmdir /s /q ""{app}\python"""; \
RunOnceId: RemovePython
参考ページ †
Flags の補足 †
python313._pth について †このファイルは Embeddable Python にのみ含まれるファイルで、Python の起動時に使われるパス初期化ファイル。 Embeddable Python を解凍毎の初期状態では以下のようになっている。 python313._pth (デフォルト) python313.zip . # Uncomment to run site.main() automatically #import site 重要なのは最後の行で site をimportしないと pip が有効化されず、venv も使用できない状態になってしまう。 site がやっていること
なので、pip 及び venv を有効化する為に、import site を有効化する必要がある。 python313._pth (変更後) python313.zip . # Uncomment to run site.main() automatically #import site import site # 有効化 インストーラの作成 †CLIコマンドで作成 iscc installer\installer.iss 補足(コンソールウィンドウを出したくない場合) †起動時にコンソールウィンドウを出したくない場合は、 launcher.c #include <windows.h>
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow
) {
STARTUPINFO si = { sizeof(si) };
PROCESS_INFORMATION pi;
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE;
CreateProcess(
NULL,
"cmd /c \"run_app.bat\"",
NULL, NULL,
FALSE,
CREATE_NO_WINDOW,
NULL,
NULL,
&si,
&pi
);
return 0;
}
ビルド( Build Tools for Visual Studio が必要) cl launcher.c /O2 あとは installer.iss を以下の通り変更するだけ。 [Files]
Source: "launcher.exe"; DestDir: "{app}"
[Icons]
Name: "{group}\MyPythonApp"; Filename: "{app}\launcher.exe"
Name: "{userdesktop}\MyPythonApp"; Filename: "{app}\launcher.exe"
補足(Github Actions 用のワークフロー) †TODO: 動作確認
.github/workflows/build-installer.yml name: Build Windows Installer (Offline Python, Wheels Included)
on:
push:
tags:
- "v*"
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
# -------------------------------------------------
# チェックアウト
# -------------------------------------------------
- name: Checkout repository
uses: actions/checkout@v4
# -------------------------------------------------
# Pythonセットアップ
# -------------------------------------------------
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
architecture: "x64"
# -------------------------------------------------
# pip & wheel アップグレード
# -------------------------------------------------
- name: Upgrade pip and wheel
run: |
python -m pip install --upgrade pip wheel
# -------------------------------------------------
# 依存ライブラリの wheel 取得
# -------------------------------------------------
- name: Build wheels (batch)
run: |
cd tools
build_wheels.bat
cd ..
# -------------------------------------------------
# Inno Setupのインストール
# -------------------------------------------------
- name: Install Inno Setup
run: |
choco install innosetup -y
# -------------------------------------------------
# インストーラーのビルド
# -------------------------------------------------
- name: Build installer
run: |
iscc installer\installer.iss
# -------------------------------------------------
# ビルド結果をアーティファクトとしてアップロード
# -------------------------------------------------
- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: MyPythonAppInstaller
path: installer\Output\*.exe
|