|
@echo off |
|
setlocal |
|
rem # |
|
rem # peyexe |
|
rem # |
|
rem # Super simple batch file to pack a Python project into a single-executable exe using 7z SFX. |
|
rem # |
|
rem # ysfchn (https://ysfchn.com) |
|
rem # |
|
rem # Before getting started, make sure you have: |
|
rem # |
|
rem # - Obviously, an internet connection. |
|
rem # An embedded verison of Python will be downloaded. |
|
rem # |
|
rem # - A "requirements.txt" in the current working directory to specify additional libraries. |
|
rem # |
|
rem # - A "peyexe.ini" file for configuration (in key=value format): |
|
rem # * python |
|
rem # Specifies which version of Python will be used. Example: "python=3.9.7" |
|
rem # * sources |
|
rem # Name of the folder that will includes project sources. |
|
rem # * run |
|
rem # Name of the file in the source directory that will be executed. |
|
rem # * console |
|
rem # 0 to disable Python console window. 1 (default) to show console. |
|
rem # * progress |
|
rem # 0 to hide extract progress. 1 (default) to show the progress. |
|
rem # * pip_strategy |
|
rem # 0 (default) to install packages beforehand (bigger exe size but starts faster), |
|
rem # 1 to install pip packages when started (smaller exe size but slightly takes longer to start) |
|
rem # |
|
rem # If everything goes ok, an executable named "peyexe.exe" will be created in the current working directory. |
|
rem # |
|
|
|
rem # https://stackoverflow.com/a/4518146 |
|
@for /f "tokens=2 delims==" %%a in ('find "python=" "peyexe.ini"') do set PYTHONVERSION=%%a |
|
@for /f "tokens=2 delims==" %%a in ('find "run=" "peyexe.ini"') do set PYTHONEXECUTE=%%a |
|
@for /f "tokens=2 delims==" %%a in ('find "sources=" "peyexe.ini"') do set PYTHONSOURCES=%%a |
|
@for /f "tokens=2 delims==" %%a in ('find "console=" "peyexe.ini"') do set PYTHONWINDOWMODE=%%a |
|
@for /f "tokens=2 delims==" %%a in ('find "progress=" "peyexe.ini"') do set PYTHONPROGRESS=%%a |
|
@for /f "tokens=2 delims==" %%a in ('find "pip_strategy=" "peyexe.ini"') do set PYTHONPIPSTRATEGY=%%a |
|
|
|
bitsadmin /transfer . /download /priority foreground https://www.7-zip.org/a/7zr.exe %temp%\\7zr.exe |
|
bitsadmin /transfer . /download /priority foreground https://sourceforge.net/projects/sevenzip/files/LZMA%%20SDK/lzma2201.7z/download %temp%\\lzmasdk.7z |
|
bitsadmin /transfer . /download /priority foreground https://sourceforge.net/projects/sevenzip/files/7-Zip/22.01/7z2201-extra.7z/download %temp%\\7z.7z |
|
bitsadmin /transfer . /download /priority foreground https://www.python.org/ftp/python/%PYTHONVERSION%/python-%PYTHONVERSION%-embed-win32.zip %temp%\\python-embed.zip |
|
bitsadmin /transfer . /download /priority foreground https://bootstrap.pypa.io/get-pip.py %temp%\\get-pip.py |
|
|
|
echo Extracting... |
|
|
|
%temp%\7zr.exe x -bso0 -bsp0 -y -o%temp%\7z %temp%\7z.7z |
|
%temp%\7z\7za.exe x -bso0 -bsp0 -y -o%temp%\lzma %temp%\lzmasdk.7z |
|
%temp%\7z\7za.exe x -bso0 -bsp0 -y -o%temp%\python-embed %temp%\python-embed.zip |
|
|
|
echo Setting up Python... |
|
|
|
rem # Find python(VERSION)._pth file. |
|
for /r "%temp%\python-embed" %%a in (*._pth) do set PYPATHFILE=%%~na |
|
|
|
rem # Modify ._pth file to enable site-packages. |
|
del %temp%\python-embed\%PYPATHFILE%._pth |
|
echo %PYPATHFILE%.zip >> %temp%\python-embed\%PYPATHFILE%._pth |
|
echo . >> %temp%\python-embed\%PYPATHFILE%._pth |
|
echo | set /p a="import site" >> %temp%\python-embed\%PYPATHFILE%._pth |
|
|
|
rem # Install pip. |
|
move /Y %temp%\get-pip.py %temp%\python-embed >nul |
|
%temp%\python-embed\python.exe %temp%\python-embed\get-pip.py --no-warn-script-location |
|
|
|
rem # If pip_strategy is 1, only download wheels and install them on startup, |
|
rem # otherwise, install packages right now and delete pip. |
|
if "%PYTHONPIPSTRATEGY%"=="1" ( |
|
%temp%\python-embed\python.exe -m pip download -r %cd%\requirements.txt --dest %temp%\python-embed\external |
|
copy /Y %cd%\requirements.txt %temp%\python-embed\requirements.txt >nul |
|
) else ( |
|
%temp%\python-embed\python.exe -m pip install -r %cd%\requirements.txt --no-warn-script-location |
|
%temp%\python-embed\python.exe -m pip uninstall pip -y |
|
) |
|
|
|
echo Packaging... |
|
|
|
rem # Copy sources in python-embed. |
|
mkdir %temp%\python-embed\app |
|
xcopy %cd%\%PYTHONSOURCES% %temp%\python-embed\app /e |
|
|
|
rem # Delete get-pip.py |
|
del %temp%\python-embed\get-pip.py |
|
|
|
set PYTHONEXECUTABLE=python.exe |
|
set EXTRACTPROGRESS=yes |
|
if "%PYTHONWINDOWMODE%"=="0" (set PYTHONEXECUTABLE=pythonw.exe) |
|
if "%PYTHONPROGRESS%"=="0" (set EXTRACTPROGRESS=no) |
|
|
|
rem # Create bootstrapper. |
|
( |
|
echo import subprocess |
|
if "%PYTHONPIPSTRATEGY%"=="1" echo subprocess.call^("cd external && ..\python.exe -m pip install -r ../requirements.txt --no-index --find-links . && cd ..", shell=True^) |
|
echo subprocess.call^(".\python.exe -E app/%PYTHONEXECUTE%", shell=True^) |
|
) > %temp%\python-embed\bootstrap.py |
|
|
|
rem # Pack the embedded Python. |
|
%temp%\7zr.exe a -bso0 -bsp0 -y -mx0 %temp%\peyexe-source.7z %temp%\python-embed\* |
|
|
|
rem # Create config file. |
|
( |
|
echo ;!@Install@!UTF-8! |
|
echo Progress="%EXTRACTPROGRESS%" |
|
echo RunProgram=".\%PYTHONEXECUTABLE% -E bootstrap.py" |
|
echo ;!@InstallEnd@! |
|
) > %temp%\peyexe-build.txt |
|
|
|
rem # Build 7z SFX. |
|
copy /Y /b %temp%\lzma\bin\7zSD.sfx + %temp%\peyexe-build.txt + %temp%\peyexe-source.7z peyexe.exe >nul |
|
|
|
echo Cleaning up... |
|
|
|
rmdir /s /q %temp%\python-embed |
|
del %temp%\python-embed.zip |
|
del %temp%\peyexe-build.txt |
|
del %temp%\peyexe-source.7z |
|
del %temp%\7zr.exe |
|
rmdir /s /q %temp%\7z |
|
rmdir /s /q %temp%\lzma |
|
|
|
echo Done! |