Reputation: 11
I created a small flask app which I display using PyQt5, and I want to freeze it into an executable. For the PyQt side of things I copied an example off of the internet and added my own small changes, with these imports:
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
When I freeze it in cx_freeze I get a monstrous folder about 300mb in size, which is far too large for my liking. It seems to me that cx_freeze is including the whole PyQt5 module. Is there any way that I could cut down on the size of the application after cx_freeze?
Thanks!
Upvotes: 1
Views: 1574
Reputation: 48260
I had the same problem when migrating from PyQt4 to PyQt5. It looks like cx_Freeze wants to embed the whole Qt library, not only PyQt, but that is usually not necessary. With simple programs, it is enough to get rid of the Qt directory inside the PyQt5 one (which is over 160mb alone). Sometimes, though, there are DLLs which are still necessary: in my program I use QtMultimedia's audio properties, and I found out that the libraries inside PyQt5/Qt/plugins/audio are required to allow audio playback. A good approach could be run the freezed executable and then run another script which checks the dependencies the process requires.
I use a script similar to this:
import os, psutil
#set the base path of the freezed executable; (might change,
#check the last part for different architectures and python versions
basePath = 'c:\\somepath\\build\\exe.win32-3.5\\'
#look for current processes and break when my program is found;
#be sure that the name is unique
for procId in psutil.pids():
proc = psutil.Process(procId)
if proc.name().lower() == 'mytestprogram.exe':
break
#search for its dependencies and build a list of those *inside*
#its path, ignoring system deps in C:\Windows, etc.
deps = [p.path.lower() for p in proc.memory_maps() if p.path.lower().startswith(basePath)]
#create a list of all files inside the build path
allFiles = []
for root, dirs, files in os.walk(basePath):
for fileName in files:
filePath = os.path.join(root, fileName).lower()
allFiles.append(filePath)
#create a list of existing files not required, ignoring .pyc and .pyd files
unusedSet = set(allFiles) ^ set(deps)
unusedFiles = []
for filePath in sorted(unusedSet):
if filePath.endswith('pyc') or filePath.endswith('pyd'):
continue
unusedFiles.append((filePath[len(basePath):], os.stat(filePath).st_size))
#print the list, sorted by size
for filePath, size in sorted(unusedFiles, key=lambda d: d[1]):
print(filePath, size)
Be careful that it is not safe to remove everything listed in the printed list, but it can give you a good hint about the biggest files not required. I usually leave everything as it is, and then ignore the unrequired files when creating a setup program, but since the output dir will be rebuilt again after a build
command, you can just try to remove those files and see what happens.
Upvotes: 1